aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.mailmap6
-rw-r--r--CREDITS4
-rw-r--r--Documentation/admin-guide/cgroup-v2.rst9
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt12
-rw-r--r--Documentation/admin-guide/mm/transhuge.rst2
-rw-r--r--Documentation/admin-guide/pm/cpufreq.rst20
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml24
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml19
-rw-r--r--Documentation/devicetree/bindings/firmware/arm,scmi.yaml2
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml21
-rw-r--r--Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml8
-rw-r--r--Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml22
-rw-r--r--Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml11
-rw-r--r--Documentation/devicetree/bindings/net/fsl,enetc.yaml28
-rw-r--r--Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml32
-rw-r--r--Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml20
-rw-r--r--Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml104
-rw-r--r--Documentation/devicetree/bindings/net/qcom,ethqos.yaml19
-rw-r--r--Documentation/devicetree/bindings/net/renesas,ether.yaml3
-rw-r--r--Documentation/devicetree/bindings/net/sff,sfp.yaml2
-rw-r--r--Documentation/devicetree/bindings/net/snps,dwmac.yaml5
-rw-r--r--Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml110
-rw-r--r--Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml9
-rw-r--r--Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml6
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml29
-rw-r--r--Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml2
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml5
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml18
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml4
-rw-r--r--Documentation/fault-injection/fault-injection.rst40
-rw-r--r--Documentation/filesystems/caching/cachefiles.rst2
-rw-r--r--Documentation/iio/ad7380.rst13
-rw-r--r--Documentation/netlink/specs/dpll.yaml41
-rw-r--r--Documentation/netlink/specs/mptcp_pm.yaml1
-rw-r--r--Documentation/netlink/specs/netdev.yaml7
-rw-r--r--Documentation/netlink/specs/rt_neigh.yaml442
-rw-r--r--Documentation/netlink/specs/rt_rule.yaml242
-rw-r--r--Documentation/netlink/specs/tc.yaml2
-rw-r--r--Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst91
-rw-r--r--Documentation/networking/device_drivers/wwan/t7xx.rst64
-rw-r--r--Documentation/networking/devlink/octeontx2.rst21
-rw-r--r--Documentation/networking/devmem.rst9
-rw-r--r--Documentation/networking/ethtool-netlink.rst3
-rw-r--r--Documentation/networking/j1939.rst2
-rw-r--r--Documentation/networking/napi.rst170
-rw-r--r--Documentation/networking/net_cachelines/net_device.rst2
-rw-r--r--Documentation/networking/net_dim.rst2
-rw-r--r--Documentation/networking/packet_mmap.rst5
-rw-r--r--Documentation/rust/arch-support.rst2
-rw-r--r--Documentation/security/landlock.rst14
-rw-r--r--Documentation/userspace-api/landlock.rst90
-rw-r--r--Documentation/userspace-api/mseal.rst307
-rw-r--r--MAINTAINERS146
-rw-r--r--Makefile2
-rw-r--r--arch/Kconfig4
-rw-r--r--arch/arm/boot/dts/rockchip/rk3036-kylin.dts4
-rw-r--r--arch/arm/boot/dts/rockchip/rk3036.dtsi14
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-lvds0.dtsi12
-rw-r--r--arch/arm64/boot/dts/freescale/imx8-ss-vpu.dtsi4
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts12
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts1
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp.dtsi6
-rw-r--r--arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi8
-rw-r--r--arch/arm64/boot/dts/freescale/imx8ulp.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8939.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/sm8450.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-crd.dts10
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100-qcp.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/x1e80100.dtsi53
-rw-r--r--arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3328.dtsi3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts6
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi6
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi2
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts3
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-base.dtsi20
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts4
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi1
-rw-r--r--arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts1
-rw-r--r--arch/arm64/include/asm/mman.h10
-rw-r--r--arch/arm64/include/asm/topology.h4
-rw-r--r--arch/arm64/kernel/fpsimd.c1
-rw-r--r--arch/arm64/kernel/signal.c92
-rw-r--r--arch/arm64/kernel/smccc-call.S35
-rw-r--r--arch/arm64/net/bpf_jit_comp.c12
-rw-r--r--arch/loongarch/include/asm/kasan.h13
-rw-r--r--arch/loongarch/include/asm/page.h5
-rw-r--r--arch/loongarch/kernel/acpi.c81
-rw-r--r--arch/loongarch/kernel/paravirt.c15
-rw-r--r--arch/loongarch/kernel/smp.c5
-rw-r--r--arch/loongarch/mm/kasan_init.c46
-rw-r--r--arch/mips/kernel/cmpxchg.c1
-rw-r--r--arch/parisc/include/asm/mman.h5
-rw-r--r--arch/parisc/lib/checksum.c13
-rw-r--r--arch/powerpc/kvm/book3s_hv.c12
-rw-r--r--arch/riscv/Kconfig2
-rw-r--r--arch/riscv/boot/dts/sophgo/sg2042.dtsi6
-rw-r--r--arch/riscv/boot/dts/starfive/jh7110-common.dtsi2
-rw-r--r--arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts3
-rw-r--r--arch/riscv/errata/Makefile6
-rw-r--r--arch/riscv/kernel/Makefile5
-rw-r--r--arch/riscv/kernel/acpi.c4
-rw-r--r--arch/riscv/kernel/asm-offsets.c2
-rw-r--r--arch/riscv/kernel/cacheinfo.c7
-rw-r--r--arch/riscv/kernel/cpu-hotplug.c2
-rw-r--r--arch/riscv/kernel/efi-header.S2
-rw-r--r--arch/riscv/kernel/pi/Makefile6
-rw-r--r--arch/riscv/kernel/traps_misaligned.c2
-rw-r--r--arch/riscv/kernel/vdso/Makefile1
-rw-r--r--arch/s390/include/asm/stp.h1
-rw-r--r--arch/s390/include/asm/timex.h6
-rw-r--r--arch/s390/kernel/time.c7
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/amd_nb.h5
-rw-r--r--arch/x86/include/asm/runtime-const.h4
-rw-r--r--arch/x86/include/asm/topology.h5
-rw-r--r--arch/x86/include/asm/uaccess_64.h43
-rw-r--r--arch/x86/kernel/acpi/cppc.c7
-rw-r--r--arch/x86/kernel/cpu/common.c10
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c51
-rw-r--r--arch/x86/kernel/traps.c12
-rw-r--r--arch/x86/kernel/vmlinux.lds.S1
-rw-r--r--arch/x86/kvm/lapic.c29
-rw-r--r--arch/x86/kvm/svm/sev.c15
-rw-r--r--arch/x86/kvm/vmx/nested.c30
-rw-r--r--arch/x86/kvm/vmx/vmx.c6
-rw-r--r--arch/x86/lib/getuser.S9
-rw-r--r--arch/x86/virt/svm/sev.c2
-rw-r--r--arch/xtensa/include/asm/page.h18
-rw-r--r--block/blk-map.c58
-rw-r--r--drivers/accel/ivpu/ivpu_debugfs.c9
-rw-r--r--drivers/accel/ivpu/ivpu_hw.c1
-rw-r--r--drivers/accel/ivpu/ivpu_hw.h1
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.c5
-rw-r--r--drivers/acpi/button.c11
-rw-r--r--drivers/acpi/cppc_acpi.c37
-rw-r--r--drivers/acpi/prmt.c29
-rw-r--r--drivers/acpi/processor_driver.c9
-rw-r--r--drivers/acpi/resource.c7
-rw-r--r--drivers/ata/libata-eh.c1
-rw-r--r--drivers/base/arch_topology.c6
-rw-r--r--drivers/base/core.c48
-rw-r--r--drivers/base/module.c4
-rw-r--r--drivers/bluetooth/btbcm.c4
-rw-r--r--drivers/bluetooth/btintel.c113
-rw-r--r--drivers/bluetooth/btintel.h10
-rw-r--r--drivers/bluetooth/btintel_pcie.c387
-rw-r--r--drivers/bluetooth/btintel_pcie.h18
-rw-r--r--drivers/bluetooth/btmtk.c3
-rw-r--r--drivers/bluetooth/btmtksdio.c21
-rw-r--r--drivers/bluetooth/btmtkuart.c2
-rw-r--r--drivers/bluetooth/btnxpuart.c81
-rw-r--r--drivers/bluetooth/btrtl.c2
-rw-r--r--drivers/bluetooth/btusb.c76
-rw-r--r--drivers/bluetooth/hci_bcm.c25
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/bluetooth/hci_ll.c2
-rw-r--r--drivers/bluetooth/hci_nokia.c2
-rw-r--r--drivers/bluetooth/hci_qca.c32
-rw-r--r--drivers/char/tpm/tpm-buf.c20
-rw-r--r--drivers/char/tpm/tpm-chip.c14
-rw-r--r--drivers/char/tpm/tpm-dev-common.c3
-rw-r--r--drivers/char/tpm/tpm-interface.c30
-rw-r--r--drivers/char/tpm/tpm2-cmd.c30
-rw-r--r--drivers/char/tpm/tpm2-sessions.c154
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c2
-rw-r--r--drivers/clk/qcom/gcc-x1e80100.c12
-rw-r--r--drivers/clk/qcom/videocc-sm8350.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c55
-rw-r--r--drivers/cxl/Kconfig1
-rw-r--r--drivers/cxl/Makefile20
-rw-r--r--drivers/cxl/acpi.c7
-rw-r--r--drivers/cxl/core/cdat.c3
-rw-r--r--drivers/cxl/core/hdm.c50
-rw-r--r--drivers/cxl/core/port.c13
-rw-r--r--drivers/cxl/core/region.c91
-rw-r--r--drivers/cxl/core/trace.h17
-rw-r--r--drivers/cxl/cxl.h3
-rw-r--r--drivers/cxl/port.c17
-rw-r--r--drivers/dma/sh/rz-dmac.c25
-rw-r--r--drivers/dma/ti/k3-udma.c62
-rw-r--r--drivers/dpll/dpll_netlink.c24
-rw-r--r--drivers/edac/qcom_edac.c8
-rw-r--r--drivers/firewire/core-topology.c2
-rw-r--r--drivers/firmware/arm_scmi/bus.c7
-rw-r--r--drivers/firmware/arm_scmi/common.h2
-rw-r--r--drivers/firmware/arm_scmi/driver.c10
-rw-r--r--drivers/firmware/arm_sdei.c2
-rw-r--r--drivers/firmware/microchip/mpfs-auto-update.c42
-rw-r--r--drivers/firmware/qcom/qcom_scm.c17
-rw-r--r--drivers/firmware/smccc/smccc.c4
-rw-r--r--drivers/gpio/gpio-sloppy-logic-analyzer.c4
-rw-r--r--drivers/gpio/gpiolib-swnode.c2
-rw-r--r--drivers/gpio/gpiolib.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c9
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c18
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml2/dml2_policy.c1
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c60
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0.h132
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c16
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c140
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h2
-rw-r--r--drivers/gpu/drm/bridge/aux-bridge.c3
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c1
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c1
-rw-r--r--drivers/gpu/drm/i915/Kconfig3
-rw-r--r--drivers/gpu/drm/imagination/pvr_context.c33
-rw-r--r--drivers/gpu/drm/imagination/pvr_context.h21
-rw-r--r--drivers/gpu/drm/imagination/pvr_device.h10
-rw-r--r--drivers/gpu/drm/imagination/pvr_drv.c3
-rw-r--r--drivers/gpu/drm/imagination/pvr_vm.c22
-rw-r--r--drivers/gpu/drm/imagination/pvr_vm.h1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_crtc.c4
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ddp_comp.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ddp_comp.h10
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_drv.h2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl.c74
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c7
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dp.c85
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ethdr.c7
-rw-r--r--drivers/gpu/drm/mediatek/mtk_ethdr.h1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_plane.c15
-rw-r--r--drivers/gpu/drm/mediatek/mtk_plane.h4
-rw-r--r--drivers/gpu/drm/panthor/panthor_device.c4
-rw-r--r--drivers/gpu/drm/panthor/panthor_fw.c4
-rw-r--r--drivers/gpu/drm/panthor/panthor_gem.c11
-rw-r--r--drivers/gpu/drm/panthor/panthor_mmu.c18
-rw-r--r--drivers/gpu/drm/panthor/panthor_mmu.h1
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c20
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c5
-rw-r--r--drivers/gpu/drm/tegra/drm.c4
-rw-r--r--drivers/gpu/drm/tests/drm_connector_test.c24
-rw-r--r--drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c8
-rw-r--r--drivers/gpu/drm/tests/drm_kunit_helpers.c42
-rw-r--r--drivers/gpu/drm/xe/display/xe_display.c65
-rw-r--r--drivers/gpu/drm/xe/display/xe_display.h8
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gt_regs.h2
-rw-r--r--drivers/gpu/drm/xe/xe_device.c12
-rw-r--r--drivers/gpu/drm/xe/xe_device.h14
-rw-r--r--drivers/gpu/drm/xe/xe_device_types.h9
-rw-r--r--drivers/gpu/drm/xe/xe_exec.c13
-rw-r--r--drivers/gpu/drm/xe/xe_exec_queue.c6
-rw-r--r--drivers/gpu/drm/xe/xe_force_wake.c12
-rw-r--r--drivers/gpu/drm/xe/xe_ggtt.c10
-rw-r--r--drivers/gpu/drm/xe/xe_gt_ccs_mode.c15
-rw-r--r--drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c4
-rw-r--r--drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c2
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ct.c9
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c34
-rw-r--r--drivers/gpu/drm/xe/xe_pm.c6
-rw-r--r--drivers/gpu/drm/xe/xe_sync.c3
-rw-r--r--drivers/gpu/drm/xe/xe_wait_user_fence.c7
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c6
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h1
-rw-r--r--drivers/i2c/muxes/i2c-mux-mule.c4
-rw-r--r--drivers/iio/adc/ad7124.c2
-rw-r--r--drivers/iio/adc/ad7380.c136
-rw-r--r--drivers/iio/dac/Kconfig2
-rw-r--r--drivers/iio/industrialio-gts-helper.c4
-rw-r--r--drivers/iio/light/veml6030.c2
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.c4
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.c38
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.h2
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c1
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c4
-rw-r--r--drivers/input/input.c134
-rw-r--r--drivers/input/keyboard/adp5588-keys.c6
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c19
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c14
-rw-r--r--drivers/irqchip/irq-gic-v3.c7
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c16
-rw-r--r--drivers/md/dm-bufio.c12
-rw-r--r--drivers/md/dm-cache-background-tracker.c25
-rw-r--r--drivers/md/dm-cache-background-tracker.h8
-rw-r--r--drivers/md/dm-cache-target.c84
-rw-r--r--drivers/md/dm-unstripe.c4
-rw-r--r--drivers/md/dm-verity-target.c9
-rw-r--r--drivers/md/dm-verity.h1
-rw-r--r--drivers/md/dm.c4
-rw-r--r--drivers/md/md.c24
-rw-r--r--drivers/md/raid10.c7
-rw-r--r--drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c6
-rw-r--r--drivers/media/cec/usb/pulse8/pulse8-cec.c2
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c3
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c28
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c4
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c8
-rw-r--r--drivers/media/dvb-core/dvbdev.c16
-rw-r--r--drivers/media/dvb-frontends/cx24116.c7
-rw-r--r--drivers/media/dvb-frontends/stb0899_algo.c2
-rw-r--r--drivers/media/i2c/adv7604.c26
-rw-r--r--drivers/media/i2c/ar0521.c4
-rw-r--r--drivers/media/pci/mgb4/mgb4_cmt.c2
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c17
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.h4
-rw-r--r--drivers/media/test-drivers/vivid/vivid-ctrls.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-api.c17
-rw-r--r--drivers/misc/mei/client.c4
-rw-r--r--drivers/mmc/host/sdhci-pci-gli.c38
-rw-r--r--drivers/net/amt.c12
-rw-r--r--drivers/net/bonding/bond_main.c25
-rw-r--r--drivers/net/bonding/bond_options.c82
-rw-r--r--drivers/net/can/c_can/c_can_main.c7
-rw-r--r--drivers/net/can/cc770/Kconfig2
-rw-r--r--drivers/net/can/m_can/m_can.c3
-rw-r--r--drivers/net/can/rockchip/Kconfig3
-rw-r--r--drivers/net/can/sja1000/Kconfig2
-rw-r--r--drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c8
-rw-r--r--drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c10
-rw-r--r--drivers/net/can/vxcan.c12
-rw-r--r--drivers/net/dsa/b53/b53_common.c3
-rw-r--r--drivers/net/dsa/bcm_sf2.c4
-rw-r--r--drivers/net/dsa/bcm_sf2.h4
-rw-r--r--drivers/net/dsa/bcm_sf2_cfp.c22
-rw-r--r--drivers/net/dsa/dsa_loop.c3
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek.c8
-rw-r--r--drivers/net/dsa/microchip/ksz9477.c4
-rw-r--r--drivers/net/dsa/microchip/ksz9477_i2c.c14
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c315
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h60
-rw-r--r--drivers/net/dsa/microchip/ksz_spi.c7
-rw-r--r--drivers/net/dsa/microchip/lan937x.h2
-rw-r--r--drivers/net/dsa/microchip/lan937x_main.c226
-rw-r--r--drivers/net/dsa/microchip/lan937x_reg.h4
-rw-r--r--drivers/net/dsa/mt7530.c49
-rw-r--r--drivers/net/dsa/mt7530.h12
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c57
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c14
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h8
-rw-r--r--drivers/net/dsa/qca/qca8k-8xxx.c2
-rw-r--r--drivers/net/dsa/rzn1_a5psw.c6
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ethtool.c7
-rw-r--r--drivers/net/dsa/xrs700x/xrs700x.c6
-rw-r--r--drivers/net/dummy.c17
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.c58
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_com.h32
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_ethtool.c14
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c22
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c6
-rw-r--r--drivers/net/ethernet/arc/emac_main.c27
-rw-r--r--drivers/net/ethernet/arc/emac_mdio.c9
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c6
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c12
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c22
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c68
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c127
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c165
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c132
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h43
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c8
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h1
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c31
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c23
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h62
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c10
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c386
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_res.c42
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c28
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth.c26
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_eth_trace.h2
-rw-r--r--drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c40
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c15
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c9
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h2
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c9
-rw-r--r--drivers/net/ethernet/freescale/enetc/Kconfig40
-rw-r--r--drivers/net/ethernet/freescale/enetc/Makefile9
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c271
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.h30
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc4_hw.h155
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc4_pf.c756
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c70
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_hw.h53
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c31
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c332
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.h21
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf_common.c336
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf_common.h19
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_qos.c2
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_vf.c17
-rw-r--r--drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c445
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c1
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.h3
-rw-r--r--drivers/net/ethernet/freescale/fman/mac.c5
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c8
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c34
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth_ethtool.c21
-rw-r--r--drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hnae.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c20
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c5
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h4
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c70
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c31
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c66
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c5
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ethtool.c67
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.c5
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hnae3.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c11
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c4
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c54
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c50
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c6
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c42
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c88
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c49
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c49
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c49
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c30
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c10
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c17
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c15
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/devlink_port.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h17
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ddp.c302
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ddp.h5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c70
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c110
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.h39
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fdir.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c41
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.c21
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl.c59
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h4
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ethtool.c11
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c4
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c3
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c6
-rw-r--r--drivers/net/ethernet/intel/igbvf/igbvf.h3
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_diag.c3
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c13
-rw-r--r--drivers/net/ethernet/intel/igc/igc_hw.h1
-rw-r--r--drivers/net/ethernet/intel/igc/igc_mac.c316
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c1
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c24
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h16
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h15
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c1
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c39
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c31
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c31
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/Kconfig8
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/Makefile3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/common.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h75
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h38
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c27
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c35
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c49
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c132
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c50
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c468
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h26
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c20
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/Makefile2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c4
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c58
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h90
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c49
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c78
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c5
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c303
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c25
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c31
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c19
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/rep.c864
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/rep.h54
-rw-r--r--drivers/net/ethernet/marvell/skge.c3
-rw-r--r--drivers/net/ethernet/marvell/sky2.c3
-rw-r--r--drivers/net/ethernet/mediatek/airoha_eth.c102
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c4
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_wo.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/Makefile63
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cq.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/dpll.c81
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c97
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c127
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eq.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c561
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c31
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.c15
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c32
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c)4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h)36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h)6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c)4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c)2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_rule.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h (renamed from drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h)0
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/wq.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c7
-rw-r--r--drivers/net/ethernet/meta/fbnic/Makefile3
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic.h4
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_csr.c148
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_csr.h36
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c17
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_netdev.c1
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_rpc.c110
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_rpc.h4
-rw-r--r--drivers/net/ethernet/microchip/Kconfig1
-rw-r--r--drivers/net/ethernet/microchip/Makefile1
-rw-r--r--drivers/net/ethernet/microchip/lan969x/Kconfig5
-rw-r--r--drivers/net/ethernet/microchip/lan969x/Makefile13
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x.c353
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x.h65
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c191
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x_regs.c222
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x_vcap_ag_api.c3843
-rw-r--r--drivers/net/ethernet/microchip/lan969x/lan969x_vcap_impl.c85
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c72
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c2
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.c77
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.h78
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h132
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c10
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c26
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_packet.c16
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_port.c46
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c15
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_qos.c3
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_regs.c5
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_regs.h5
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c10
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c5
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h2
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c48
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h21
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c55
-rw-r--r--drivers/net/ethernet/mscc/ocelot_flower.c54
-rw-r--r--drivers/net/ethernet/mscc/ocelot_net.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfd3/dp.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfdk/dp.c4
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c4
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c1
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_txrx.c2
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c14
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_ethtool.c38
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c60
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c4
-rw-r--r--drivers/net/ethernet/realtek/r8169.h1
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c219
-rw-r--r--drivers/net/ethernet/realtek/r8169_phy_config.c35
-rw-r--r--drivers/net/ethernet/realtek/rtase/rtase.h2
-rw-r--r--drivers/net/ethernet/realtek/rtase/rtase_main.c10
-rw-r--r--drivers/net/ethernet/sfc/ef10.c2
-rw-r--r--drivers/net/ethernet/sfc/ef100_ethtool.c1
-rw-r--r--drivers/net/ethernet/sfc/ef100_nic.c2
-rw-r--r--drivers/net/ethernet/sfc/efx.c8
-rw-r--r--drivers/net/ethernet/sfc/efx.h1
-rw-r--r--drivers/net/ethernet/sfc/efx_common.c16
-rw-r--r--drivers/net/ethernet/sfc/efx_common.h1
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c1
-rw-r--r--drivers/net/ethernet/sfc/ethtool_common.c46
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.c8
-rw-r--r--drivers/net/ethernet/sfc/falcon/efx.h1
-rw-r--r--drivers/net/ethernet/sfc/falcon/ethtool.c34
-rw-r--r--drivers/net/ethernet/sfc/falcon/falcon.c2
-rw-r--r--drivers/net/ethernet/sfc/falcon/farch.c22
-rw-r--r--drivers/net/ethernet/sfc/falcon/net_driver.h2
-rw-r--r--drivers/net/ethernet/sfc/falcon/nic.c20
-rw-r--r--drivers/net/ethernet/sfc/falcon/nic.h7
-rw-r--r--drivers/net/ethernet/sfc/falcon/tx.c8
-rw-r--r--drivers/net/ethernet/sfc/falcon/tx.h3
-rw-r--r--drivers/net/ethernet/sfc/mae.c11
-rw-r--r--drivers/net/ethernet/sfc/mae.h1
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c76
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h10
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h2
-rw-r--r--drivers/net/ethernet/sfc/nic.c9
-rw-r--r--drivers/net/ethernet/sfc/nic_common.h2
-rw-r--r--drivers/net/ethernet/sfc/ptp.c7
-rw-r--r--drivers/net/ethernet/sfc/ptp.h3
-rw-r--r--drivers/net/ethernet/sfc/siena/ethtool_common.c46
-rw-r--r--drivers/net/ethernet/sfc/siena/net_driver.h2
-rw-r--r--drivers/net/ethernet/sfc/siena/nic.c14
-rw-r--r--drivers/net/ethernet/sfc/siena/nic_common.h5
-rw-r--r--drivers/net/ethernet/sfc/siena/ptp.c2
-rw-r--r--drivers/net/ethernet/sfc/siena/ptp.h2
-rw-r--r--drivers/net/ethernet/sfc/siena/siena.c2
-rw-r--r--drivers/net/ethernet/sfc/tx.c8
-rw-r--r--drivers/net/ethernet/sfc/tx.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c25
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c273
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c101
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c150
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.h26
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c31
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.c22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c413
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h33
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c26
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c188
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c38
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c4
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c75
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h6
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.c58
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.h12
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_wireless.c1
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_wireless.h1
-rw-r--r--drivers/net/ethernet/vertexcom/mse102x.c9
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c4
-rw-r--r--drivers/net/fjes/fjes_ethtool.c64
-rw-r--r--drivers/net/gtp.c38
-rw-r--r--drivers/net/ifb.c17
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c3
-rw-r--r--drivers/net/macsec.c73
-rw-r--r--drivers/net/macvlan.c4
-rw-r--r--drivers/net/mctp/mctp-i2c.c6
-rw-r--r--drivers/net/mctp/mctp-i3c.c2
-rw-r--r--drivers/net/mctp/mctp-serial.c5
-rw-r--r--drivers/net/mdio.c172
-rw-r--r--drivers/net/netdevsim/fib.c4
-rw-r--r--drivers/net/netdevsim/netdev.c6
-rw-r--r--drivers/net/netkit.c11
-rw-r--r--drivers/net/phy/Kconfig17
-rw-r--r--drivers/net/phy/Makefile3
-rw-r--r--drivers/net/phy/adin.c6
-rw-r--r--drivers/net/phy/aquantia/aquantia_main.c52
-rw-r--r--drivers/net/phy/bcm-phy-lib.c5
-rw-r--r--drivers/net/phy/dp83822.c31
-rw-r--r--drivers/net/phy/dp83848.c2
-rw-r--r--drivers/net/phy/icplus.c3
-rw-r--r--drivers/net/phy/marvell.c12
-rw-r--r--drivers/net/phy/mediatek/Kconfig27
-rw-r--r--drivers/net/phy/mediatek/Makefile4
-rw-r--r--drivers/net/phy/mediatek/mtk-ge-soc.c (renamed from drivers/net/phy/mediatek-ge-soc.c)298
-rw-r--r--drivers/net/phy/mediatek/mtk-ge.c (renamed from drivers/net/phy/mediatek-ge.c)31
-rw-r--r--drivers/net/phy/mediatek/mtk-phy-lib.c270
-rw-r--r--drivers/net/phy/mediatek/mtk.h89
-rw-r--r--drivers/net/phy/micrel.c8
-rw-r--r--drivers/net/phy/microchip_t1.c1
-rw-r--r--drivers/net/phy/mscc/mscc_main.c3
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.c6
-rw-r--r--drivers/net/phy/nxp-cbtx.c2
-rw-r--r--drivers/net/phy/phy-c45.c30
-rw-r--r--drivers/net/phy/phy-core.c21
-rw-r--r--drivers/net/phy/phy_device.c23
-rw-r--r--drivers/net/phy/phylink.c222
-rw-r--r--drivers/net/phy/qcom/qca83xx.c6
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/usb/r8152.c1
-rw-r--r--drivers/net/veth.c18
-rw-r--r--drivers/net/virtio_net.c573
-rw-r--r--drivers/net/vrf.c2
-rw-r--r--drivers/net/vxlan/vxlan_core.c15
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c105
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c7
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c20
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c7
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c5
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.c3
-rw-r--r--drivers/net/wireless/ath/ath11k/wow.c39
-rw-r--r--drivers/net/wireless/ath/ath12k/Kconfig10
-rw-r--r--drivers/net/wireless/ath/ath12k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath12k/ce.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c9
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h110
-rw-r--r--drivers/net/wireless/ath/ath12k/coredump.c51
-rw-r--r--drivers/net/wireless/ath/ath12k/coredump.h80
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c1358
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h444
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.c58
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.h7
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_mon.c122
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c16
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_tx.c9
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_tx.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.c12
-rw-r--r--drivers/net/wireless/ath/ath12k/hal_rx.h53
-rw-r--r--drivers/net/wireless/ath/ath12k/hif.h6
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c1850
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h11
-rw-r--r--drivers/net/wireless/ath/ath12k/mhi.c5
-rw-r--r--drivers/net/wireless/ath/ath12k/mhi.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/p2p.c17
-rw-r--r--drivers/net/wireless/ath/ath12k/p2p.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c200
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.c13
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/rx_desc.h88
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c30
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h8
-rw-r--r--drivers/net/wireless/ath/ath12k/wow.c87
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_aic.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c52
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c8
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h2
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c1
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/Kconfig1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c29
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h9
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c55
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c22
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c9
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h2
-rw-r--r--drivers/net/wireless/intel/ipw2x00/Kconfig11
-rw-r--r--drivers/net/wireless/intel/ipw2x00/Makefile7
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c11
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.h2
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c25
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.h6
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw.h114
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_crypto.c246
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c (renamed from net/wireless/lib80211_crypt_ccmp.c)76
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c (renamed from net/wireless/lib80211_crypt_tkip.c)106
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c (renamed from net/wireless/lib80211_crypt_wep.c)73
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_module.c36
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_rx.c19
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_spy.c (renamed from net/wireless/wext-spy.c)63
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_tx.c4
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_wx.c43
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-mac.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.c15
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.h12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/bz.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/sc.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c96
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/binding.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/context.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/d3.h69
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/location.h30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h32
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dump.c27
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/init.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/coex.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c181
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c66
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c75
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c113
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/offloading.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c57
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tdls.c14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c4
-rw-r--r--drivers/net/wireless/intersil/p54/p54spi.c4
-rw-r--r--drivers/net/wireless/marvell/libertas/Kconfig1
-rw-r--r--drivers/net/wireless/marvell/libertas/cfg.c1
-rw-r--r--drivers/net/wireless/marvell/libertas/mesh.h1
-rw-r--r--drivers/net/wireless/marvell/libertas/radiotap.h4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cmdevt.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/fw.h2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/ioctl.h2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/join.c11
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.h4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_event.c6
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_ioctl.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/tdls.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/util.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mcu.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/soc.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/soc.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/soc.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c5
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.c113
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.h2
-rw-r--r--drivers/net/wireless/microchip/wilc1000/mon.c4
-rw-r--r--drivers/net/wireless/microchip/wilc1000/netdev.c37
-rw-r--r--drivers/net/wireless/microchip/wilc1000/sdio.c99
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c8
-rw-r--r--drivers/net/wireless/microchip/wilc1000/wlan.c444
-rw-r--r--drivers/net/wireless/microchip/wilc1000/wlan.h53
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.c2
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.h1
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/core.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c11
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c79
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h10
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/efuse.c11
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192du/sw.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c18
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/Kconfig33
-rw-r--r--drivers/net/wireless/realtek/rtw88/Makefile15
-rw-r--r--drivers/net/wireless/realtek/rtw88/coex.c37
-rw-r--r--drivers/net/wireless/realtek/rtw88/coex.h11
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c46
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.h17
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac.c15
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac.h3
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac80211.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c35
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h52
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c4
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.c82
-rw-r--r--drivers/net/wireless/realtek/rtw88/reg.h174
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8703b.c83
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723d.c70
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723x.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8812a.c1102
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8812a.h10
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8812a_table.c2812
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8812a_table.h26
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8812au.c28
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821a.c1197
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821a.h10
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821a_table.c2350
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821a_table.h21
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821au.c28
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.c87
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.h24
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822b.c73
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822b.h12
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c82
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw88xxa.c1989
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw88xxa.h175
-rw-r--r--drivers/net/wireless/realtek/rtw88/rx.c82
-rw-r--r--drivers/net/wireless/realtek/rtw88/rx.h64
-rw-r--r--drivers/net/wireless/realtek/rtw88/sdio.c11
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.h4
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.c15
-rw-r--r--drivers/net/wireless/realtek/rtw89/cam.c310
-rw-r--r--drivers/net/wireless/realtek/rtw89/cam.h48
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.c384
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.h23
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.c393
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.h6
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c1091
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h512
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c144
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.c150
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.h2
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse_be.c52
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c896
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h284
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c761
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h128
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c663
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac_be.c73
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.c153
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.h39
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci_be.c77
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c702
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.h13
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy_be.c12
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.c109
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.h14
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h2
-rw-r--r--drivers/net/wireless/realtek/rtw89/regd.c111
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851b.c18
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851be.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a.c13
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852ae.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b.c18
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b_common.c8
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852be.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bt.c18
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bte.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.c17
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c8
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852ce.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a.c121
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c61
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922ae.c8
-rw-r--r--drivers/net/wireless/realtek/rtw89/sar.c6
-rw-r--r--drivers/net/wireless/realtek/rtw89/ser.c37
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.c217
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.h10
-rw-r--r--drivers/net/wireless/silabs/wfx/main.c17
-rw-r--r--drivers/net/wireless/st/cw1200/cw1200_spi.c2
-rw-r--r--drivers/net/wireless/st/cw1200/queue.c27
-rw-r--r--drivers/net/wireless/st/cw1200/queue.h1
-rw-r--r--drivers/net/wireless/ti/wl1251/sdio.c4
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c2
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c5
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c13
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c16
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_modem_ops.c1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_pci.c58
-rw-r--r--drivers/net/wwan/t7xx/t7xx_pci.h1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port.h3
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_proxy.c51
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_proxy.h1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_wwan.c8
-rw-r--r--drivers/net/wwan/wwan_core.c10
-rw-r--r--drivers/nvme/host/core.c77
-rw-r--r--drivers/nvme/host/ioctl.c7
-rw-r--r--drivers/nvme/target/auth.c1
-rw-r--r--drivers/pci/pci.c14
-rw-r--r--drivers/pci/probe.c2
-rw-r--r--drivers/pci/pwrctl/pci-pwrctl-pwrseq.c55
-rw-r--r--drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c12
-rw-r--r--drivers/phy/broadcom/phy-brcm-usb-init.c2
-rw-r--r--drivers/phy/cadence/phy-cadence-sierra.c21
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8m-pcie.c10
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie.c8
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb.c1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usbc.c1
-rw-r--r--drivers/phy/rockchip/Kconfig1
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb.c16
-rw-r--r--drivers/phy/tegra/xusb.c2
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c4
-rw-r--r--drivers/platform/x86/amd/pmc/pmc.c5
-rw-r--r--drivers/platform/x86/amd/pmf/core.c1
-rw-r--r--drivers/platform/x86/amd/pmf/spc.c1
-rw-r--r--drivers/platform/x86/asus-wmi.c10
-rw-r--r--drivers/platform/x86/dell/dell-smbios-base.c1
-rw-r--r--drivers/platform/x86/dell/dell-wmi-base.c15
-rw-r--r--drivers/platform/x86/ideapad-laptop.c3
-rw-r--r--drivers/platform/x86/intel/pmc/adl.c2
-rw-r--r--drivers/platform/x86/intel/pmc/cnp.c2
-rw-r--r--drivers/platform/x86/intel/pmc/core.c46
-rw-r--r--drivers/platform/x86/intel/pmc/core.h8
-rw-r--r--drivers/platform/x86/intel/pmc/core_ssram.c4
-rw-r--r--drivers/platform/x86/intel/pmc/icl.c2
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c2
-rw-r--r--drivers/platform/x86/intel/pmc/tgl.c2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c28
-rw-r--r--drivers/powercap/dtpm_devfreq.c2
-rw-r--r--drivers/ptp/Kconfig17
-rw-r--r--drivers/ptp/Makefile1
-rw-r--r--drivers/ptp/ptp_fc3.c5
-rw-r--r--drivers/ptp/ptp_pch.c6
-rw-r--r--drivers/ptp/ptp_s390.c129
-rw-r--r--drivers/pwm/pwm-imx-tpm.c4
-rw-r--r--drivers/regulator/rk808-regulator.c2
-rw-r--r--drivers/regulator/rtq2208-regulator.c2
-rw-r--r--drivers/rpmsg/qcom_glink_native.c10
-rw-r--r--drivers/scsi/scsi_debug.c10
-rw-r--r--drivers/scsi/sd_zbc.c3
-rw-r--r--drivers/soc/fsl/dpio/dpio-service.c2
-rw-r--r--drivers/soc/qcom/llcc-qcom.c3
-rw-r--r--drivers/soc/qcom/pmic_glink.c25
-rw-r--r--drivers/soc/qcom/socinfo.c8
-rw-r--r--drivers/soundwire/intel_ace2x.c19
-rw-r--r--drivers/spi/spi-fsl-dspi.c6
-rw-r--r--drivers/spi/spi-geni-qcom.c8
-rw-r--r--drivers/spi/spi-mtk-snfi.c2
-rw-r--r--drivers/spi/spi-stm32.c1
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/iio/frequency/ad9832.c7
-rw-r--r--drivers/staging/media/av7110/av7110.h4
-rw-r--r--drivers/staging/media/av7110/av7110_ca.c25
-rw-r--r--drivers/staging/rtl8192e/Kconfig61
-rw-r--r--drivers/staging/rtl8192e/Makefile19
-rw-r--r--drivers/staging/rtl8192e/TODO18
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/Kconfig10
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/Makefile19
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_def.h266
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c198
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h17
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c79
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h12
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c1915
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h34
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c189
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h52
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h244
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c1110
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h55
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h773
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c123
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.h25
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c2016
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h402
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c1856
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.h155
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c84
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h12
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c37
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.c79
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h20
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.c89
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.h16
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.c230
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.h31
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c867
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.h13
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/table.c543
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/table.h27
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BA.h60
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c544
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HT.h223
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c699
-rw-r--r--drivers/staging/rtl8192e/rtl819x_Qos.h43
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TS.h50
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c450
-rw-r--r--drivers/staging/rtl8192e/rtllib.h1799
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_ccmp.c411
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_tkip.c706
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_wep.c242
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c179
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c2564
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c2309
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c534
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c901
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c752
-rw-r--r--drivers/staging/rtl8712/TODO1
-rw-r--r--drivers/staging/rtl8723bs/TODO1
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c6
-rw-r--r--drivers/staging/vt6655/TODO1
-rw-r--r--drivers/staging/vt6656/TODO1
-rw-r--r--drivers/thermal/qcom/lmh.c7
-rw-r--r--drivers/thermal/thermal_of.c21
-rw-r--r--drivers/thunderbolt/retimer.c7
-rw-r--r--drivers/thunderbolt/tb.c48
-rw-r--r--drivers/thunderbolt/usb4.c2
-rw-r--r--drivers/ufs/core/ufshcd.c12
-rw-r--r--drivers/usb/core/usb-acpi.c4
-rw-r--r--drivers/usb/dwc2/params.c1
-rw-r--r--drivers/usb/dwc3/core.c25
-rw-r--r--drivers/usb/host/xhci-pci.c6
-rw-r--r--drivers/usb/host/xhci-ring.c16
-rw-r--r--drivers/usb/musb/sunxi.c2
-rw-r--r--drivers/usb/phy/phy.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c8
-rw-r--r--drivers/usb/serial/option.c6
-rw-r--r--drivers/usb/serial/qcserial.c2
-rw-r--r--drivers/usb/typec/class.c6
-rw-r--r--drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c10
-rw-r--r--drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c8
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c10
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c2
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_base.c2
-rw-r--r--drivers/vdpa/mlx5/core/mr.c8
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.c21
-rw-r--r--drivers/vdpa/solidrun/snet_main.c14
-rw-r--r--drivers/vdpa/virtio_pci/vp_vdpa.c10
-rw-r--r--drivers/vhost/net.c2
-rw-r--r--drivers/video/fbdev/Kconfig15
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/bw2.c2
-rw-r--r--drivers/video/fbdev/cg14.c2
-rw-r--r--drivers/video/fbdev/cg3.c2
-rw-r--r--drivers/video/fbdev/cg6.c2
-rw-r--r--drivers/video/fbdev/da8xx-fb.c1665
-rw-r--r--drivers/video/fbdev/ffb.c2
-rw-r--r--drivers/video/fbdev/leo.c2
-rw-r--r--drivers/video/fbdev/nvidia/nv_hw.c8
-rw-r--r--drivers/video/fbdev/p9100.c2
-rw-r--r--drivers/video/fbdev/sbuslib.c2
-rw-r--r--drivers/video/fbdev/sbuslib.h2
-rw-r--r--drivers/video/fbdev/sstfb.c9
-rw-r--r--drivers/video/fbdev/tcx.c2
-rw-r--r--drivers/virtio/virtio_pci_common.c24
-rw-r--r--drivers/virtio/virtio_pci_common.h1
-rw-r--r--drivers/virtio/virtio_pci_modern.c12
-rw-r--r--drivers/virtio/virtio_ring.c356
-rw-r--r--fs/9p/v9fs.h34
-rw-r--r--fs/9p/v9fs_vfs.h2
-rw-r--r--fs/9p/vfs_inode.c129
-rw-r--r--fs/9p/vfs_inode_dotl.c112
-rw-r--r--fs/9p/vfs_super.c2
-rw-r--r--fs/afs/dir.c25
-rw-r--r--fs/afs/dir_edit.c91
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/autofs/dev-ioctl.c5
-rw-r--r--fs/backing-file.c8
-rw-r--r--fs/bcachefs/alloc_background.h3
-rw-r--r--fs/bcachefs/alloc_foreground.c19
-rw-r--r--fs/bcachefs/backpointers.c17
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/bkey.c7
-rw-r--r--fs/bcachefs/btree_cache.c107
-rw-r--r--fs/bcachefs/btree_cache.h2
-rw-r--r--fs/bcachefs/btree_gc.c2
-rw-r--r--fs/bcachefs/btree_io.c6
-rw-r--r--fs/bcachefs/btree_iter.c13
-rw-r--r--fs/bcachefs/btree_node_scan.c2
-rw-r--r--fs/bcachefs/btree_update_interior.c33
-rw-r--r--fs/bcachefs/btree_write_buffer.c30
-rw-r--r--fs/bcachefs/btree_write_buffer.h1
-rw-r--r--fs/bcachefs/buckets.h19
-rw-r--r--fs/bcachefs/data_update.c21
-rw-r--r--fs/bcachefs/data_update.h3
-rw-r--r--fs/bcachefs/ec.c4
-rw-r--r--fs/bcachefs/errcode.h3
-rw-r--r--fs/bcachefs/extents.c91
-rw-r--r--fs/bcachefs/extents.h5
-rw-r--r--fs/bcachefs/fs-io.c17
-rw-r--r--fs/bcachefs/io_read.c10
-rw-r--r--fs/bcachefs/io_write.c7
-rw-r--r--fs/bcachefs/journal_io.c5
-rw-r--r--fs/bcachefs/move.c2
-rw-r--r--fs/bcachefs/opts.c4
-rw-r--r--fs/bcachefs/recovery.c21
-rw-r--r--fs/bcachefs/recovery_passes.c12
-rw-r--r--fs/bcachefs/recovery_passes_types.h1
-rw-r--r--fs/bcachefs/sb-downgrade.c3
-rw-r--r--fs/bcachefs/sb-errors_format.h6
-rw-r--r--fs/bcachefs/sb-members.c4
-rw-r--r--fs/bcachefs/sb-members_format.h6
-rw-r--r--fs/bcachefs/super-io.c5
-rw-r--r--fs/bcachefs/super.c1
-rw-r--r--fs/bcachefs/tests.c5
-rw-r--r--fs/btrfs/bio.c37
-rw-r--r--fs/btrfs/bio.h3
-rw-r--r--fs/btrfs/defrag.c10
-rw-r--r--fs/btrfs/delayed-ref.c2
-rw-r--r--fs/btrfs/extent_map.c7
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/super.c25
-rw-r--r--fs/btrfs/volumes.c1
-rw-r--r--fs/dax.c45
-rw-r--r--fs/debugfs/file.c100
-rw-r--r--fs/debugfs/inode.c63
-rw-r--r--fs/debugfs/internal.h6
-rw-r--r--fs/erofs/super.c4
-rw-r--r--fs/eventpoll.c36
-rw-r--r--fs/fuse/file.c18
-rw-r--r--fs/fuse/passthrough.c9
-rw-r--r--fs/iomap/buffered-io.c17
-rw-r--r--fs/nfs/client.c3
-rw-r--r--fs/nfs/inode.c70
-rw-r--r--fs/nfs/localio.c3
-rw-r--r--fs/nfs/nfs4proc.c4
-rw-r--r--fs/nfs/super.c10
-rw-r--r--fs/nfs_common/nfslocalio.c23
-rw-r--r--fs/nfsd/nfs4proc.c8
-rw-r--r--fs/nfsd/nfs4state.c50
-rw-r--r--fs/nfsd/state.h2
-rw-r--r--fs/nfsd/vfs.c13
-rw-r--r--fs/nilfs2/btnode.c2
-rw-r--r--fs/nilfs2/gcinode.c4
-rw-r--r--fs/nilfs2/mdt.c1
-rw-r--r--fs/nilfs2/namei.c3
-rw-r--r--fs/nilfs2/page.c3
-rw-r--r--fs/ocfs2/file.c8
-rw-r--r--fs/ocfs2/super.c13
-rw-r--r--fs/ocfs2/xattr.c3
-rw-r--r--fs/overlayfs/file.c9
-rw-r--r--fs/proc/softirqs.c2
-rw-r--r--fs/proc/vmcore.c9
-rw-r--r--fs/smb/client/cifsfs.c2
-rw-r--r--fs/smb/client/connect.c14
-rw-r--r--fs/smb/client/fs_context.c7
-rw-r--r--fs/smb/server/connection.c1
-rw-r--r--fs/smb/server/connection.h1
-rw-r--r--fs/smb/server/mgmt/user_session.c15
-rw-r--r--fs/smb/server/server.c20
-rw-r--r--fs/smb/server/smb_common.c10
-rw-r--r--fs/smb/server/smb_common.h2
-rw-r--r--fs/squashfs/file_direct.c9
-rw-r--r--fs/super.c26
-rw-r--r--fs/tracefs/inode.c12
-rw-r--r--fs/userfaultfd.c28
-rw-r--r--fs/xfs/libxfs/xfs_ag.c75
-rw-r--r--fs/xfs/libxfs/xfs_ag.h11
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c2
-rw-r--r--fs/xfs/scrub/repair.c8
-rw-r--r--fs/xfs/xfs_buf_item_recover.c70
-rw-r--r--fs/xfs/xfs_filestream.c99
-rw-r--r--fs/xfs/xfs_fsops.c20
-rw-r--r--fs/xfs/xfs_inode.c2
-rw-r--r--fs/xfs/xfs_inode.h5
-rw-r--r--fs/xfs/xfs_ioctl.c4
-rw-r--r--fs/xfs/xfs_iomap.c2
-rw-r--r--fs/xfs/xfs_log_recover.c7
-rw-r--r--fs/xfs/xfs_mount.c9
-rw-r--r--fs/xfs/xfs_trace.h15
-rw-r--r--include/acpi/cppc_acpi.h2
-rw-r--r--include/acpi/processor.h2
-rw-r--r--include/drm/drm_kunit_helpers.h4
-rw-r--r--include/linux/alloc_tag.h16
-rw-r--r--include/linux/arch_topology.h4
-rw-r--r--include/linux/arm-smccc.h32
-rw-r--r--include/linux/ath9k_platform.h51
-rw-r--r--include/linux/backing-file.h2
-rw-r--r--include/linux/bpf.h14
-rw-r--r--include/linux/bpf_mem_alloc.h3
-rw-r--r--include/linux/bpf_types.h1
-rw-r--r--include/linux/clocksource_ids.h1
-rw-r--r--include/linux/compiler-gcc.h4
-rw-r--r--include/linux/compiler_types.h6
-rw-r--r--include/linux/debugfs.h62
-rw-r--r--include/linux/device.h3
-rw-r--r--include/linux/dim.h5
-rw-r--r--include/linux/dpll.h4
-rw-r--r--include/linux/dynamic_queue_limits.h2
-rw-r--r--include/linux/ethtool.h6
-rw-r--r--include/linux/fs_context.h6
-rw-r--r--include/linux/fsl/netc_global.h19
-rw-r--r--include/linux/gfp.h22
-rw-r--r--include/linux/ieee80211.h2
-rw-r--r--include/linux/inetdevice.h9
-rw-r--r--include/linux/input.h10
-rw-r--r--include/linux/iomap.h19
-rw-r--r--include/linux/ksm.h10
-rw-r--r--include/linux/mdio.h19
-rw-r--r--include/linux/memcontrol.h12
-rw-r--r--include/linux/mm_types.h18
-rw-r--r--include/linux/mm_types_task.h21
-rw-r--r--include/linux/mman.h28
-rw-r--r--include/linux/mmzone.h8
-rw-r--r--include/linux/netdevice.h25
-rw-r--r--include/linux/netpoll.h1
-rw-r--r--include/linux/nfslocalio.h3
-rw-r--r--include/linux/page-flags.h8
-rw-r--r--include/linux/page_frag_cache.h61
-rw-r--r--include/linux/phy.h21
-rw-r--r--include/linux/platform_data/microchip-ksz.h1
-rw-r--r--include/linux/rtnetlink.h25
-rw-r--r--include/linux/skbuff.h57
-rw-r--r--include/linux/soc/qcom/llcc-qcom.h2
-rw-r--r--include/linux/sockptr.h4
-rw-r--r--include/linux/swap.h1
-rw-r--r--include/linux/tcp.h3
-rw-r--r--include/linux/tick.h8
-rw-r--r--include/linux/tpm.h3
-rw-r--r--include/linux/uaccess.h21
-rw-r--r--include/linux/user_namespace.h3
-rw-r--r--include/linux/userfaultfd_k.h5
-rw-r--r--include/linux/virtio.h13
-rw-r--r--include/linux/vm_event_item.h2
-rw-r--r--include/linux/wireless.h5
-rw-r--r--include/linux/wwan.h4
-rw-r--r--include/net/bluetooth/hci.h19
-rw-r--r--include/net/bluetooth/hci_core.h85
-rw-r--r--include/net/bluetooth/mgmt.h10
-rw-r--r--include/net/bond_options.h2
-rw-r--r--include/net/busy_poll.h3
-rw-r--r--include/net/cfg80211.h67
-rw-r--r--include/net/checksum.h6
-rw-r--r--include/net/devlink.h13
-rw-r--r--include/net/dropreason-core.h26
-rw-r--r--include/net/eee.h5
-rw-r--r--include/net/flow_offload.h1
-rw-r--r--include/net/ieee80211_radiotap.h43
-rw-r--r--include/net/ip_fib.h12
-rw-r--r--include/net/ip_tunnels.h2
-rw-r--r--include/net/iw_handler.h41
-rw-r--r--include/net/lib80211.h122
-rw-r--r--include/net/mac80211.h80
-rw-r--r--include/net/mctp.h18
-rw-r--r--include/net/mctpdevice.h4
-rw-r--r--include/net/neighbour.h26
-rw-r--r--include/net/neighbour_tables.h12
-rw-r--r--include/net/net_debug.h4
-rw-r--r--include/net/netfilter/nf_tables.h32
-rw-r--r--include/net/netlabel.h1
-rw-r--r--include/net/netlink.h263
-rw-r--r--include/net/nfc/nci.h2
-rw-r--r--include/net/nfc/nci_core.h4
-rw-r--r--include/net/nfc/nfc.h4
-rw-r--r--include/net/pkt_cls.h1
-rw-r--r--include/net/route.h40
-rw-r--r--include/net/rtnetlink.h9
-rw-r--r--include/net/tcp.h26
-rw-r--r--include/net/tcp_ao.h3
-rw-r--r--include/net/tls.h12
-rw-r--r--include/soc/fsl/qman.h2
-rw-r--r--include/trace/events/afs.h7
-rw-r--r--include/trace/events/rxrpc.h26
-rw-r--r--include/uapi/linux/bpf.h3
-rw-r--r--include/uapi/linux/dpll.h24
-rw-r--r--include/uapi/linux/ethtool.h33
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--include/uapi/linux/netdev.h1
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h18
-rw-r--r--include/uapi/linux/nfc.h3
-rw-r--r--include/uapi/linux/nl80211.h10
-rw-r--r--include/uapi/linux/rtnetlink.h2
-rw-r--r--include/uapi/sound/asoc.h2
-rw-r--r--include/video/da8xx-fb.h94
-rw-r--r--io_uring/rw.c23
-rw-r--r--kernel/bpf/cgroup.c19
-rw-r--r--kernel/bpf/helpers.c64
-rw-r--r--kernel/bpf/inode.c5
-rw-r--r--kernel/bpf/lpm_trie.c2
-rw-r--r--kernel/bpf/memalloc.c14
-rw-r--r--kernel/bpf/ringbuf.c2
-rw-r--r--kernel/bpf/syscall.c16
-rw-r--r--kernel/bpf/verifier.c98
-rw-r--r--kernel/cgroup/cgroup.c4
-rw-r--r--kernel/events/core.c2
-rw-r--r--kernel/fork.c14
-rw-r--r--kernel/irq/msi.c2
-rw-r--r--kernel/resource.c4
-rw-r--r--kernel/sched/core.c21
-rw-r--r--kernel/sched/ext.c93
-rw-r--r--kernel/sched/ext.h2
-rw-r--r--kernel/sched/fair.c25
-rw-r--r--kernel/sched/sched.h41
-rw-r--r--kernel/sched/syscalls.c2
-rw-r--r--kernel/signal.c3
-rw-r--r--kernel/trace/bpf_trace.c6
-rw-r--r--kernel/trace/fgraph.c12
-rw-r--r--kernel/trace/trace.c4
-rw-r--r--kernel/ucount.c9
-rw-r--r--lib/Kconfig.debug10
-rw-r--r--lib/Kconfig.kasan7
-rw-r--r--lib/checksum.c11
-rw-r--r--lib/dim/dim.c3
-rw-r--r--lib/dim/net_dim.c10
-rw-r--r--lib/dynamic_queue_limits.c2
-rw-r--r--lib/iov_iter.c25
-rw-r--r--lib/objpool.c18
-rw-r--r--lib/slub_kunit.c2
-rw-r--r--mm/Kconfig1
-rw-r--r--mm/Makefile1
-rw-r--r--mm/damon/core.c42
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/gup.c143
-rw-r--r--mm/huge_memory.c60
-rw-r--r--mm/internal.h55
-rw-r--r--mm/kasan/kasan_test_c.c27
-rw-r--r--mm/memcontrol-v1.c25
-rw-r--r--mm/memcontrol.c13
-rw-r--r--mm/memory.c15
-rw-r--r--mm/migrate.c9
-rw-r--r--mm/mlock.c9
-rw-r--r--mm/mmap.c215
-rw-r--r--mm/mprotect.c2
-rw-r--r--mm/nommu.c11
-rw-r--r--mm/numa_memblks.c2
-rw-r--r--mm/page_alloc.c177
-rw-r--r--mm/page_frag_cache.c171
-rw-r--r--mm/page_io.c20
-rw-r--r--mm/pagewalk.c16
-rw-r--r--mm/rmap.c9
-rw-r--r--mm/shmem.c5
-rw-r--r--mm/shrinker.c8
-rw-r--r--mm/slab_common.c33
-rw-r--r--mm/swap.c18
-rw-r--r--mm/swapfile.c49
-rw-r--r--mm/vma.c37
-rw-r--r--mm/vma.h32
-rw-r--r--mm/vmscan.c106
-rw-r--r--mm/vmstat.c2
-rw-r--r--mm/zswap.c6
-rw-r--r--net/8021q/vlan_netlink.c6
-rw-r--r--net/bluetooth/hci_conn.c230
-rw-r--r--net/bluetooth/hci_core.c28
-rw-r--r--net/bluetooth/hci_event.c47
-rw-r--r--net/bluetooth/hci_sync.c27
-rw-r--r--net/bluetooth/hci_sysfs.c15
-rw-r--r--net/bluetooth/iso.c121
-rw-r--r--net/bluetooth/mgmt.c60
-rw-r--r--net/bluetooth/rfcomm/sock.c10
-rw-r--r--net/bluetooth/sco.c99
-rw-r--r--net/bpf/test_run.c1
-rw-r--r--net/bridge/br_fdb.c36
-rw-r--r--net/bridge/br_netfilter_hooks.c13
-rw-r--r--net/bridge/br_private.h4
-rw-r--r--net/bridge/netfilter/Kconfig8
-rw-r--r--net/bridge/netfilter/nft_meta_bridge.c2
-rw-r--r--net/core/Makefile1
-rw-r--r--net/core/dev.c43
-rw-r--r--net/core/dev.h25
-rw-r--r--net/core/dev_ioctl.c6
-rw-r--r--net/core/fib_rules.c3
-rw-r--r--net/core/filter.c173
-rw-r--r--net/core/lwt_bpf.c8
-rw-r--r--net/core/neighbour.c325
-rw-r--r--net/core/net_namespace.c1
-rw-r--r--net/core/netdev-genl-gen.c5
-rw-r--r--net/core/netdev-genl.c14
-rw-r--r--net/core/netpoll.c45
-rw-r--r--net/core/page_pool.c2
-rw-r--r--net/core/rtnetlink.c305
-rw-r--r--net/core/skb_fault_injection.c106
-rw-r--r--net/core/skbuff.c6
-rw-r--r--net/core/sock.c42
-rw-r--r--net/core/sock_map.c4
-rw-r--r--net/dccp/ipv6.c2
-rw-r--r--net/devlink/dev.c18
-rw-r--r--net/devlink/devl_internal.h5
-rw-r--r--net/devlink/dpipe.c18
-rw-r--r--net/devlink/health.c25
-rw-r--r--net/devlink/rate.c8
-rw-r--r--net/devlink/region.c15
-rw-r--r--net/devlink/resource.c101
-rw-r--r--net/devlink/trap.c34
-rw-r--r--net/dsa/devlink.c23
-rw-r--r--net/dsa/user.c91
-rw-r--r--net/ethtool/common.c42
-rw-r--r--net/ethtool/ioctl.c7
-rw-r--r--net/ethtool/linkinfo.c8
-rw-r--r--net/ethtool/linkmodes.c18
-rw-r--r--net/hsr/hsr_device.c85
-rw-r--r--net/hsr/hsr_forward.c19
-rw-r--r--net/hsr/hsr_netlink.c5
-rw-r--r--net/ieee802154/nl-mac.c15
-rw-r--r--net/ieee802154/nl802154.c26
-rw-r--r--net/ipv4/arp.c2
-rw-r--r--net/ipv4/devinet.c193
-rw-r--r--net/ipv4/fib_frontend.c19
-rw-r--r--net/ipv4/icmp.c4
-rw-r--r--net/ipv4/ip_fragment.c11
-rw-r--r--net/ipv4/ip_input.c20
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/ip_tunnel.c2
-rw-r--r--net/ipv4/ipmr.c8
-rw-r--r--net/ipv4/ipmr_base.c3
-rw-r--r--net/ipv4/netfilter.c2
-rw-r--r--net/ipv4/netfilter/Kconfig16
-rw-r--r--net/ipv4/netfilter/ipt_rpfilter.c2
-rw-r--r--net/ipv4/netfilter/nf_dup_ipv4.c2
-rw-r--r--net/ipv4/netfilter/nft_fib_ipv4.c3
-rw-r--r--net/ipv4/nexthop.c13
-rw-r--r--net/ipv4/route.c236
-rw-r--r--net/ipv4/tcp.c2
-rw-r--r--net/ipv4/tcp_ao.c42
-rw-r--r--net/ipv4/tcp_bpf.c7
-rw-r--r--net/ipv4/tcp_cong.c3
-rw-r--r--net/ipv4/tcp_input.c4
-rw-r--r--net/ipv4/tcp_ipv4.c3
-rw-r--r--net/ipv4/tcp_output.c4
-rw-r--r--net/ipv6/addrconf.c7
-rw-r--r--net/ipv6/ila/ila_xlat.c15
-rw-r--r--net/ipv6/ioam6.c14
-rw-r--r--net/ipv6/ioam6_iptunnel.c6
-rw-r--r--net/ipv6/ip6_fib.c8
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/netfilter/Kconfig9
-rw-r--r--net/ipv6/netfilter/nf_reject_ipv6.c15
-rw-r--r--net/ipv6/route.c51
-rw-r--r--net/ipv6/seg6_local.c14
-rw-r--r--net/ipv6/tcp_ipv6.c8
-rw-r--r--net/mac80211/Kconfig2
-rw-r--r--net/mac80211/agg-rx.c94
-rw-r--r--net/mac80211/agg-tx.c33
-rw-r--r--net/mac80211/cfg.c211
-rw-r--r--net/mac80211/chan.c65
-rw-r--r--net/mac80211/debugfs.c28
-rw-r--r--net/mac80211/debugfs_key.c9
-rw-r--r--net/mac80211/debugfs_netdev.c3
-rw-r--r--net/mac80211/debugfs_sta.c9
-rw-r--r--net/mac80211/driver-ops.c16
-rw-r--r--net/mac80211/driver-ops.h18
-rw-r--r--net/mac80211/eht.c21
-rw-r--r--net/mac80211/ht.c2
-rw-r--r--net/mac80211/ibss.c7
-rw-r--r--net/mac80211/ieee80211_i.h35
-rw-r--r--net/mac80211/iface.c52
-rw-r--r--net/mac80211/key.c42
-rw-r--r--net/mac80211/link.c61
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mesh.c2
-rw-r--r--net/mac80211/mesh_hwmp.c6
-rw-r--r--net/mac80211/mesh_pathtbl.c10
-rw-r--r--net/mac80211/mesh_plink.c7
-rw-r--r--net/mac80211/mesh_sync.c2
-rw-r--r--net/mac80211/mlme.c118
-rw-r--r--net/mac80211/ocb.c4
-rw-r--r--net/mac80211/rate.c35
-rw-r--r--net/mac80211/rate.h10
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c2
-rw-r--r--net/mac80211/rx.c75
-rw-r--r--net/mac80211/scan.c22
-rw-r--r--net/mac80211/spectmgmt.c9
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/mac80211/status.c5
-rw-r--r--net/mac80211/tdls.c3
-rw-r--r--net/mac80211/tkip.c2
-rw-r--r--net/mac80211/trace.h34
-rw-r--r--net/mac80211/tx.c8
-rw-r--r--net/mac80211/util.c20
-rw-r--r--net/mac80211/vht.c29
-rw-r--r--net/mac80211/wpa.c3
-rw-r--r--net/mctp/device.c12
-rw-r--r--net/mptcp/mptcp_pm_gen.c1
-rw-r--r--net/mptcp/pm_netlink.c3
-rw-r--r--net/mptcp/pm_userspace.c18
-rw-r--r--net/mptcp/protocol.c22
-rw-r--r--net/mptcp/sched.c2
-rw-r--r--net/mptcp/subflow.c1
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c5
-rw-r--r--net/netfilter/nf_bpf_link.c2
-rw-r--r--net/netfilter/nf_nat_core.c6
-rw-r--r--net/netfilter/nf_tables_api.c558
-rw-r--r--net/netfilter/nfnetlink.c2
-rw-r--r--net/netfilter/nft_bitwise.c166
-rw-r--r--net/netfilter/nft_flow_offload.c8
-rw-r--r--net/netfilter/nft_payload.c3
-rw-r--r--net/netfilter/nft_set_bitmap.c10
-rw-r--r--net/netfilter/nft_set_hash.c3
-rw-r--r--net/netfilter/nft_tunnel.c5
-rw-r--r--net/netfilter/x_tables.c2
-rw-r--r--net/netlabel/netlabel_mgmt.c13
-rw-r--r--net/netlink/af_netlink.c41
-rw-r--r--net/netlink/af_netlink.h2
-rw-r--r--net/nfc/nci/core.c13
-rw-r--r--net/nfc/nci/ntf.c32
-rw-r--r--net/nfc/netlink.c5
-rw-r--r--net/openvswitch/datapath.c10
-rw-r--r--net/openvswitch/flow_netlink.c2
-rw-r--r--net/openvswitch/vport-internal_dev.c1
-rw-r--r--net/phonet/pn_dev.c5
-rw-r--r--net/phonet/pn_netlink.c12
-rw-r--r--net/rfkill/rfkill-gpio.c8
-rw-r--r--net/rxrpc/conn_client.c4
-rw-r--r--net/rxrpc/conn_object.c4
-rw-r--r--net/rxrpc/local_object.c4
-rw-r--r--net/rxrpc/sendmsg.c1
-rw-r--r--net/sched/act_ct.c10
-rw-r--r--net/sched/act_ctinfo.c8
-rw-r--r--net/sched/act_gate.c11
-rw-r--r--net/sched/act_mpls.c18
-rw-r--r--net/sched/act_police.c6
-rw-r--r--net/sched/cls_api.c48
-rw-r--r--net/sched/cls_u32.c18
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sched/sch_choke.c2
-rw-r--r--net/sched/sch_gred.c2
-rw-r--r--net/sched/sch_htb.c4
-rw-r--r--net/sched/sch_qfq.c5
-rw-r--r--net/sched/sch_red.c2
-rw-r--r--net/sched/sch_taprio.c2
-rw-r--r--net/sctp/ipv6.c21
-rw-r--r--net/sctp/protocol.c16
-rw-r--r--net/sctp/sm_statefuns.c2
-rw-r--r--net/smc/af_smc.c4
-rw-r--r--net/smc/smc_ib.c8
-rw-r--r--net/smc/smc_pnet.c4
-rw-r--r--net/socket.c4
-rw-r--r--net/sunrpc/svcsock.c6
-rw-r--r--net/sunrpc/xprtrdma/ib_client.c1
-rw-r--r--net/sunrpc/xprtsock.c1
-rw-r--r--net/vmw_vsock/af_vsock.c3
-rw-r--r--net/vmw_vsock/hyperv_transport.c1
-rw-r--r--net/vmw_vsock/virtio_transport_common.c10
-rw-r--r--net/wireless/Kconfig45
-rw-r--r--net/wireless/Makefile5
-rw-r--r--net/wireless/chan.c5
-rw-r--r--net/wireless/core.c74
-rw-r--r--net/wireless/core.h1
-rw-r--r--net/wireless/lib80211.c257
-rw-r--r--net/wireless/mlme.c6
-rw-r--r--net/wireless/nl80211.c161
-rw-r--r--net/wireless/radiotap.c2
-rw-r--r--net/wireless/rdev-ops.h5
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/scan.c16
-rw-r--r--net/wireless/trace.h10
-rw-r--r--net/wireless/util.c31
-rw-r--r--net/wireless/wext-compat.c13
-rw-r--r--net/wireless/wext-compat.h6
-rw-r--r--net/wireless/wext-core.c2
-rw-r--r--net/xfrm/xfrm_user.c8
-rw-r--r--samples/landlock/sandboxer.c112
-rwxr-xr-xsamples/pktgen/pktgen_sample01_simple.sh2
-rw-r--r--scripts/Makefile.package7
-rw-r--r--scripts/kconfig/menu.c13
-rw-r--r--scripts/mod/file2alias.c12
-rw-r--r--scripts/mod/sumversion.c5
-rwxr-xr-xscripts/package/builddeb2
-rwxr-xr-xscripts/package/install-extmod-build6
-rwxr-xr-xscripts/package/mkdebian10
-rwxr-xr-xscripts/rustc-llvm-version.sh2
-rw-r--r--security/integrity/evm/evm_main.c3
-rw-r--r--security/integrity/ima/ima_template_lib.c14
-rw-r--r--security/integrity/integrity.h4
-rw-r--r--security/keys/keyring.c7
-rw-r--r--security/keys/trusted-keys/trusted_dcp.c9
-rw-r--r--security/landlock/fs.c31
-rw-r--r--security/landlock/net.c28
-rw-r--r--security/landlock/ruleset.h74
-rw-r--r--security/landlock/syscalls.c2
-rw-r--r--security/landlock/task.c18
-rw-r--r--sound/core/ump.c2
-rw-r--r--sound/firewire/amdtp-stream.c3
-rw-r--r--sound/firewire/tascam/amdtp-tascam.c2
-rw-r--r--sound/hda/intel-dsp-config.c4
-rw-r--r--sound/pci/hda/Kconfig2
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_realtek.c83
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c28
-rw-r--r--sound/soc/codecs/aw88399.c2
-rw-r--r--sound/soc/codecs/cs42l51.c7
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c15
-rw-r--r--sound/soc/codecs/max98388.c1
-rw-r--r--sound/soc/codecs/pcm3060-i2c.c4
-rw-r--r--sound/soc/codecs/pcm3060-spi.c4
-rw-r--r--sound/soc/codecs/pcm3060.c4
-rw-r--r--sound/soc/codecs/pcm3060.h2
-rw-r--r--sound/soc/codecs/rt5640.c27
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c2
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c1
-rw-r--r--sound/soc/codecs/wcd937x.c12
-rw-r--r--sound/soc/codecs/wcd937x.h4
-rw-r--r--sound/soc/fsl/fsl_esai.c4
-rw-r--r--sound/soc/fsl/fsl_micfil.c81
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c64
-rw-r--r--sound/soc/intel/avs/core.c3
-rw-r--r--sound/soc/intel/avs/pcm.c19
-rw-r--r--sound/soc/intel/avs/pcm.h16
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c48
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c38
-rw-r--r--sound/soc/loongson/loongson_card.c1
-rw-r--r--sound/soc/qcom/Kconfig2
-rw-r--r--sound/soc/qcom/lpass-cpu.c2
-rw-r--r--sound/soc/qcom/sc7280.c10
-rw-r--r--sound/soc/qcom/sdm845.c7
-rw-r--r--sound/soc/sh/rcar/core.c7
-rw-r--r--sound/soc/soc-dapm.c6
-rw-r--r--sound/soc/sof/amd/acp-loader.c5
-rw-r--r--sound/soc/sof/amd/acp.c14
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c23
-rw-r--r--sound/soc/sof/intel/hda-dai.c37
-rw-r--r--sound/soc/sof/intel/hda-loader.c17
-rw-r--r--sound/soc/sof/ipc4-topology.c15
-rw-r--r--sound/soc/sof/sof-client-probes-ipc4.c1
-rw-r--r--sound/soc/stm/stm32_sai_sub.c6
-rw-r--r--sound/soc/stm/stm32_spdifrx.c2
-rw-r--r--sound/usb/mixer.c1
-rw-r--r--sound/usb/mixer_quirks.c3
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--tools/arch/arm64/include/asm/cputype.h2
-rw-r--r--tools/arch/x86/include/asm/msr-index.h34
-rw-r--r--tools/arch/x86/include/uapi/asm/kvm.h1
-rw-r--r--tools/arch/x86/include/uapi/asm/unistd_32.h3
-rw-r--r--tools/arch/x86/include/uapi/asm/unistd_64.h3
-rw-r--r--tools/include/linux/bits.h15
-rw-r--r--tools/include/linux/unaligned.h11
-rw-r--r--tools/include/uapi/linux/bits.h3
-rw-r--r--tools/include/uapi/linux/bpf.h3
-rw-r--r--tools/include/uapi/linux/const.h17
-rw-r--r--tools/include/uapi/linux/netdev.h1
-rw-r--r--tools/include/vdso/unaligned.h15
-rw-r--r--tools/lib/thermal/Makefile4
-rw-r--r--tools/lib/thermal/sampling.c2
-rw-r--r--tools/mm/page-types.c9
-rw-r--r--tools/mm/slabinfo.c4
-rwxr-xr-xtools/net/ynl/cli.py23
-rwxr-xr-xtools/net/ynl/ethtool.py2
-rw-r--r--tools/net/ynl/generated/Makefile2
-rw-r--r--tools/net/ynl/lib/Makefile2
-rw-r--r--tools/net/ynl/lib/nlspec.py3
-rw-r--r--tools/net/ynl/lib/ynl.py57
-rw-r--r--tools/net/ynl/samples/Makefile2
-rw-r--r--tools/net/ynl/samples/page-pool.c2
-rwxr-xr-xtools/net/ynl/ynl-gen-c.py21
-rw-r--r--tools/perf/Makefile.config4
-rw-r--r--tools/perf/builtin-trace.c2
-rwxr-xr-xtools/perf/check-headers.sh1
-rwxr-xr-xtools/perf/tests/shell/base_probe/test_adding_blacklisted.sh69
-rw-r--r--tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c22
-rw-r--r--tools/perf/util/cap.c10
-rw-r--r--tools/perf/util/python.c3
-rw-r--r--tools/perf/util/syscalltbl.c10
-rw-r--r--tools/sched_ext/include/scx/common.bpf.h2
-rw-r--r--tools/sched_ext/scx_show_state.py2
-rw-r--r--tools/testing/cxl/test/cxl.c200
-rw-r--r--tools/testing/cxl/test/mem.c1
-rw-r--r--tools/testing/selftests/bpf/.gitignore1
-rw-r--r--tools/testing/selftests/bpf/Makefile24
-rw-r--r--tools/testing/selftests/bpf/map_tests/lpm_trie_map_get_next_key.c109
-rw-r--r--tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c264
-rw-r--r--tools/testing/selftests/bpf/prog_tests/mptcp.c42
-rw-r--r--tools/testing/selftests/bpf/prog_tests/test_csum_diff.c408
-rw-r--r--tools/testing/selftests/bpf/prog_tests/verifier.c19
-rw-r--r--tools/testing/selftests/bpf/progs/csum_diff_test.c42
-rw-r--r--tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c82
-rw-r--r--tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c167
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_array_access.c3
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_bits_iter.c87
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c55
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_const.c31
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_mtu.c18
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_search_pruning.c23
-rw-r--r--tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c3
-rw-r--r--tools/testing/selftests/bpf/test_sockmap.c202
-rwxr-xr-xtools/testing/selftests/bpf/test_tcp_check_syncookie.sh85
-rw-r--r--tools/testing/selftests/bpf/test_tcp_check_syncookie_user.c213
-rw-r--r--tools/testing/selftests/bpf/veristat.cfg1
-rwxr-xr-xtools/testing/selftests/drivers/net/bonding/bond_options.sh54
-rw-r--r--tools/testing/selftests/drivers/net/hw/.gitignore1
-rw-r--r--tools/testing/selftests/drivers/net/hw/Makefile9
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/devmem.py45
-rw-r--r--tools/testing/selftests/drivers/net/hw/ncdevmem.c789
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/rss_ctx.py79
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap.sh2
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_drops.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh12
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip6.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan_ipv6.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/tc_sample.sh4
-rwxr-xr-xtools/testing/selftests/drivers/net/netcons_basic.sh40
-rw-r--r--tools/testing/selftests/drivers/net/netdevsim/Makefile3
-rw-r--r--tools/testing/selftests/drivers/net/netdevsim/config1
-rw-r--r--tools/testing/selftests/drivers/net/netdevsim/ethtool-features.sh31
-rwxr-xr-xtools/testing/selftests/drivers/net/netdevsim/fib_notifications.sh6
-rwxr-xr-xtools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh117
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/mount_options.tc101
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc16
-rw-r--r--tools/testing/selftests/ftrace/test.d/functions25
-rwxr-xr-xtools/testing/selftests/intel_pstate/run.sh9
-rw-r--r--tools/testing/selftests/kvm/Makefile10
-rw-r--r--tools/testing/selftests/kvm/guest_memfd_test.c2
-rw-r--r--tools/testing/selftests/kvm/lib/x86_64/vmx.c2
-rw-r--r--tools/testing/selftests/kvm/memslot_perf_test.c2
-rw-r--r--tools/testing/selftests/mm/Makefile3
-rw-r--r--tools/testing/selftests/mm/hugetlb_dio.c12
-rw-r--r--tools/testing/selftests/mm/page_frag/Makefile18
-rw-r--r--tools/testing/selftests/mm/page_frag/page_frag_test.c198
-rwxr-xr-xtools/testing/selftests/mm/run_vmtests.sh8
-rwxr-xr-xtools/testing/selftests/mm/test_page_frag.sh175
-rw-r--r--tools/testing/selftests/mm/uffd-common.c5
-rw-r--r--tools/testing/selftests/mm/uffd-common.h3
-rw-r--r--tools/testing/selftests/mm/uffd-unit-tests.c24
-rw-r--r--tools/testing/selftests/mount_setattr/mount_setattr_test.c9
-rw-r--r--tools/testing/selftests/net/.gitignore3
-rw-r--r--tools/testing/selftests/net/Makefile7
-rwxr-xr-xtools/testing/selftests/net/busy_poll_test.sh165
-rw-r--r--tools/testing/selftests/net/busy_poller.c346
-rwxr-xr-xtools/testing/selftests/net/drop_monitor_tests.sh2
-rwxr-xr-xtools/testing/selftests/net/fdb_notify.sh96
-rwxr-xr-xtools/testing/selftests/net/fib_tests.sh8
-rw-r--r--tools/testing/selftests/net/forwarding/Makefile3
-rw-r--r--tools/testing/selftests/net/forwarding/devlink_lib.sh2
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_flat.sh14
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_flat_key.sh14
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_flat_keys.sh14
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_hier.sh14
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_hier_key.sh14
-rwxr-xr-xtools/testing/selftests/net/forwarding/ip6gre_hier_keys.sh14
-rw-r--r--tools/testing/selftests/net/forwarding/ip6gre_lib.sh80
-rw-r--r--tools/testing/selftests/net/forwarding/lib.sh199
-rwxr-xr-xtools/testing/selftests/net/forwarding/tc_police.sh8
-rw-r--r--tools/testing/selftests/net/hsr/config1
-rw-r--r--tools/testing/selftests/net/hsr/hsr_common.sh4
-rwxr-xr-xtools/testing/selftests/net/hsr/hsr_ping.sh98
-rw-r--r--tools/testing/selftests/net/hsr/settings1
-rwxr-xr-xtools/testing/selftests/net/ipv6_route_update_soft_lockup.sh262
-rw-r--r--tools/testing/selftests/net/lib.sh223
-rw-r--r--tools/testing/selftests/net/mptcp/Makefile2
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_connect.sh9
-rw-r--r--tools/testing/selftests/net/ncdevmem.c570
-rw-r--r--tools/testing/selftests/net/netfilter/Makefile7
-rw-r--r--tools/testing/selftests/net/netfilter/conntrack_dump_flush.c6
-rwxr-xr-xtools/testing/selftests/net/netfilter/conntrack_dump_flush.sh3
-rwxr-xr-xtools/testing/selftests/net/netfilter/nft_flowtable.sh39
-rwxr-xr-xtools/testing/selftests/net/netfilter/nft_queue.sh8
-rw-r--r--tools/testing/selftests/net/netlink-dumps.c110
-rwxr-xr-xtools/testing/selftests/net/pmtu.sh114
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh108
-rwxr-xr-xtools/testing/selftests/net/veth.sh2
-rw-r--r--tools/testing/selftests/sched_ext/Makefile2
-rw-r--r--tools/testing/selftests/sched_ext/create_dsq.bpf.c6
-rw-r--r--tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/dsp_local_on.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/enq_last_no_enq_fails.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/enq_last_no_enq_fails.c10
-rw-r--r--tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/exit.bpf.c22
-rw-r--r--tools/testing/selftests/sched_ext/hotplug.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/init_enable_count.bpf.c8
-rw-r--r--tools/testing/selftests/sched_ext/maximal.bpf.c58
-rw-r--r--tools/testing/selftests/sched_ext/maybe_null.bpf.c6
-rw-r--r--tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/maybe_null_fail_yld.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/prog_run.bpf.c2
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c2
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c6
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c2
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c12
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/basic.json6
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/cgroup.json6
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/flow.json2
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/route.json2
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/u32.json24
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json98
-rw-r--r--tools/testing/selftests/watchdog/watchdog-test.c6
-rw-r--r--tools/testing/vma/vma.c40
-rw-r--r--tools/usb/usbip/src/usbip_detach.c1
-rw-r--r--tools/virtio/vringh_test.c2
1981 files changed, 57199 insertions, 45429 deletions
diff --git a/.mailmap b/.mailmap
index 9a94c514e32c..5e829da09e7f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -199,7 +199,8 @@ Elliot Berman <quic_eberman@quicinc.com> <eberman@codeaurora.org>
Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
-Eugen Hristev <eugen.hristev@collabora.com> <eugen.hristev@microchip.com>
+Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@microchip.com>
+Eugen Hristev <eugen.hristev@linaro.org> <eugen.hristev@collabora.com>
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> <ezequiel@collabora.com>
Faith Ekstrand <faith.ekstrand@collabora.com> <jason@jlekstrand.net>
@@ -282,7 +283,7 @@ Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com>
Jan Kuliga <jtkuliga.kdev@gmail.com> <jankul@alatek.krakow.pl>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@linux.intel.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko@profian.com>
-Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@tuni.fi>
+Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@parity.io>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
@@ -664,6 +665,7 @@ Tomeu Vizoso <tomeu@tomeuvizoso.net> <tomeu.vizoso@collabora.com>
Thomas Graf <tgraf@suug.ch>
Thomas Körper <socketcan@esd.eu> <thomas.koerper@esd.eu>
Thomas Pedersen <twp@codeaurora.org>
+Thorsten Blum <thorsten.blum@linux.dev> <thorsten.blum@toblux.com>
Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com>
Tingwei Zhang <quic_tingwei@quicinc.com> <tingwei@codeaurora.org>
Tirupathi Reddy <quic_tirupath@quicinc.com> <tirupath@codeaurora.org>
diff --git a/CREDITS b/CREDITS
index 63f53feefa0a..96660c63f5b9 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1204,6 +1204,10 @@ S: Dreisbachstrasse 24
S: D-57250 Netphen
S: Germany
+N: Florian Fainelli
+E: f.fainelli@gmail.com
+D: DSA
+
N: Rik Faith
E: faith@acm.org
D: Future Domain TMC-16x0 SCSI driver (author)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index 69af2173555f..6d02168d78be 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -1599,6 +1599,15 @@ The following nested keys are defined.
pglazyfreed (npn)
Amount of reclaimed lazyfree pages
+ swpin_zero
+ Number of pages swapped into memory and filled with zero, where I/O
+ was optimized out because the page content was detected to be zero
+ during swapout.
+
+ swpout_zero
+ Number of zero-filled pages swapped out with I/O skipped due to the
+ content being detected as zero.
+
zswpin
Number of pages moved in to memory from zswap.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 1518343bbe22..ea717cdaf581 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1546,6 +1546,7 @@
failslab=
fail_usercopy=
fail_page_alloc=
+ fail_skb_realloc=
fail_make_request=[KNL]
General fault injection mechanism.
Format: <interval>,<probability>,<space>,<times>
@@ -6688,7 +6689,7 @@
0: no polling (default)
thp_anon= [KNL]
- Format: <size>,<size>[KMG]:<state>;<size>-<size>[KMG]:<state>
+ Format: <size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>
state is one of "always", "madvise", "never" or "inherit".
Control the default behavior of the system with respect
to anonymous transparent hugepages.
@@ -6727,6 +6728,15 @@
torture.verbose_sleep_duration= [KNL]
Duration of each verbose-printk() sleep in jiffies.
+ tpm.disable_pcr_integrity= [HW,TPM]
+ Do not protect PCR registers from unintended physical
+ access, or interposers in the bus by the means of
+ having an integrity protected session wrapped around
+ TPM2_PCR_Extend command. Consider this in a situation
+ where TPM is heavily utilized by IMA, thus protection
+ causing a major performance hit, and the space where
+ machines are deployed is by other means guarded.
+
tpm_suspend_pcr=[HW,TPM]
Format: integer pcr id
Specify that at suspend time, the tpm driver
diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index cfdd16a52e39..a1bb495eab59 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -303,7 +303,7 @@ control by passing the parameter ``transparent_hugepage=always`` or
kernel command line.
Alternatively, each supported anonymous THP size can be controlled by
-passing ``thp_anon=<size>,<size>[KMG]:<state>;<size>-<size>[KMG]:<state>``,
+passing ``thp_anon=<size>[KMG],<size>[KMG]:<state>;<size>[KMG]-<size>[KMG]:<state>``,
where ``<size>`` is the THP size (must be a power of 2 of PAGE_SIZE and
supported anonymous THP) and ``<state>`` is one of ``always``, ``madvise``,
``never`` or ``inherit``.
diff --git a/Documentation/admin-guide/pm/cpufreq.rst b/Documentation/admin-guide/pm/cpufreq.rst
index fe1be4ad88cb..a21369eba034 100644
--- a/Documentation/admin-guide/pm/cpufreq.rst
+++ b/Documentation/admin-guide/pm/cpufreq.rst
@@ -425,8 +425,8 @@ This governor exposes only one tunable:
``rate_limit_us``
Minimum time (in microseconds) that has to pass between two consecutive
- runs of governor computations (default: 1000 times the scaling driver's
- transition latency).
+ runs of governor computations (default: 1.5 times the scaling driver's
+ transition latency or the maximum 2ms).
The purpose of this tunable is to reduce the scheduler context overhead
of the governor which might be excessive without it.
@@ -474,17 +474,17 @@ This governor exposes the following tunables:
This is how often the governor's worker routine should run, in
microseconds.
- Typically, it is set to values of the order of 10000 (10 ms). Its
- default value is equal to the value of ``cpuinfo_transition_latency``
- for each policy this governor is attached to (but since the unit here
- is greater by 1000, this means that the time represented by
- ``sampling_rate`` is 1000 times greater than the transition latency by
- default).
+ Typically, it is set to values of the order of 2000 (2 ms). Its
+ default value is to add a 50% breathing room
+ to ``cpuinfo_transition_latency`` on each policy this governor is
+ attached to. The minimum is typically the length of two scheduler
+ ticks.
If this tunable is per-policy, the following shell command sets the time
- represented by it to be 750 times as high as the transition latency::
+ represented by it to be 1.5 times as high as the transition latency
+ (the default)::
- # echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) > ondemand/sampling_rate
+ # echo `$(($(cat cpuinfo_transition_latency) * 3 / 2)) > ondemand/sampling_rate
``up_threshold``
If the estimated CPU load is above this value (in percent), the governor
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
index 3a82aec9021c..497c0eb4ed0b 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
@@ -63,6 +63,16 @@ properties:
- const: sleep
power-domains:
+ description: |
+ The MediaTek DPI module is typically associated with one of the
+ following multimedia power domains:
+ POWER_DOMAIN_DISPLAY
+ POWER_DOMAIN_VDOSYS
+ POWER_DOMAIN_MM
+ The specific power domain used varies depending on the SoC design.
+
+ It is recommended to explicitly add the appropriate power domain
+ property to the DPI node in the device tree.
maxItems: 1
port:
@@ -79,20 +89,6 @@ required:
- clock-names
- port
-allOf:
- - if:
- not:
- properties:
- compatible:
- contains:
- enum:
- - mediatek,mt6795-dpi
- - mediatek,mt8173-dpi
- - mediatek,mt8186-dpi
- then:
- properties:
- power-domains: false
-
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml
index e4affc854f3d..4b6ff546757e 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml
@@ -38,6 +38,7 @@ properties:
description: A phandle and PM domain specifier as defined by bindings of
the power controller specified by phandle. See
Documentation/devicetree/bindings/power/power-domain.yaml for details.
+ maxItems: 1
mediatek,gce-client-reg:
description:
@@ -57,6 +58,9 @@ properties:
clocks:
items:
- description: SPLIT Clock
+ - description: Used for interfacing with the HDMI RX signal source.
+ - description: Paired with receiving HDMI RX metadata.
+ minItems: 1
required:
- compatible
@@ -72,9 +76,24 @@ allOf:
const: mediatek,mt8195-mdp3-split
then:
+ properties:
+ clocks:
+ minItems: 3
+
required:
- mediatek,gce-client-reg
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: mediatek,mt8173-disp-split
+
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index 54d7d11bfed4..ff7a6f12cd00 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -124,7 +124,7 @@ properties:
atomic mode of operation, even if requested.
default: 0
- max-rx-timeout-ms:
+ arm,max-rx-timeout-ms:
description:
An optional time value, expressed in milliseconds, representing the
transport maximum timeout value for the receive channel. The value should
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
index bd19abb867d9..0065d6508824 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -67,6 +67,10 @@ properties:
A 2.5V to 3.3V supply for the external reference voltage. When omitted,
the internal 2.5V reference is used.
+ refin-supply:
+ description:
+ A 2.5V to 3.3V supply for external reference voltage, for ad7380-4 only.
+
aina-supply:
description:
The common mode voltage supply for the AINA- pin on pseudo-differential
@@ -135,6 +139,23 @@ allOf:
ainc-supply: false
aind-supply: false
+ # ad7380-4 uses refin-supply as external reference.
+ # All other chips from ad738x family use refio as optional external reference.
+ # When refio-supply is omitted, internal reference is used.
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7380-4
+ then:
+ properties:
+ refio-supply: false
+ required:
+ - refin-supply
+ else:
+ properties:
+ refin-supply: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
diff --git a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml
index 37a65badb448..0a2d7baf5db3 100644
--- a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml
+++ b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml
@@ -34,6 +34,12 @@ properties:
firmware-name:
maxItems: 1
+ device-wakeup-gpios:
+ maxItems: 1
+ description:
+ Host-To-Chip power save mechanism is driven by this GPIO
+ connected to BT_WAKE_IN pin of the NXP chipset.
+
required:
- compatible
@@ -41,10 +47,12 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
serial {
bluetooth {
compatible = "nxp,88w8987-bt";
fw-init-baudrate = <3000000>;
firmware-name = "uartuart8987_bt_v0.bin";
+ device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
index 30c0c3e6f37a..62ca63e8a26f 100644
--- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
+++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
@@ -34,6 +34,7 @@ properties:
- microchip,ksz9563
- microchip,ksz8563
- microchip,ksz8567
+ - microchip,lan9646
reset-gpios:
description:
@@ -81,6 +82,26 @@ properties:
interrupts:
maxItems: 1
+ mdio:
+ $ref: /schemas/net/mdio.yaml#
+ unevaluatedProperties: false
+ properties:
+ mdio-parent-bus:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle pointing to the MDIO bus controller connected to the
+ secondary MDIO interface. This property should be used when
+ the internal MDIO bus is accessed via a secondary MDIO
+ interface rather than the primary management interface.
+
+ patternProperties:
+ "^ethernet-phy@[0-9a-f]$":
+ type: object
+ $ref: /schemas/net/ethernet-phy.yaml#
+ unevaluatedProperties: false
+ description:
+ Integrated PHY node
+
required:
- compatible
- reg
@@ -138,7 +159,6 @@ examples:
pinctrl-0 = <&pinctrl_spi_ksz>;
cs-gpios = <&pioC 25 0>;
- id = <1>;
ksz9477: switch@0 {
compatible = "microchip,ksz9477";
diff --git a/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml b/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml
index c1dd6aa04321..71c43ece8295 100644
--- a/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml
+++ b/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml
@@ -20,10 +20,13 @@ maintainers:
properties:
compatible:
- items:
- - enum:
- - pci1957,ee01
- - const: fsl,enetc-mdio
+ oneOf:
+ - items:
+ - enum:
+ - pci1957,ee01
+ - const: fsl,enetc-mdio
+ - items:
+ - const: pci1131,ee00
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/net/fsl,enetc.yaml b/Documentation/devicetree/bindings/net/fsl,enetc.yaml
index e152c93998fe..ca70f0050171 100644
--- a/Documentation/devicetree/bindings/net/fsl,enetc.yaml
+++ b/Documentation/devicetree/bindings/net/fsl,enetc.yaml
@@ -20,14 +20,25 @@ maintainers:
properties:
compatible:
- items:
+ oneOf:
+ - items:
+ - enum:
+ - pci1957,e100
+ - const: fsl,enetc
- enum:
- - pci1957,e100
- - const: fsl,enetc
+ - pci1131,e101
reg:
maxItems: 1
+ clocks:
+ items:
+ - description: MAC transmit/receive reference clock
+
+ clock-names:
+ items:
+ - const: ref
+
mdio:
$ref: mdio.yaml
unevaluatedProperties: false
@@ -40,6 +51,17 @@ required:
allOf:
- $ref: /schemas/pci/pci-device.yaml
- $ref: ethernet-controller.yaml
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - pci1131,e101
+ then:
+ properties:
+ clocks: false
+ clock-names: false
unevaluatedProperties: false
diff --git a/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml b/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml
index 71c25c4580ea..cc674b21588c 100644
--- a/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml
+++ b/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml
@@ -53,37 +53,21 @@ examples:
ethernet-phy@1 {
reg = <1>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <10 8>; /* Pin 10, active low */
};
ethernet-phy@2 {
reg = <2>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <10 8>; /* Pin 10, active low */
};
ethernet-phy@3 {
reg = <3>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <10 8>; /* Pin 10, active low */
};
ethernet-phy@4 {
reg = <4>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <10 8>; /* Pin 10, active low */
};
@@ -96,37 +80,21 @@ examples:
ethernet-phy@1 {
reg = <1>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <12 8>; /* Pin 12, active low */
};
ethernet-phy@2 {
reg = <2>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <12 8>; /* Pin 12, active low */
};
ethernet-phy@3 {
reg = <3>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <12 8>; /* Pin 12, active low */
};
ethernet-phy@4 {
reg = <4>;
- marvell,reg-init = <3 0x10 0 0x5777>,
- <3 0x11 0 0x00aa>,
- <3 0x12 0 0x4105>,
- <3 0x13 0 0x0a60>;
interrupt-parent = <&gpio>;
interrupts = <12 8>; /* Pin 12, active low */
};
diff --git a/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml b/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml
index fcafef8d5a33..dedfad526666 100644
--- a/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml
+++ b/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml
@@ -9,6 +9,7 @@ title: Microchip Sparx5 Ethernet switch controller
maintainers:
- Steen Hegelund <steen.hegelund@microchip.com>
- Lars Povlsen <lars.povlsen@microchip.com>
+ - Daniel Machon <daniel.machon@microchip.com>
description: |
The SparX-5 Enterprise Ethernet switch family provides a rich set of
@@ -34,7 +35,24 @@ properties:
pattern: "^switch@[0-9a-f]+$"
compatible:
- const: microchip,sparx5-switch
+ oneOf:
+ - enum:
+ - microchip,lan9691-switch
+ - microchip,sparx5-switch
+ - items:
+ - enum:
+ - microchip,lan969c-switch
+ - microchip,lan969b-switch
+ - microchip,lan969a-switch
+ - microchip,lan9699-switch
+ - microchip,lan9698-switch
+ - microchip,lan9697-switch
+ - microchip,lan9696-switch
+ - microchip,lan9695-switch
+ - microchip,lan9694-switch
+ - microchip,lan9693-switch
+ - microchip,lan9692-switch
+ - const: microchip,lan9691-switch
reg:
items:
diff --git a/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml b/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
new file mode 100644
index 000000000000..97389fd5dbbf
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/nxp,netc-blk-ctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NETC Blocks Control
+
+description:
+ Usually, NETC has 2 blocks of 64KB registers, integrated endpoint register
+ block (IERB) and privileged register block (PRB). IERB is used for pre-boot
+ initialization for all NETC devices, such as ENETC, Timer, EMIDO and so on.
+ And PRB controls global reset and global error handling for NETC. Moreover,
+ for the i.MX platform, there is also a NETCMIX block for link configuration,
+ such as MII protocol, PCS protocol, etc.
+
+maintainers:
+ - Wei Fang <wei.fang@nxp.com>
+ - Clark Wang <xiaoning.wang@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ - nxp,imx95-netc-blk-ctrl
+
+ reg:
+ maxItems: 3
+
+ reg-names:
+ items:
+ - const: ierb
+ - const: prb
+ - const: netcmix
+
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 2
+
+ ranges: true
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: ipg
+
+ power-domains:
+ maxItems: 1
+
+patternProperties:
+ "^pcie@[0-9a-f]+$":
+ $ref: /schemas/pci/host-generic-pci.yaml#
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ system-controller@4cde0000 {
+ compatible = "nxp,imx95-netc-blk-ctrl";
+ reg = <0x0 0x4cde0000 0x0 0x10000>,
+ <0x0 0x4cdf0000 0x0 0x10000>,
+ <0x0 0x4c81000c 0x0 0x18>;
+ reg-names = "ierb", "prb", "netcmix";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ clocks = <&scmi_clk 98>;
+ clock-names = "ipg";
+ power-domains = <&scmi_devpd 18>;
+
+ pcie@4cb00000 {
+ compatible = "pci-host-ecam-generic";
+ reg = <0x0 0x4cb00000 0x0 0x100000>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ bus-range = <0x1 0x1>;
+ ranges = <0x82000000 0x0 0x4cce0000 0x0 0x4cce0000 0x0 0x20000
+ 0xc2000000 0x0 0x4cd10000 0x0 0x4cd10000 0x0 0x10000>;
+
+ mdio@0,0 {
+ compatible = "pci1131,ee00";
+ reg = <0x010000 0 0 0 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
index 6672327358bc..0bcd593a7bd0 100644
--- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
+++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
@@ -18,11 +18,20 @@ allOf:
properties:
compatible:
- enum:
- - qcom,qcs404-ethqos
- - qcom,sa8775p-ethqos
- - qcom,sc8280xp-ethqos
- - qcom,sm8150-ethqos
+ oneOf:
+ - items:
+ - enum:
+ - qcom,qcs8300-ethqos
+ - const: qcom,sa8775p-ethqos
+ - items:
+ - enum:
+ - qcom,qcs615-ethqos
+ - const: qcom,sm8150-ethqos
+ - enum:
+ - qcom,qcs404-ethqos
+ - qcom,sa8775p-ethqos
+ - qcom,sc8280xp-ethqos
+ - qcom,sm8150-ethqos
reg:
maxItems: 2
diff --git a/Documentation/devicetree/bindings/net/renesas,ether.yaml b/Documentation/devicetree/bindings/net/renesas,ether.yaml
index 29355ab98569..d6c5983499b8 100644
--- a/Documentation/devicetree/bindings/net/renesas,ether.yaml
+++ b/Documentation/devicetree/bindings/net/renesas,ether.yaml
@@ -59,6 +59,9 @@ properties:
clocks:
maxItems: 1
+ iommus:
+ maxItems: 1
+
power-domains:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/net/sff,sfp.yaml b/Documentation/devicetree/bindings/net/sff,sfp.yaml
index 90611b598d2b..15616ad737f5 100644
--- a/Documentation/devicetree/bindings/net/sff,sfp.yaml
+++ b/Documentation/devicetree/bindings/net/sff,sfp.yaml
@@ -132,7 +132,7 @@ examples:
pinctrl-names = "default";
pinctrl-0 = <&cpm_phy0_pins &cps_phy0_pins>;
reg = <0>;
- interrupt = <&cpm_gpio2 18 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
sfp = <&sfp2>;
};
};
diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
index 4e2ba1bf788c..eb1f3ae41ab9 100644
--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -26,6 +26,7 @@ select:
- snps,dwmac-3.610
- snps,dwmac-3.70a
- snps,dwmac-3.710
+ - snps,dwmac-3.72a
- snps,dwmac-4.00
- snps,dwmac-4.10a
- snps,dwmac-4.20a
@@ -90,6 +91,7 @@ properties:
- snps,dwmac-3.610
- snps,dwmac-3.70a
- snps,dwmac-3.710
+ - snps,dwmac-3.72a
- snps,dwmac-4.00
- snps,dwmac-4.10a
- snps,dwmac-4.20a
@@ -99,6 +101,7 @@ properties:
- snps,dwxgmac-2.10
- starfive,jh7100-dwmac
- starfive,jh7110-dwmac
+ - thead,th1520-gmac
reg:
minItems: 1
@@ -560,7 +563,7 @@ properties:
max read outstanding req. limit
snps,kbbe:
- $ref: /schemas/types.yaml#/definitions/uint32
+ $ref: /schemas/types.yaml#/definitions/flag
description:
do not cross 1KiB boundary.
diff --git a/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml b/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml
new file mode 100644
index 000000000000..6d9de3303762
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/thead,th1520-gmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: T-HEAD TH1520 GMAC Ethernet controller
+
+maintainers:
+ - Drew Fustini <dfustini@tenstorrent.com>
+
+description: |
+ The TH1520 GMAC is described in the TH1520 Peripheral Interface User Manual
+ https://git.beagleboard.org/beaglev-ahead/beaglev-ahead/-/tree/main/docs
+
+ Features include
+ - Compliant with IEEE802.3 Specification
+ - IEEE 1588-2008 standard for precision networked clock synchronization
+ - Supports 10/100/1000Mbps data transfer rate
+ - Supports RGMII/MII interface
+ - Preamble and start of frame data (SFD) insertion in Transmit path
+ - Preamble and SFD deletion in the Receive path
+ - Automatic CRC and pad generation options for receive frames
+ - MDIO master interface for PHY device configuration and management
+
+ The GMAC Registers consists of two parts
+ - APB registers are used to configure clock frequency/clock enable/clock
+ direction/PHY interface type.
+ - AHB registers are use to configure GMAC core (DesignWare Core part).
+ GMAC core register consists of DMA registers and GMAC registers.
+
+select:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - thead,th1520-gmac
+ required:
+ - compatible
+
+allOf:
+ - $ref: snps,dwmac.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - thead,th1520-gmac
+ - const: snps,dwmac-3.70a
+
+ reg:
+ items:
+ - description: DesignWare GMAC IP core registers
+ - description: GMAC APB registers
+
+ reg-names:
+ items:
+ - const: dwmac
+ - const: apb
+
+ clocks:
+ items:
+ - description: GMAC main clock
+ - description: Peripheral registers interface clock
+
+ clock-names:
+ items:
+ - const: stmmaceth
+ - const: pclk
+
+ interrupts:
+ items:
+ - description: Combined signal for various interrupt events
+
+ interrupt-names:
+ items:
+ - const: macirq
+
+required:
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ gmac0: ethernet@e7070000 {
+ compatible = "thead,th1520-gmac", "snps,dwmac-3.70a";
+ reg = <0xe7070000 0x2000>, <0xec003000 0x1000>;
+ reg-names = "dwmac", "apb";
+ clocks = <&clk 1>, <&clk 2>;
+ clock-names = "stmmaceth", "pclk";
+ interrupts = <66>;
+ interrupt-names = "macirq";
+ phy-mode = "rgmii-id";
+ snps,fixed-burst;
+ snps,axi-config = <&stmmac_axi_setup>;
+ snps,pbl = <32>;
+ phy-handle = <&phy0>;
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dwmac-mdio";
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
index e564f20d8f41..a3607d55ef36 100644
--- a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
@@ -53,6 +53,7 @@ properties:
- pci14e4,4488 # BCM4377
- pci14e4,4425 # BCM4378
- pci14e4,4433 # BCM4387
+ - pci14e4,449d # BCM43752
reg:
description: SDIO function number for the device (for most cases
@@ -121,6 +122,14 @@ properties:
NVRAM. This would normally be filled in by the bootloader from platform
configuration data.
+ clocks:
+ items:
+ - description: External Low Power Clock input (32.768KHz)
+
+ clock-names:
+ items:
+ - const: lpo
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml
index 2460ccc08237..5d40f22765bb 100644
--- a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml
@@ -16,7 +16,11 @@ description:
properties:
compatible:
- const: microchip,wilc1000
+ oneOf:
+ - items:
+ - const: microchip,wilc3000
+ - const: microchip,wilc1000
+ - const: microchip,wilc1000
reg: true
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
index 8675d7d0215c..a71fdf05bc1e 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
@@ -50,6 +50,9 @@ properties:
vddrfa1p7-supply:
description: VDD_RFA_1P7 supply regulator handle
+ vddrfa1p8-supply:
+ description: VDD_RFA_1P8 supply regulator handle
+
vddpcie0p9-supply:
description: VDD_PCIE_0P9 supply regulator handle
@@ -77,6 +80,22 @@ allOf:
- vddrfa1p7-supply
- vddpcie0p9-supply
- vddpcie1p8-supply
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: pci17cb,1103
+ then:
+ required:
+ - vddrfacmn-supply
+ - vddaon-supply
+ - vddwlcx-supply
+ - vddwlmx-supply
+ - vddrfa0p8-supply
+ - vddrfa1p2-supply
+ - vddrfa1p8-supply
+ - vddpcie0p9-supply
+ - vddpcie1p8-supply
additionalProperties: false
@@ -99,6 +118,16 @@ examples:
compatible = "pci17cb,1103";
reg = <0x10000 0x0 0x0 0x0 0x0>;
+ vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>;
+ vddaon-supply = <&vreg_pmu_aon_0p8>;
+ vddwlcx-supply = <&vreg_pmu_wlcx_0p8>;
+ vddwlmx-supply = <&vreg_pmu_wlmx_0p8>;
+ vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>;
+ vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>;
+ vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>;
+ vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>;
+ vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>;
+
qcom,ath11k-calibration-variant = "LE_X13S";
};
};
diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
index e95c21628281..fb02e579463c 100644
--- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
+++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml
@@ -61,7 +61,7 @@ properties:
- gmii
- rgmii
- sgmii
- - 1000BaseX
+ - 1000base-x
xlnx,phy-type:
description:
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
index dcf4fa55fbba..380a9222a51d 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
@@ -154,8 +154,6 @@ allOf:
- qcom,sm8550-qmp-gen4x2-pcie-phy
- qcom,sm8650-qmp-gen3x2-pcie-phy
- qcom,sm8650-qmp-gen4x2-pcie-phy
- - qcom,x1e80100-qmp-gen3x2-pcie-phy
- - qcom,x1e80100-qmp-gen4x2-pcie-phy
then:
properties:
clocks:
@@ -171,6 +169,8 @@ allOf:
- qcom,sc8280xp-qmp-gen3x1-pcie-phy
- qcom,sc8280xp-qmp-gen3x2-pcie-phy
- qcom,sc8280xp-qmp-gen3x4-pcie-phy
+ - qcom,x1e80100-qmp-gen3x2-pcie-phy
+ - qcom,x1e80100-qmp-gen4x2-pcie-phy
- qcom,x1e80100-qmp-gen4x4-pcie-phy
then:
properties:
@@ -201,6 +201,7 @@ allOf:
- qcom,sm8550-qmp-gen4x2-pcie-phy
- qcom,sm8650-qmp-gen4x2-pcie-phy
- qcom,x1e80100-qmp-gen4x2-pcie-phy
+ - qcom,x1e80100-qmp-gen4x4-pcie-phy
then:
properties:
resets:
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
index ab3206ffa4af..beef193aaaeb 100644
--- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
@@ -102,21 +102,21 @@ properties:
default: 2
interrupts:
- oneOf:
- - minItems: 1
- items:
- - description: TX interrupt
- - description: RX interrupt
- - items:
- - description: common/combined interrupt
+ minItems: 1
+ maxItems: 2
interrupt-names:
oneOf:
- - minItems: 1
+ - description: TX interrupt
+ const: tx
+ - description: RX interrupt
+ const: rx
+ - description: TX and RX interrupts
items:
- const: tx
- const: rx
- - const: common
+ - description: Common/combined interrupt
+ const: common
fck_parent:
$ref: /schemas/types.yaml#/definitions/string
diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
index ecf3d7d968c8..2cf229a076f0 100644
--- a/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3308-codec.yaml
@@ -48,6 +48,10 @@ properties:
- const: mclk_rx
- const: hclk
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
resets:
maxItems: 1
diff --git a/Documentation/fault-injection/fault-injection.rst b/Documentation/fault-injection/fault-injection.rst
index 8b8aeea71c68..1c14ba08fbfc 100644
--- a/Documentation/fault-injection/fault-injection.rst
+++ b/Documentation/fault-injection/fault-injection.rst
@@ -45,6 +45,32 @@ Available fault injection capabilities
ALLOW_ERROR_INJECTION() macro, by setting debugfs entries
under /sys/kernel/debug/fail_function. No boot option supported.
+- fail_skb_realloc
+
+ inject skb (socket buffer) reallocation events into the network path. The
+ primary goal is to identify and prevent issues related to pointer
+ mismanagement in the network subsystem. By forcing skb reallocation at
+ strategic points, this feature creates scenarios where existing pointers to
+ skb headers become invalid.
+
+ When the fault is injected and the reallocation is triggered, cached pointers
+ to skb headers and data no longer reference valid memory locations. This
+ deliberate invalidation helps expose code paths where proper pointer updating
+ is neglected after a reallocation event.
+
+ By creating these controlled fault scenarios, the system can catch instances
+ where stale pointers are used, potentially leading to memory corruption or
+ system instability.
+
+ To select the interface to act on, write the network name to
+ /sys/kernel/debug/fail_skb_realloc/devname.
+ If this field is left empty (which is the default value), skb reallocation
+ will be forced on all network interfaces.
+
+ The effectiveness of this fault detection is enhanced when KASAN is
+ enabled, as it helps identify invalid memory references and use-after-free
+ (UAF) issues.
+
- NVMe fault injection
inject NVMe status code and retry flag on devices permitted by setting
@@ -216,6 +242,19 @@ configuration of fault-injection capabilities.
use a negative errno, you better use 'printf' instead of 'echo', e.g.:
$ printf %#x -12 > retval
+- /sys/kernel/debug/fail_skb_realloc/devname:
+
+ Specifies the network interface on which to force SKB reallocation. If
+ left empty, SKB reallocation will be applied to all network interfaces.
+
+ Example usage::
+
+ # Force skb reallocation on eth0
+ echo "eth0" > /sys/kernel/debug/fail_skb_realloc/devname
+
+ # Clear the selection and force skb reallocation on all interfaces
+ echo "" > /sys/kernel/debug/fail_skb_realloc/devname
+
Boot option
^^^^^^^^^^^
@@ -227,6 +266,7 @@ use the boot option::
fail_usercopy=
fail_make_request=
fail_futex=
+ fail_skb_realloc=
mmc_core.fail_request=<interval>,<probability>,<space>,<times>
proc entries
diff --git a/Documentation/filesystems/caching/cachefiles.rst b/Documentation/filesystems/caching/cachefiles.rst
index e04a27bdbe19..b3ccc782cb3b 100644
--- a/Documentation/filesystems/caching/cachefiles.rst
+++ b/Documentation/filesystems/caching/cachefiles.rst
@@ -115,7 +115,7 @@ set up cache ready for use. The following script commands are available:
This mask can also be set through sysfs, eg::
- echo 5 >/sys/modules/cachefiles/parameters/debug
+ echo 5 > /sys/module/cachefiles/parameters/debug
Starting the Cache
diff --git a/Documentation/iio/ad7380.rst b/Documentation/iio/ad7380.rst
index 9c784c1e652e..6f70b49b9ef2 100644
--- a/Documentation/iio/ad7380.rst
+++ b/Documentation/iio/ad7380.rst
@@ -41,13 +41,22 @@ supports only 1 SDO line.
Reference voltage
-----------------
-2 possible reference voltage sources are supported:
+ad7380-4
+~~~~~~~~
+
+ad7380-4 supports only an external reference voltage (2.5V to 3.3V). It must be
+declared in the device tree as ``refin-supply``.
+
+All other devices from ad738x family
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All other devices from ad738x support 2 possible reference voltage sources:
- Internal reference (2.5V)
- External reference (2.5V to 3.3V)
The source is determined by the device tree. If ``refio-supply`` is present,
-then the external reference is used, else the internal reference is used.
+then it is used as external reference, else the internal reference is used.
Oversampling and resolution boost
---------------------------------
diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml
index f2894ca35de8..8feefeae5376 100644
--- a/Documentation/netlink/specs/dpll.yaml
+++ b/Documentation/netlink/specs/dpll.yaml
@@ -86,6 +86,36 @@ definitions:
locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT.
render-max: true
-
+ type: enum
+ name: clock-quality-level
+ doc: |
+ level of quality of a clock device. This mainly applies when
+ the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER.
+ The current list is defined according to the table 11-7 contained
+ in ITU-T G.8264/Y.1364 document. One may extend this list freely
+ by other ITU-T defined clock qualities, or different ones defined
+ by another standardization body (for those, please use
+ different prefix).
+ entries:
+ -
+ name: itu-opt1-prc
+ value: 1
+ -
+ name: itu-opt1-ssu-a
+ -
+ name: itu-opt1-ssu-b
+ -
+ name: itu-opt1-eec1
+ -
+ name: itu-opt1-prtc
+ -
+ name: itu-opt1-eprtc
+ -
+ name: itu-opt1-eeec
+ -
+ name: itu-opt1-eprc
+ render-max: true
+ -
type: const
name: temp-divider
value: 1000
@@ -252,6 +282,17 @@ attribute-sets:
name: lock-status-error
type: u32
enum: lock-status-error
+ -
+ name: clock-quality-level
+ type: u32
+ enum: clock-quality-level
+ multi-attr: true
+ doc: |
+ Level of quality of a clock device. This mainly applies when
+ the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. This could
+ be put to message multiple times to indicate possible parallel
+ quality levels (e.g. one specified by ITU option 1 and another
+ one specified by option 2).
-
name: pin
enum-name: dpll_a_pin
diff --git a/Documentation/netlink/specs/mptcp_pm.yaml b/Documentation/netlink/specs/mptcp_pm.yaml
index 30d8342cacc8..dc190bf838fe 100644
--- a/Documentation/netlink/specs/mptcp_pm.yaml
+++ b/Documentation/netlink/specs/mptcp_pm.yaml
@@ -293,7 +293,6 @@ operations:
doc: Get endpoint information
attribute-set: attr
dont-validate: [ strict ]
- flags: [ uns-admin-perm ]
do: &get-addr-attrs
request:
attributes:
diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index f9cb97d6106c..cbb544bd6c84 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -263,6 +263,11 @@ attribute-sets:
the end of a NAPI cycle. This may add receive latency in exchange
for reducing the number of frames processed by the network stack.
type: uint
+ -
+ name: irq-suspend-timeout
+ doc: The timeout, in nanoseconds, of how long to suspend irq
+ processing, if event polling finds events
+ type: uint
-
name: queue
attributes:
@@ -653,6 +658,7 @@ operations:
- pid
- defer-hard-irqs
- gro-flush-timeout
+ - irq-suspend-timeout
dump:
request:
attributes:
@@ -704,6 +710,7 @@ operations:
- id
- defer-hard-irqs
- gro-flush-timeout
+ - irq-suspend-timeout
kernel-family:
headers: [ "linux/list.h"]
diff --git a/Documentation/netlink/specs/rt_neigh.yaml b/Documentation/netlink/specs/rt_neigh.yaml
new file mode 100644
index 000000000000..e670b6dc07be
--- /dev/null
+++ b/Documentation/netlink/specs/rt_neigh.yaml
@@ -0,0 +1,442 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+
+name: rt-neigh
+protocol: netlink-raw
+protonum: 0
+
+doc:
+ IP neighbour management over rtnetlink.
+
+definitions:
+ -
+ name: ndmsg
+ type: struct
+ members:
+ -
+ name: family
+ type: u8
+ -
+ name: pad
+ type: pad
+ len: 3
+ -
+ name: ifindex
+ type: s32
+ -
+ name: state
+ type: u16
+ enum: nud-state
+ -
+ name: flags
+ type: u8
+ enum: ntf-flags
+ -
+ name: type
+ type: u8
+ enum: rtm-type
+ -
+ name: ndtmsg
+ type: struct
+ members:
+ -
+ name: family
+ type: u8
+ -
+ name: pad
+ type: pad
+ len: 3
+ -
+ name: nud-state
+ type: flags
+ entries:
+ - incomplete
+ - reachable
+ - stale
+ - delay
+ - probe
+ - failed
+ - noarp
+ - permanent
+ -
+ name: ntf-flags
+ type: flags
+ entries:
+ - use
+ - self
+ - master
+ - proxy
+ - ext-learned
+ - offloaded
+ - sticky
+ - router
+ -
+ name: ntf-ext-flags
+ type: flags
+ entries:
+ - managed
+ - locked
+ -
+ name: rtm-type
+ type: enum
+ entries:
+ - unspec
+ - unicast
+ - local
+ - broadcast
+ - anycast
+ - multicast
+ - blackhole
+ - unreachable
+ - prohibit
+ - throw
+ - nat
+ - xresolve
+ -
+ name: nda-cacheinfo
+ type: struct
+ members:
+ -
+ name: confirmed
+ type: u32
+ -
+ name: used
+ type: u32
+ -
+ name: updated
+ type: u32
+ -
+ name: refcnt
+ type: u32
+ -
+ name: ndt-config
+ type: struct
+ members:
+ -
+ name: key-len
+ type: u16
+ -
+ name: entry-size
+ type: u16
+ -
+ name: entries
+ type: u32
+ -
+ name: last-flush
+ type: u32
+ -
+ name: last-rand
+ type: u32
+ -
+ name: hash-rnd
+ type: u32
+ -
+ name: hash-mask
+ type: u32
+ -
+ name: hash-chain-gc
+ type: u32
+ -
+ name: proxy-qlen
+ type: u32
+ -
+ name: ndt-stats
+ type: struct
+ members:
+ -
+ name: allocs
+ type: u64
+ -
+ name: destroys
+ type: u64
+ -
+ name: hash-grows
+ type: u64
+ -
+ name: res-failed
+ type: u64
+ -
+ name: lookups
+ type: u64
+ -
+ name: hits
+ type: u64
+ -
+ name: rcv-probes-mcast
+ type: u64
+ -
+ name: rcv-probes-ucast
+ type: u64
+ -
+ name: periodic-gc-runs
+ type: u64
+ -
+ name: forced-gc-runs
+ type: u64
+ -
+ name: table-fulls
+ type: u64
+
+attribute-sets:
+ -
+ name: neighbour-attrs
+ attributes:
+ -
+ name: unspec
+ type: binary
+ value: 0
+ -
+ name: dst
+ type: binary
+ display-hint: ipv4
+ -
+ name: lladr
+ type: binary
+ display-hint: mac
+ -
+ name: cacheinfo
+ type: binary
+ struct: nda-cacheinfo
+ -
+ name: probes
+ type: u32
+ -
+ name: vlan
+ type: u16
+ -
+ name: port
+ type: u16
+ -
+ name: vni
+ type: u32
+ -
+ name: ifindex
+ type: u32
+ -
+ name: master
+ type: u32
+ -
+ name: link-netnsid
+ type: s32
+ -
+ name: src-vni
+ type: u32
+ -
+ name: protocol
+ type: u8
+ -
+ name: nh-id
+ type: u32
+ -
+ name: fdb-ext-attrs
+ type: binary
+ -
+ name: flags-ext
+ type: u32
+ enum: ntf-ext-flags
+ -
+ name: ndm-state-mask
+ type: u16
+ -
+ name: ndm-flags-mask
+ type: u8
+ -
+ name: ndt-attrs
+ attributes:
+ -
+ name: name
+ type: string
+ -
+ name: thresh1
+ type: u32
+ -
+ name: thresh2
+ type: u32
+ -
+ name: thresh3
+ type: u32
+ -
+ name: config
+ type: binary
+ struct: ndt-config
+ -
+ name: parms
+ type: nest
+ nested-attributes: ndtpa-attrs
+ -
+ name: stats
+ type: binary
+ struct: ndt-stats
+ -
+ name: gc-interval
+ type: u64
+ -
+ name: pad
+ type: pad
+ -
+ name: ndtpa-attrs
+ attributes:
+ -
+ name: ifindex
+ type: u32
+ -
+ name: refcnt
+ type: u32
+ -
+ name: reachable-time
+ type: u64
+ -
+ name: base-reachable-time
+ type: u64
+ -
+ name: retrans-time
+ type: u64
+ -
+ name: gc-staletime
+ type: u64
+ -
+ name: delay-probe-time
+ type: u64
+ -
+ name: queue-len
+ type: u32
+ -
+ name: app-probes
+ type: u32
+ -
+ name: ucast-probes
+ type: u32
+ -
+ name: mcast-probes
+ type: u32
+ -
+ name: anycast-delay
+ type: u64
+ -
+ name: proxy-delay
+ type: u64
+ -
+ name: proxy-qlen
+ type: u32
+ -
+ name: locktime
+ type: u64
+ -
+ name: queue-lenbytes
+ type: u32
+ -
+ name: mcast-reprobes
+ type: u32
+ -
+ name: pad
+ type: pad
+ -
+ name: interval-probe-time-ms
+ type: u64
+
+operations:
+ enum-model: directional
+ list:
+ -
+ name: newneigh
+ doc: Add new neighbour entry
+ fixed-header: ndmsg
+ attribute-set: neighbour-attrs
+ do:
+ request:
+ value: 28
+ attributes: &neighbour-all
+ - dst
+ - lladdr
+ - probes
+ - vlan
+ - port
+ - vni
+ - ifindex
+ - master
+ - protocol
+ - nh-id
+ - flags-ext
+ - fdb-ext-attrs
+ -
+ name: delneigh
+ doc: Remove an existing neighbour entry
+ fixed-header: ndmsg
+ attribute-set: neighbour-attrs
+ do:
+ request:
+ value: 29
+ attributes:
+ - dst
+ - ifindex
+ -
+ name: delneigh-ntf
+ doc: Notify a neighbour deletion
+ value: 29
+ notify: delneigh
+ fixed-header: ndmsg
+ -
+ name: getneigh
+ doc: Get or dump neighbour entries
+ fixed-header: ndmsg
+ attribute-set: neighbour-attrs
+ do:
+ request:
+ value: 30
+ attributes:
+ - dst
+ reply:
+ value: 28
+ attributes: *neighbour-all
+ dump:
+ request:
+ attributes:
+ - ifindex
+ - master
+ reply:
+ attributes: *neighbour-all
+ -
+ name: newneigh-ntf
+ doc: Notify a neighbour creation
+ value: 28
+ notify: getneigh
+ fixed-header: ndmsg
+ -
+ name: getneightbl
+ doc: Get or dump neighbour tables
+ fixed-header: ndtmsg
+ attribute-set: ndt-attrs
+ dump:
+ request:
+ value: 66
+ reply:
+ value: 64
+ attributes:
+ - name
+ - thresh1
+ - thresh2
+ - thresh3
+ - config
+ - parms
+ - stats
+ - gc-interval
+ -
+ name: setneightbl
+ doc: Set neighbour tables
+ fixed-header: ndtmsg
+ attribute-set: ndt-attrs
+ do:
+ request:
+ value: 67
+ attributes:
+ - name
+ - thresh1
+ - thresh2
+ - thresh3
+ - parms
+ - gc-interval
+
+mcast-groups:
+ list:
+ -
+ name: rtnlgrp-neigh
+ value: 3
diff --git a/Documentation/netlink/specs/rt_rule.yaml b/Documentation/netlink/specs/rt_rule.yaml
new file mode 100644
index 000000000000..03a8eef7952e
--- /dev/null
+++ b/Documentation/netlink/specs/rt_rule.yaml
@@ -0,0 +1,242 @@
+# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
+
+name: rt-rule
+protocol: netlink-raw
+protonum: 0
+
+doc:
+ FIB rule management over rtnetlink.
+
+definitions:
+ -
+ name: rtgenmsg
+ type: struct
+ members:
+ -
+ name: family
+ type: u8
+ -
+ name: pad
+ type: pad
+ len: 3
+ -
+ name: fib-rule-hdr
+ type: struct
+ members:
+ -
+ name: family
+ type: u8
+ -
+ name: dst-len
+ type: u8
+ -
+ name: src-len
+ type: u8
+ -
+ name: tos
+ type: u8
+ -
+ name: table
+ type: u8
+ -
+ name: res1
+ type: pad
+ len: 1
+ -
+ name: res2
+ type: pad
+ len: 1
+ -
+ name: action
+ type: u8
+ enum: fr-act
+ -
+ name: flags
+ type: u32
+ -
+ name: fr-act
+ type: enum
+ entries:
+ - unspec
+ - to-tbl
+ - goto
+ - nop
+ - res3
+ - res4
+ - blackhole
+ - unreachable
+ - prohibit
+ -
+ name: fib-rule-port-range
+ type: struct
+ members:
+ -
+ name: start
+ type: u16
+ -
+ name: end
+ type: u16
+ -
+ name: fib-rule-uid-range
+ type: struct
+ members:
+ -
+ name: start
+ type: u32
+ -
+ name: end
+ type: u32
+
+attribute-sets:
+ -
+ name: fib-rule-attrs
+ attributes:
+ -
+ name: dst
+ type: u32
+ -
+ name: src
+ type: u32
+ -
+ name: iifname
+ type: string
+ -
+ name: goto
+ type: u32
+ -
+ name: unused2
+ type: pad
+ -
+ name: priority
+ type: u32
+ -
+ name: unused3
+ type: pad
+ -
+ name: unused4
+ type: pad
+ -
+ name: unused5
+ type: pad
+ -
+ name: fwmark
+ type: u32
+ display-hint: hex
+ -
+ name: flow
+ type: u32
+ -
+ name: tun-id
+ type: u64
+ -
+ name: suppress-ifgroup
+ type: u32
+ -
+ name: suppress-prefixlen
+ type: u32
+ display-hint: hex
+ -
+ name: table
+ type: u32
+ -
+ name: fwmask
+ type: u32
+ display-hint: hex
+ -
+ name: oifname
+ type: string
+ -
+ name: pad
+ type: pad
+ -
+ name: l3mdev
+ type: u8
+ -
+ name: uid-range
+ type: binary
+ struct: fib-rule-uid-range
+ -
+ name: protocol
+ type: u8
+ -
+ name: ip-proto
+ type: u8
+ -
+ name: sport-range
+ type: binary
+ struct: fib-rule-port-range
+ -
+ name: dport-range
+ type: binary
+ struct: fib-rule-port-range
+ -
+ name: dscp
+ type: u8
+
+operations:
+ enum-model: directional
+ fixed-header: fib-rule-hdr
+ list:
+ -
+ name: newrule
+ doc: Add new FIB rule
+ attribute-set: fib-rule-attrs
+ do:
+ request:
+ value: 32
+ attributes: &fib-rule-all
+ - iifname
+ - oifname
+ - priority
+ - fwmark
+ - flow
+ - tun-id
+ - fwmask
+ - table
+ - suppress-prefixlen
+ - suppress-ifgroup
+ - goto
+ - l3mdev
+ - uid-range
+ - protocol
+ - ip-proto
+ - sport-range
+ - dport-range
+ - dscp
+ -
+ name: newrule-ntf
+ doc: Notify a rule creation
+ value: 32
+ notify: newrule
+ -
+ name: delrule
+ doc: Remove an existing FIB rule
+ attribute-set: fib-rule-attrs
+ do:
+ request:
+ value: 33
+ attributes: *fib-rule-all
+ -
+ name: delrule-ntf
+ doc: Notify a rule deletion
+ value: 33
+ notify: delrule
+ -
+ name: getrule
+ doc: Dump all FIB rules
+ attribute-set: fib-rule-attrs
+ dump:
+ request:
+ value: 34
+ reply:
+ value: 32
+ attributes: *fib-rule-all
+
+mcast-groups:
+ list:
+ -
+ name: rtnlgrp-ipv4-rule
+ value: 8
+ -
+ name: rtnlgrp-ipv6-rule
+ value: 19
diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml
index b02d59a0349c..aacccea5dfe4 100644
--- a/Documentation/netlink/specs/tc.yaml
+++ b/Documentation/netlink/specs/tc.yaml
@@ -622,7 +622,7 @@ definitions:
-
name: max-P
type: u32
- doc: probabilty, high resolution
+ doc: probability, high resolution
-
name: stats
type: binary
diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
index 1e196cb9ce25..af7db0e91f6b 100644
--- a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
+++ b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
@@ -14,6 +14,7 @@ Contents
- `Basic packet flow`_
- `Devlink health reporters`_
- `Quality of service`_
+- `RVU representors`_
Overview
========
@@ -340,3 +341,93 @@ Setup HTB offload
# tc class add dev <interface> parent 1: classid 1:2 htb rate 10Gbit prio 2 quantum 188416
# tc class add dev <interface> parent 1: classid 1:3 htb rate 10Gbit prio 2 quantum 32768
+
+
+RVU Representors
+================
+
+RVU representor driver adds support for creation of representor devices for
+RVU PFs' VFs in the system. Representor devices are created when user enables
+the switchdev mode.
+Switchdev mode can be enabled either before or after setting up SRIOV numVFs.
+All representor devices share a single NIXLF but each has a dedicated Rx/Tx
+queues. RVU PF representor driver registers a separate netdev for each
+Rx/Tx queue pair.
+
+Current HW does not support built-in switch which can do L2 learning and
+forwarding packets between representee and representor. Hence, packet path
+between representee and it's representor is achieved by setting up appropriate
+NPC MCAM filters.
+Transmit packets matching these filters will be loopbacked through hardware
+loopback channel/interface (i.e, instead of sending them out of MAC interface).
+Which will again match the installed filters and will be forwarded.
+This way representee => representor and representor => representee packet
+path is achieved. These rules get installed when representors are created
+and gets active/deactivate based on the representor/representee interface state.
+
+Usage example:
+
+ - Change device to switchdev mode::
+
+ # devlink dev eswitch set pci/0002:1c:00.0 mode switchdev
+
+ - List of representor devices on the system::
+
+ # ip link show
+ Rpf1vf0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether f6:43:83:ee:26:21 brd ff:ff:ff:ff:ff:ff
+ Rpf1vf1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 12:b2:54:0e:24:54 brd ff:ff:ff:ff:ff:ff
+ Rpf1vf2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 4a:12:c4:4c:32:62 brd ff:ff:ff:ff:ff:ff
+ Rpf1vf3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether ca:cb:68:0e:e2:6e brd ff:ff:ff:ff:ff:ff
+ Rpf2vf0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 06:cc:ad:b4:f0:93 brd ff:ff:ff:ff:ff:ff
+
+
+To delete the representors devices from the system. Change the device to legacy mode.
+
+ - Change device to legacy mode::
+
+ # devlink dev eswitch set pci/0002:1c:00.0 mode legacy
+
+RVU representors can be managed using devlink ports
+(see :ref:`Documentation/networking/devlink/devlink-port.rst <devlink_port>`) interface.
+
+ - Show devlink ports of representors::
+
+ # devlink port
+ pci/0002:1c:00.0/0: type eth netdev Rpf1vf0 flavour physical port 0 splittable false
+ pci/0002:1c:00.0/1: type eth netdev Rpf1vf1 flavour pcivf controller 0 pfnum 1 vfnum 1 external false splittable false
+ pci/0002:1c:00.0/2: type eth netdev Rpf1vf2 flavour pcivf controller 0 pfnum 1 vfnum 2 external false splittable false
+ pci/0002:1c:00.0/3: type eth netdev Rpf1vf3 flavour pcivf controller 0 pfnum 1 vfnum 3 external false splittable false
+
+Function attributes
+===================
+
+The RVU representor support function attributes for representors.
+Port function configuration of the representors are supported through devlink eswitch port.
+
+MAC address setup
+-----------------
+
+RVU representor driver support devlink port function attr mechanism to setup MAC
+address. (refer to Documentation/networking/devlink/devlink-port.rst)
+
+ - To setup MAC address for port 2::
+
+ # devlink port function set pci/0002:1c:00.0/2 hw_addr 5c:a1:1b:5e:43:11
+ # devlink port show pci/0002:1c:00.0/2
+ pci/0002:1c:00.0/2: type eth netdev Rpf1vf2 flavour pcivf controller 0 pfnum 1 vfnum 2 external false splittable false
+ function:
+ hw_addr 5c:a1:1b:5e:43:11
+
+
+TC offload
+==========
+
+The rvu representor driver implements support for offloading tc rules using port representors.
+
+ - Drop packets with vlan id 3::
+
+ # tc filter add dev Rpf1vf0 protocol 802.1Q parent ffff: flower vlan_id 3 vlan_ethtype ipv4 skip_sw action drop
+
+ - Redirect packets with vlan id 5 and IPv4 packets to eth1, after stripping vlan header.::
+
+ # tc filter add dev Rpf1vf0 ingress protocol 802.1Q flower vlan_id 5 vlan_ethtype ipv4 skip_sw action vlan pop action mirred ingress redirect dev eth1
diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst
index f346f5f85f15..e07de7700dfc 100644
--- a/Documentation/networking/device_drivers/wwan/t7xx.rst
+++ b/Documentation/networking/device_drivers/wwan/t7xx.rst
@@ -7,12 +7,13 @@
============================================
t7xx driver for MTK PCIe based T700 5G modem
============================================
-The t7xx driver is a WWAN PCIe host driver developed for linux or Chrome OS platforms
-for data exchange over PCIe interface between Host platform & MediaTek's T700 5G modem.
-The driver exposes an interface conforming to the MBIM protocol [1]. Any front end
-application (e.g. Modem Manager) could easily manage the MBIM interface to enable
-data communication towards WWAN. The driver also provides an interface to interact
-with the MediaTek's modem via AT commands.
+The t7xx driver is a WWAN PCIe host driver developed for linux or Chrome OS
+platforms for data exchange over PCIe interface between Host platform &
+MediaTek's T700 5G modem.
+The driver exposes an interface conforming to the MBIM protocol [1]. Any front
+end application (e.g. Modem Manager) could easily manage the MBIM interface to
+enable data communication towards WWAN. The driver also provides an interface
+to interact with the MediaTek's modem via AT commands.
Basic usage
===========
@@ -45,8 +46,8 @@ The driver provides sysfs interfaces to userspace.
t7xx_mode
---------
-The sysfs interface provides userspace with access to the device mode, this interface
-supports read and write operations.
+The sysfs interface provides userspace with access to the device mode, this
+interface supports read and write operations.
Device mode:
@@ -67,6 +68,28 @@ Write from userspace to set the device mode.
::
$ echo fastboot_switching > /sys/bus/pci/devices/${bdf}/t7xx_mode
+t7xx_debug_ports
+----------------
+The sysfs interface provides userspace with access to enable/disable the debug
+ports, this interface supports read and write operations.
+
+Debug port status:
+
+- ``1`` represents enable debug ports
+- ``0`` represents disable debug ports
+
+Currently supported debug ports (ADB/MIPC).
+
+Read from userspace to get the current debug ports status.
+
+::
+ $ cat /sys/bus/pci/devices/${bdf}/t7xx_debug_ports
+
+Write from userspace to set the debug ports status.
+
+::
+ $ echo 1 > /sys/bus/pci/devices/${bdf}/t7xx_debug_ports
+
Management application development
==================================
The driver and userspace interfaces are described below. The MBIM protocol is
@@ -139,6 +162,25 @@ Please note that driver needs to be reloaded to export /dev/wwan0fastboot0
port, because device needs a cold reset after enter ``fastboot_switching``
mode.
+ADB port userspace ABI
+----------------------
+
+/dev/wwan0adb0 character device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The driver exposes a ADB protocol interface by implementing ADB WWAN Port.
+The userspace end of the ADB channel pipe is a /dev/wwan0adb0 character device.
+Application shall use this interface for ADB protocol communication.
+
+MIPC port userspace ABI
+-----------------------
+
+/dev/wwan0mipc0 character device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The driver exposes a diagnostic interface by implementing MIPC (Modem
+Information Process Center) WWAN Port. The userspace end of the MIPC channel
+pipe is a /dev/wwan0mipc0 character device.
+Application shall use this interface for MTK modem diagnostic communication.
+
The MediaTek's T700 modem supports the 3GPP TS 27.007 [4] specification.
References
@@ -164,3 +206,9 @@ speak the Mobile Interface Broadband Model (MBIM) protocol"*
[5] *fastboot "a mechanism for communicating with bootloaders"*
- https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md
+
+[6] *ADB (Android Debug Bridge) "a mechanism to keep track of Android devices
+and emulators instances connected to or running on a given host developer
+machine with ADB protocol"*
+
+- https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/README.md
diff --git a/Documentation/networking/devlink/octeontx2.rst b/Documentation/networking/devlink/octeontx2.rst
index d33a90dd44bf..84206537aedb 100644
--- a/Documentation/networking/devlink/octeontx2.rst
+++ b/Documentation/networking/devlink/octeontx2.rst
@@ -40,6 +40,27 @@ The ``octeontx2 AF`` driver implements the following driver-specific parameters.
- runtime
- Use to set the quantum which hardware uses for scheduling among transmit queues.
Hardware uses weighted DWRR algorithm to schedule among all transmit queues.
+ * - ``npc_mcam_high_zone_percent``
+ - u8
+ - runtime
+ - Use to set the number of high priority zone entries in NPC MCAM that can be allocated
+ by a user, out of the three priority zone categories high, mid and low.
+ * - ``npc_def_rule_cntr``
+ - bool
+ - runtime
+ - Use to enable or disable hit counters for the default rules in NPC MCAM.
+ Its not guaranteed that counters gets enabled and mapped to all the default rules,
+ since the counters are scarce and driver follows a best effort approach.
+ The default rule serves as the primary packet steering rule for a specific PF or VF,
+ based on its DMAC address which is installed by AF driver as part of its initialization.
+ Sample command to read hit counters for default rule from debugfs is as follows,
+ cat /sys/kernel/debug/cn10k/npc/mcam_rules
+ * - ``nix_maxlf``
+ - u16
+ - runtime
+ - Use to set the maximum number of LFs in NIX hardware block. This would be useful
+ to increase the availability of default resources allocated to enabled LFs like
+ MCAM entries for example.
The ``octeontx2 PF`` driver implements the following driver-specific parameters.
diff --git a/Documentation/networking/devmem.rst b/Documentation/networking/devmem.rst
index a55bf21f671c..d95363645331 100644
--- a/Documentation/networking/devmem.rst
+++ b/Documentation/networking/devmem.rst
@@ -225,6 +225,15 @@ The user must ensure the tokens are returned to the kernel in a timely manner.
Failure to do so will exhaust the limited dmabuf that is bound to the RX queue
and will lead to packet drops.
+The user must pass no more than 128 tokens, with no more than 1024 total frags
+among the token->token_count across all the tokens. If the user provides more
+than 1024 frags, the kernel will free up to 1024 frags and return early.
+
+The kernel returns the number of actual frags freed. The number of frags freed
+can be less than the tokens provided by the user in case of:
+
+(a) an internal kernel leak bug.
+(b) the user passed more than 1024 frags.
Implementation & Caveats
========================
diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst
index 295563e91082..b25926071ece 100644
--- a/Documentation/networking/ethtool-netlink.rst
+++ b/Documentation/networking/ethtool-netlink.rst
@@ -236,6 +236,7 @@ Userspace to kernel:
``ETHTOOL_MSG_MM_GET`` get MAC merge layer state
``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
+ ``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information
===================================== =================================
Kernel to userspace:
@@ -283,6 +284,8 @@ Kernel to userspace:
``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters
``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status
``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
+ ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information
+ ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
diff --git a/Documentation/networking/j1939.rst b/Documentation/networking/j1939.rst
index e4bd7aa1f5aa..544bad175aae 100644
--- a/Documentation/networking/j1939.rst
+++ b/Documentation/networking/j1939.rst
@@ -121,7 +121,7 @@ format, the Group Extension is set in the PS-field.
On the other hand, when using PDU1 format, the PS-field contains a so-called
Destination Address, which is _not_ part of the PGN. When communicating a PGN
-from user space to kernel (or vice versa) and PDU2 format is used, the PS-field
+from user space to kernel (or vice versa) and PDU1 format is used, the PS-field
of the PGN shall be set to zero. The Destination Address shall be set
elsewhere.
diff --git a/Documentation/networking/napi.rst b/Documentation/networking/napi.rst
index dfa5d549be9c..02720dd71a76 100644
--- a/Documentation/networking/napi.rst
+++ b/Documentation/networking/napi.rst
@@ -192,6 +192,33 @@ is reused to control the delay of the timer, while
``napi_defer_hard_irqs`` controls the number of consecutive empty polls
before NAPI gives up and goes back to using hardware IRQs.
+The above parameters can also be set on a per-NAPI basis using netlink via
+netdev-genl. When used with netlink and configured on a per-NAPI basis, the
+parameters mentioned above use hyphens instead of underscores:
+``gro-flush-timeout`` and ``napi-defer-hard-irqs``.
+
+Per-NAPI configuration can be done programmatically in a user application
+or by using a script included in the kernel source tree:
+``tools/net/ynl/cli.py``.
+
+For example, using the script:
+
+.. code-block:: bash
+
+ $ kernel-source/tools/net/ynl/cli.py \
+ --spec Documentation/netlink/specs/netdev.yaml \
+ --do napi-set \
+ --json='{"id": 345,
+ "defer-hard-irqs": 111,
+ "gro-flush-timeout": 11111}'
+
+Similarly, the parameter ``irq-suspend-timeout`` can be set using netlink
+via netdev-genl. There is no global sysfs parameter for this value.
+
+``irq-suspend-timeout`` is used to determine how long an application can
+completely suspend IRQs. It is used in combination with SO_PREFER_BUSY_POLL,
+which can be set on a per-epoll context basis with ``EPIOCSPARAMS`` ioctl.
+
.. _poll:
Busy polling
@@ -207,6 +234,46 @@ selected sockets or using the global ``net.core.busy_poll`` and
``net.core.busy_read`` sysctls. An io_uring API for NAPI busy polling
also exists.
+epoll-based busy polling
+------------------------
+
+It is possible to trigger packet processing directly from calls to
+``epoll_wait``. In order to use this feature, a user application must ensure
+all file descriptors which are added to an epoll context have the same NAPI ID.
+
+If the application uses a dedicated acceptor thread, the application can obtain
+the NAPI ID of the incoming connection using SO_INCOMING_NAPI_ID and then
+distribute that file descriptor to a worker thread. The worker thread would add
+the file descriptor to its epoll context. This would ensure each worker thread
+has an epoll context with FDs that have the same NAPI ID.
+
+Alternatively, if the application uses SO_REUSEPORT, a bpf or ebpf program can
+be inserted to distribute incoming connections to threads such that each thread
+is only given incoming connections with the same NAPI ID. Care must be taken to
+carefully handle cases where a system may have multiple NICs.
+
+In order to enable busy polling, there are two choices:
+
+1. ``/proc/sys/net/core/busy_poll`` can be set with a time in useconds to busy
+ loop waiting for events. This is a system-wide setting and will cause all
+ epoll-based applications to busy poll when they call epoll_wait. This may
+ not be desirable as many applications may not have the need to busy poll.
+
+2. Applications using recent kernels can issue an ioctl on the epoll context
+ file descriptor to set (``EPIOCSPARAMS``) or get (``EPIOCGPARAMS``) ``struct
+ epoll_params``:, which user programs can define as follows:
+
+.. code-block:: c
+
+ struct epoll_params {
+ uint32_t busy_poll_usecs;
+ uint16_t busy_poll_budget;
+ uint8_t prefer_busy_poll;
+
+ /* pad the struct to a multiple of 64bits */
+ uint8_t __pad;
+ };
+
IRQ mitigation
---------------
@@ -222,12 +289,111 @@ Such applications can pledge to the kernel that they will perform a busy
polling operation periodically, and the driver should keep the device IRQs
permanently masked. This mode is enabled by using the ``SO_PREFER_BUSY_POLL``
socket option. To avoid system misbehavior the pledge is revoked
-if ``gro_flush_timeout`` passes without any busy poll call.
+if ``gro_flush_timeout`` passes without any busy poll call. For epoll-based
+busy polling applications, the ``prefer_busy_poll`` field of ``struct
+epoll_params`` can be set to 1 and the ``EPIOCSPARAMS`` ioctl can be issued to
+enable this mode. See the above section for more details.
The NAPI budget for busy polling is lower than the default (which makes
sense given the low latency intention of normal busy polling). This is
not the case with IRQ mitigation, however, so the budget can be adjusted
-with the ``SO_BUSY_POLL_BUDGET`` socket option.
+with the ``SO_BUSY_POLL_BUDGET`` socket option. For epoll-based busy polling
+applications, the ``busy_poll_budget`` field can be adjusted to the desired value
+in ``struct epoll_params`` and set on a specific epoll context using the ``EPIOCSPARAMS``
+ioctl. See the above section for more details.
+
+It is important to note that choosing a large value for ``gro_flush_timeout``
+will defer IRQs to allow for better batch processing, but will induce latency
+when the system is not fully loaded. Choosing a small value for
+``gro_flush_timeout`` can cause interference of the user application which is
+attempting to busy poll by device IRQs and softirq processing. This value
+should be chosen carefully with these tradeoffs in mind. epoll-based busy
+polling applications may be able to mitigate how much user processing happens
+by choosing an appropriate value for ``maxevents``.
+
+Users may want to consider an alternate approach, IRQ suspension, to help deal
+with these tradeoffs.
+
+IRQ suspension
+--------------
+
+IRQ suspension is a mechanism wherein device IRQs are masked while epoll
+triggers NAPI packet processing.
+
+While application calls to epoll_wait successfully retrieve events, the kernel will
+defer the IRQ suspension timer. If the kernel does not retrieve any events
+while busy polling (for example, because network traffic levels subsided), IRQ
+suspension is disabled and the IRQ mitigation strategies described above are
+engaged.
+
+This allows users to balance CPU consumption with network processing
+efficiency.
+
+To use this mechanism:
+
+ 1. The per-NAPI config parameter ``irq-suspend-timeout`` should be set to the
+ maximum time (in nanoseconds) the application can have its IRQs
+ suspended. This is done using netlink, as described above. This timeout
+ serves as a safety mechanism to restart IRQ driver interrupt processing if
+ the application has stalled. This value should be chosen so that it covers
+ the amount of time the user application needs to process data from its
+ call to epoll_wait, noting that applications can control how much data
+ they retrieve by setting ``max_events`` when calling epoll_wait.
+
+ 2. The sysfs parameter or per-NAPI config parameters ``gro_flush_timeout``
+ and ``napi_defer_hard_irqs`` can be set to low values. They will be used
+ to defer IRQs after busy poll has found no data.
+
+ 3. The ``prefer_busy_poll`` flag must be set to true. This can be done using
+ the ``EPIOCSPARAMS`` ioctl as described above.
+
+ 4. The application uses epoll as described above to trigger NAPI packet
+ processing.
+
+As mentioned above, as long as subsequent calls to epoll_wait return events to
+userland, the ``irq-suspend-timeout`` is deferred and IRQs are disabled. This
+allows the application to process data without interference.
+
+Once a call to epoll_wait results in no events being found, IRQ suspension is
+automatically disabled and the ``gro_flush_timeout`` and
+``napi_defer_hard_irqs`` mitigation mechanisms take over.
+
+It is expected that ``irq-suspend-timeout`` will be set to a value much larger
+than ``gro_flush_timeout`` as ``irq-suspend-timeout`` should suspend IRQs for
+the duration of one userland processing cycle.
+
+While it is not stricly necessary to use ``napi_defer_hard_irqs`` and
+``gro_flush_timeout`` to use IRQ suspension, their use is strongly
+recommended.
+
+IRQ suspension causes the system to alternate between polling mode and
+irq-driven packet delivery. During busy periods, ``irq-suspend-timeout``
+overrides ``gro_flush_timeout`` and keeps the system busy polling, but when
+epoll finds no events, the setting of ``gro_flush_timeout`` and
+``napi_defer_hard_irqs`` determine the next step.
+
+There are essentially three possible loops for network processing and
+packet delivery:
+
+1) hardirq -> softirq -> napi poll; basic interrupt delivery
+2) timer -> softirq -> napi poll; deferred irq processing
+3) epoll -> busy-poll -> napi poll; busy looping
+
+Loop 2 can take control from Loop 1, if ``gro_flush_timeout`` and
+``napi_defer_hard_irqs`` are set.
+
+If ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` are set, Loops 2
+and 3 "wrestle" with each other for control.
+
+During busy periods, ``irq-suspend-timeout`` is used as timer in Loop 2,
+which essentially tilts network processing in favour of Loop 3.
+
+If ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` are not set, Loop 3
+cannot take control from Loop 1.
+
+Therefore, setting ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` is
+the recommended usage, because otherwise setting ``irq-suspend-timeout``
+might not have any discernible effect.
.. _threaded:
diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
index db6192b2bb50..15e31ece675f 100644
--- a/Documentation/networking/net_cachelines/net_device.rst
+++ b/Documentation/networking/net_cachelines/net_device.rst
@@ -52,7 +52,6 @@ struct net_device_core_stats* core_stats
atomic_t carrier_up_count
atomic_t carrier_down_count
struct iw_handler_def* wireless_handlers
-struct iw_public_data* wireless_data
struct ethtool_ops* ethtool_ops
struct l3mdev_ops* l3mdev_ops
struct ndisc_ops* ndisc_ops
@@ -189,4 +188,5 @@ u64 max_pacing_offload_horizon
struct_napi_config* napi_config
unsigned_long gro_flush_timeout
u32 napi_defer_hard_irqs
+struct hlist_head neighbours[2]
=================================== =========================== =================== =================== ===================================================================================
diff --git a/Documentation/networking/net_dim.rst b/Documentation/networking/net_dim.rst
index 8908fd7b0a8d..4377998e6826 100644
--- a/Documentation/networking/net_dim.rst
+++ b/Documentation/networking/net_dim.rst
@@ -156,7 +156,7 @@ usage is not complete but it should make the outline of the usage clear.
my_entity->bytes,
&dim_sample);
/* Call net DIM */
- net_dim(&my_entity->dim, dim_sample);
+ net_dim(&my_entity->dim, &dim_sample);
...
}
diff --git a/Documentation/networking/packet_mmap.rst b/Documentation/networking/packet_mmap.rst
index dca15d15feaf..02370786e77b 100644
--- a/Documentation/networking/packet_mmap.rst
+++ b/Documentation/networking/packet_mmap.rst
@@ -16,7 +16,7 @@ ii) transmit network traffic, or any other that needs raw
Howto can be found at:
- https://sites.google.com/site/packetmmap/
+ https://web.archive.org/web/20220404160947/https://sites.google.com/site/packetmmap/
Please send your comments to
- Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
@@ -166,7 +166,8 @@ As capture, each frame contains two parts::
/* bind socket to eth0 */
bind(this->socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_ll));
- A complete tutorial is available at: https://sites.google.com/site/packetmmap/
+ A complete tutorial is available at:
+ https://web.archive.org/web/20220404160947/https://sites.google.com/site/packetmmap/
By default, the user should put data at::
diff --git a/Documentation/rust/arch-support.rst b/Documentation/rust/arch-support.rst
index 750ff371570a..54be7ddf3e57 100644
--- a/Documentation/rust/arch-support.rst
+++ b/Documentation/rust/arch-support.rst
@@ -17,7 +17,7 @@ Architecture Level of support Constraints
============= ================ ==============================================
``arm64`` Maintained Little Endian only.
``loongarch`` Maintained \-
-``riscv`` Maintained ``riscv64`` only.
+``riscv`` Maintained ``riscv64`` and LLVM/Clang only.
``um`` Maintained \-
``x86`` Maintained ``x86_64`` only.
============= ================ ==============================================
diff --git a/Documentation/security/landlock.rst b/Documentation/security/landlock.rst
index 36f26501fd15..59ecdb1c0d4d 100644
--- a/Documentation/security/landlock.rst
+++ b/Documentation/security/landlock.rst
@@ -11,18 +11,18 @@ Landlock LSM: kernel documentation
Landlock's goal is to create scoped access-control (i.e. sandboxing). To
harden a whole system, this feature should be available to any process,
-including unprivileged ones. Because such process may be compromised or
+including unprivileged ones. Because such a process may be compromised or
backdoored (i.e. untrusted), Landlock's features must be safe to use from the
kernel and other processes point of view. Landlock's interface must therefore
expose a minimal attack surface.
Landlock is designed to be usable by unprivileged processes while following the
system security policy enforced by other access control mechanisms (e.g. DAC,
-LSM). Indeed, a Landlock rule shall not interfere with other access-controls
-enforced on the system, only add more restrictions.
+LSM). A Landlock rule shall not interfere with other access-controls enforced
+on the system, only add more restrictions.
Any user can enforce Landlock rulesets on their processes. They are merged and
-evaluated according to the inherited ones in a way that ensures that only more
+evaluated against inherited rulesets in a way that ensures that only more
constraints can be added.
User space documentation can be found here:
@@ -43,7 +43,7 @@ Guiding principles for safe access controls
only impact the processes requesting them.
* Resources (e.g. file descriptors) directly obtained from the kernel by a
sandboxed process shall retain their scoped accesses (at the time of resource
- acquisition) whatever process use them.
+ acquisition) whatever process uses them.
Cf. `File descriptor access rights`_.
Design choices
@@ -71,7 +71,7 @@ the same results, when they are executed under the same Landlock domain.
Taking the ``LANDLOCK_ACCESS_FS_TRUNCATE`` right as an example, it may be
allowed to open a file for writing without being allowed to
:manpage:`ftruncate` the resulting file descriptor if the related file
-hierarchy doesn't grant such access right. The following sequences of
+hierarchy doesn't grant that access right. The following sequences of
operations have the same semantic and should then have the same result:
* ``truncate(path);``
@@ -81,7 +81,7 @@ Similarly to file access modes (e.g. ``O_RDWR``), Landlock access rights
attached to file descriptors are retained even if they are passed between
processes (e.g. through a Unix domain socket). Such access rights will then be
enforced even if the receiving process is not sandboxed by Landlock. Indeed,
-this is required to keep a consistent access control over the whole system, and
+this is required to keep access controls consistent over the whole system, and
this avoids unattended bypasses through file descriptor passing (i.e. confused
deputy attack).
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index c8d3e46badc5..d639c61cb472 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -8,13 +8,13 @@ Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
-:Date: September 2024
+:Date: October 2024
-The goal of Landlock is to enable to restrict ambient rights (e.g. global
+The goal of Landlock is to enable restriction of ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock
-is a stackable LSM, it makes possible to create safe security sandboxes as new
-security layers in addition to the existing system-wide access-controls. This
-kind of sandbox is expected to help mitigate the security impact of bugs or
+is a stackable LSM, it makes it possible to create safe security sandboxes as
+new security layers in addition to the existing system-wide access-controls.
+This kind of sandbox is expected to help mitigate the security impact of bugs or
unexpected/malicious behaviors in user space applications. Landlock empowers
any process, including unprivileged ones, to securely restrict themselves.
@@ -86,8 +86,8 @@ to be explicit about the denied-by-default access rights.
LANDLOCK_SCOPE_SIGNAL,
};
-Because we may not know on which kernel version an application will be
-executed, it is safer to follow a best-effort security approach. Indeed, we
+Because we may not know which kernel version an application will be executed
+on, it is safer to follow a best-effort security approach. Indeed, we
should try to protect users as much as possible whatever the kernel they are
using.
@@ -129,7 +129,7 @@ version, and only use the available subset of access rights:
LANDLOCK_SCOPE_SIGNAL);
}
-This enables to create an inclusive ruleset that will contain our rules.
+This enables the creation of an inclusive ruleset that will contain our rules.
.. code-block:: c
@@ -219,42 +219,41 @@ If the ``landlock_restrict_self`` system call succeeds, the current thread is
now restricted and this policy will be enforced on all its subsequently created
children as well. Once a thread is landlocked, there is no way to remove its
security policy; only adding more restrictions is allowed. These threads are
-now in a new Landlock domain, merge of their parent one (if any) with the new
-ruleset.
+now in a new Landlock domain, which is a merger of their parent one (if any)
+with the new ruleset.
Full working code can be found in `samples/landlock/sandboxer.c`_.
Good practices
--------------
-It is recommended setting access rights to file hierarchy leaves as much as
+It is recommended to set access rights to file hierarchy leaves as much as
possible. For instance, it is better to be able to have ``~/doc/`` as a
read-only hierarchy and ``~/tmp/`` as a read-write hierarchy, compared to
``~/`` as a read-only hierarchy and ``~/tmp/`` as a read-write hierarchy.
Following this good practice leads to self-sufficient hierarchies that do not
depend on their location (i.e. parent directories). This is particularly
relevant when we want to allow linking or renaming. Indeed, having consistent
-access rights per directory enables to change the location of such directory
+access rights per directory enables changing the location of such directories
without relying on the destination directory access rights (except those that
are required for this operation, see ``LANDLOCK_ACCESS_FS_REFER``
documentation).
Having self-sufficient hierarchies also helps to tighten the required access
rights to the minimal set of data. This also helps avoid sinkhole directories,
-i.e. directories where data can be linked to but not linked from. However,
+i.e. directories where data can be linked to but not linked from. However,
this depends on data organization, which might not be controlled by developers.
In this case, granting read-write access to ``~/tmp/``, instead of write-only
-access, would potentially allow to move ``~/tmp/`` to a non-readable directory
+access, would potentially allow moving ``~/tmp/`` to a non-readable directory
and still keep the ability to list the content of ``~/tmp/``.
Layers of file path access rights
---------------------------------
Each time a thread enforces a ruleset on itself, it updates its Landlock domain
-with a new layer of policy. Indeed, this complementary policy is stacked with
-the potentially other rulesets already restricting this thread. A sandboxed
-thread can then safely add more constraints to itself with a new enforced
-ruleset.
+with a new layer of policy. This complementary policy is stacked with any
+other rulesets potentially already restricting this thread. A sandboxed thread
+can then safely add more constraints to itself with a new enforced ruleset.
One policy layer grants access to a file path if at least one of its rules
encountered on the path grants the access. A sandboxed thread can only access
@@ -265,7 +264,7 @@ etc.).
Bind mounts and OverlayFS
-------------------------
-Landlock enables to restrict access to file hierarchies, which means that these
+Landlock enables restricting access to file hierarchies, which means that these
access rights can be propagated with bind mounts (cf.
Documentation/filesystems/sharedsubtree.rst) but not with
Documentation/filesystems/overlayfs.rst.
@@ -278,21 +277,21 @@ access to multiple file hierarchies at the same time, whether these hierarchies
are the result of bind mounts or not.
An OverlayFS mount point consists of upper and lower layers. These layers are
-combined in a merge directory, result of the mount point. This merge hierarchy
-may include files from the upper and lower layers, but modifications performed
-on the merge hierarchy only reflects on the upper layer. From a Landlock
-policy point of view, each OverlayFS layers and merge hierarchies are
-standalone and contains their own set of files and directories, which is
-different from bind mounts. A policy restricting an OverlayFS layer will not
-restrict the resulted merged hierarchy, and vice versa. Landlock users should
-then only think about file hierarchies they want to allow access to, regardless
-of the underlying filesystem.
+combined in a merge directory, and that merged directory becomes available at
+the mount point. This merge hierarchy may include files from the upper and
+lower layers, but modifications performed on the merge hierarchy only reflect
+on the upper layer. From a Landlock policy point of view, all OverlayFS layers
+and merge hierarchies are standalone and each contains their own set of files
+and directories, which is different from bind mounts. A policy restricting an
+OverlayFS layer will not restrict the resulted merged hierarchy, and vice versa.
+Landlock users should then only think about file hierarchies they want to allow
+access to, regardless of the underlying filesystem.
Inheritance
-----------
Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain
-restrictions from its parent. This is similar to the seccomp inheritance (cf.
+restrictions from its parent. This is similar to seccomp inheritance (cf.
Documentation/userspace-api/seccomp_filter.rst) or any other LSM dealing with
task's :manpage:`credentials(7)`. For instance, one process's thread may apply
Landlock rules to itself, but they will not be automatically applied to other
@@ -311,8 +310,8 @@ Ptrace restrictions
A sandboxed process has less privileges than a non-sandboxed process and must
then be subject to additional restrictions when manipulating another process.
To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target
-process, a sandboxed process should have a subset of the target process rules,
-which means the tracee must be in a sub-domain of the tracer.
+process, a sandboxed process should have a superset of the target process's
+access rights, which means the tracee must be in a sub-domain of the tracer.
IPC scoping
-----------
@@ -322,7 +321,7 @@ interactions between sandboxes. Each Landlock domain can be explicitly scoped
for a set of actions by specifying it on a ruleset. For example, if a
sandboxed process should not be able to :manpage:`connect(2)` to a
non-sandboxed process through abstract :manpage:`unix(7)` sockets, we can
-specify such restriction with ``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET``.
+specify such a restriction with ``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET``.
Moreover, if a sandboxed process should not be able to send a signal to a
non-sandboxed process, we can specify this restriction with
``LANDLOCK_SCOPE_SIGNAL``.
@@ -394,7 +393,7 @@ Backward and forward compatibility
Landlock is designed to be compatible with past and future versions of the
kernel. This is achieved thanks to the system call attributes and the
associated bitflags, particularly the ruleset's ``handled_access_fs``. Making
-handled access right explicit enables the kernel and user space to have a clear
+handled access rights explicit enables the kernel and user space to have a clear
contract with each other. This is required to make sure sandboxing will not
get stricter with a system update, which could break applications.
@@ -563,33 +562,34 @@ always allowed when using a kernel that only supports the first or second ABI.
Starting with the Landlock ABI version 3, it is now possible to securely control
truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right.
-Network support (ABI < 4)
--------------------------
+TCP bind and connect (ABI < 4)
+------------------------------
Starting with the Landlock ABI version 4, it is now possible to restrict TCP
bind and connect actions to only a set of allowed ports thanks to the new
``LANDLOCK_ACCESS_NET_BIND_TCP`` and ``LANDLOCK_ACCESS_NET_CONNECT_TCP``
access rights.
-IOCTL (ABI < 5)
----------------
+Device IOCTL (ABI < 5)
+----------------------
IOCTL operations could not be denied before the fifth Landlock ABI, so
:manpage:`ioctl(2)` is always allowed when using a kernel that only supports an
earlier ABI.
Starting with the Landlock ABI version 5, it is possible to restrict the use of
-:manpage:`ioctl(2)` using the new ``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right.
+:manpage:`ioctl(2)` on character and block devices using the new
+``LANDLOCK_ACCESS_FS_IOCTL_DEV`` right.
-Abstract UNIX socket scoping (ABI < 6)
---------------------------------------
+Abstract UNIX socket (ABI < 6)
+------------------------------
Starting with the Landlock ABI version 6, it is possible to restrict
connections to an abstract :manpage:`unix(7)` socket by setting
``LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET`` to the ``scoped`` ruleset attribute.
-Signal scoping (ABI < 6)
-------------------------
+Signal (ABI < 6)
+----------------
Starting with the Landlock ABI version 6, it is possible to restrict
:manpage:`signal(7)` sending by setting ``LANDLOCK_SCOPE_SIGNAL`` to the
@@ -605,9 +605,9 @@ Build time configuration
Landlock was first introduced in Linux 5.13 but it must be configured at build
time with ``CONFIG_SECURITY_LANDLOCK=y``. Landlock must also be enabled at boot
-time as the other security modules. The list of security modules enabled by
+time like other security modules. The list of security modules enabled by
default is set with ``CONFIG_LSM``. The kernel configuration should then
-contains ``CONFIG_LSM=landlock,[...]`` with ``[...]`` as the list of other
+contain ``CONFIG_LSM=landlock,[...]`` with ``[...]`` as the list of other
potentially useful security modules for the running system (see the
``CONFIG_LSM`` help).
@@ -669,7 +669,7 @@ Questions and answers
What about user space sandbox managers?
---------------------------------------
-Using user space process to enforce restrictions on kernel resources can lead
+Using user space processes to enforce restrictions on kernel resources can lead
to race conditions or inconsistent evaluations (i.e. `Incorrect mirroring of
the OS code and state
<https://www.ndss-symposium.org/ndss2003/traps-and-pitfalls-practical-problems-system-call-interposition-based-security-tools/>`_).
diff --git a/Documentation/userspace-api/mseal.rst b/Documentation/userspace-api/mseal.rst
index 4132eec995a3..41102f74c5e2 100644
--- a/Documentation/userspace-api/mseal.rst
+++ b/Documentation/userspace-api/mseal.rst
@@ -23,177 +23,166 @@ applications can additionally seal security critical data at runtime.
A similar feature already exists in the XNU kernel with the
VM_FLAGS_PERMANENT flag [1] and on OpenBSD with the mimmutable syscall [2].
-User API
-========
-mseal()
------------
-The mseal() syscall has the following signature:
-
-``int mseal(void addr, size_t len, unsigned long flags)``
-
-**addr/len**: virtual memory address range.
-
-The address range set by ``addr``/``len`` must meet:
- - The start address must be in an allocated VMA.
- - The start address must be page aligned.
- - The end address (``addr`` + ``len``) must be in an allocated VMA.
- - no gap (unallocated memory) between start and end address.
-
-The ``len`` will be paged aligned implicitly by the kernel.
-
-**flags**: reserved for future use.
-
-**return values**:
-
-- ``0``: Success.
-
-- ``-EINVAL``:
- - Invalid input ``flags``.
- - The start address (``addr``) is not page aligned.
- - Address range (``addr`` + ``len``) overflow.
-
-- ``-ENOMEM``:
- - The start address (``addr``) is not allocated.
- - The end address (``addr`` + ``len``) is not allocated.
- - A gap (unallocated memory) between start and end address.
-
-- ``-EPERM``:
- - sealing is supported only on 64-bit CPUs, 32-bit is not supported.
-
-- For above error cases, users can expect the given memory range is
- unmodified, i.e. no partial update.
-
-- There might be other internal errors/cases not listed here, e.g.
- error during merging/splitting VMAs, or the process reaching the max
- number of supported VMAs. In those cases, partial updates to the given
- memory range could happen. However, those cases should be rare.
-
-**Blocked operations after sealing**:
- Unmapping, moving to another location, and shrinking the size,
- via munmap() and mremap(), can leave an empty space, therefore
- can be replaced with a VMA with a new set of attributes.
-
- Moving or expanding a different VMA into the current location,
- via mremap().
-
- Modifying a VMA via mmap(MAP_FIXED).
-
- Size expansion, via mremap(), does not appear to pose any
- specific risks to sealed VMAs. It is included anyway because
- the use case is unclear. In any case, users can rely on
- merging to expand a sealed VMA.
-
- mprotect() and pkey_mprotect().
-
- Some destructive madvice() behaviors (e.g. MADV_DONTNEED)
- for anonymous memory, when users don't have write permission to the
- memory. Those behaviors can alter region contents by discarding pages,
- effectively a memset(0) for anonymous memory.
-
- Kernel will return -EPERM for blocked operations.
-
- For blocked operations, one can expect the given address is unmodified,
- i.e. no partial update. Note, this is different from existing mm
- system call behaviors, where partial updates are made till an error is
- found and returned to userspace. To give an example:
-
- Assume following code sequence:
-
- - ptr = mmap(null, 8192, PROT_NONE);
- - munmap(ptr + 4096, 4096);
- - ret1 = mprotect(ptr, 8192, PROT_READ);
- - mseal(ptr, 4096);
- - ret2 = mprotect(ptr, 8192, PROT_NONE);
-
- ret1 will be -ENOMEM, the page from ptr is updated to PROT_READ.
-
- ret2 will be -EPERM, the page remains to be PROT_READ.
-
-**Note**:
-
-- mseal() only works on 64-bit CPUs, not 32-bit CPU.
-
-- users can call mseal() multiple times, mseal() on an already sealed memory
- is a no-action (not error).
-
-- munseal() is not supported.
-
-Use cases:
-==========
+SYSCALL
+=======
+mseal syscall signature
+-----------------------
+ ``int mseal(void \* addr, size_t len, unsigned long flags)``
+
+ **addr**/**len**: virtual memory address range.
+ The address range set by **addr**/**len** must meet:
+ - The start address must be in an allocated VMA.
+ - The start address must be page aligned.
+ - The end address (**addr** + **len**) must be in an allocated VMA.
+ - no gap (unallocated memory) between start and end address.
+
+ The ``len`` will be paged aligned implicitly by the kernel.
+
+ **flags**: reserved for future use.
+
+ **Return values**:
+ - **0**: Success.
+ - **-EINVAL**:
+ * Invalid input ``flags``.
+ * The start address (``addr``) is not page aligned.
+ * Address range (``addr`` + ``len``) overflow.
+ - **-ENOMEM**:
+ * The start address (``addr``) is not allocated.
+ * The end address (``addr`` + ``len``) is not allocated.
+ * A gap (unallocated memory) between start and end address.
+ - **-EPERM**:
+ * sealing is supported only on 64-bit CPUs, 32-bit is not supported.
+
+ **Note about error return**:
+ - For above error cases, users can expect the given memory range is
+ unmodified, i.e. no partial update.
+ - There might be other internal errors/cases not listed here, e.g.
+ error during merging/splitting VMAs, or the process reaching the maximum
+ number of supported VMAs. In those cases, partial updates to the given
+ memory range could happen. However, those cases should be rare.
+
+ **Architecture support**:
+ mseal only works on 64-bit CPUs, not 32-bit CPUs.
+
+ **Idempotent**:
+ users can call mseal multiple times. mseal on an already sealed memory
+ is a no-action (not error).
+
+ **no munseal**
+ Once mapping is sealed, it can't be unsealed. The kernel should never
+ have munseal, this is consistent with other sealing feature, e.g.
+ F_SEAL_SEAL for file.
+
+Blocked mm syscall for sealed mapping
+-------------------------------------
+ It might be important to note: **once the mapping is sealed, it will
+ stay in the process's memory until the process terminates**.
+
+ Example::
+
+ *ptr = mmap(0, 4096, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
+ rc = mseal(ptr, 4096, 0);
+ /* munmap will fail */
+ rc = munmap(ptr, 4096);
+ assert(rc < 0);
+
+ Blocked mm syscall:
+ - munmap
+ - mmap
+ - mremap
+ - mprotect and pkey_mprotect
+ - some destructive madvise behaviors: MADV_DONTNEED, MADV_FREE,
+ MADV_DONTNEED_LOCKED, MADV_FREE, MADV_DONTFORK, MADV_WIPEONFORK
+
+ The first set of syscalls to block is munmap, mremap, mmap. They can
+ either leave an empty space in the address space, therefore allowing
+ replacement with a new mapping with new set of attributes, or can
+ overwrite the existing mapping with another mapping.
+
+ mprotect and pkey_mprotect are blocked because they changes the
+ protection bits (RWX) of the mapping.
+
+ Certain destructive madvise behaviors, specifically MADV_DONTNEED,
+ MADV_FREE, MADV_DONTNEED_LOCKED, and MADV_WIPEONFORK, can introduce
+ risks when applied to anonymous memory by threads lacking write
+ permissions. Consequently, these operations are prohibited under such
+ conditions. The aforementioned behaviors have the potential to modify
+ region contents by discarding pages, effectively performing a memset(0)
+ operation on the anonymous memory.
+
+ Kernel will return -EPERM for blocked syscalls.
+
+ When blocked syscall return -EPERM due to sealing, the memory regions may
+ or may not be changed, depends on the syscall being blocked:
+
+ - munmap: munmap is atomic. If one of VMAs in the given range is
+ sealed, none of VMAs are updated.
+ - mprotect, pkey_mprotect, madvise: partial update might happen, e.g.
+ when mprotect over multiple VMAs, mprotect might update the beginning
+ VMAs before reaching the sealed VMA and return -EPERM.
+ - mmap and mremap: undefined behavior.
+
+Use cases
+=========
- glibc:
The dynamic linker, during loading ELF executables, can apply sealing to
- non-writable memory segments.
-
-- Chrome browser: protect some security sensitive data-structures.
+ mapping segments.
-Notes on which memory to seal:
-==============================
+- Chrome browser: protect some security sensitive data structures.
-It might be important to note that sealing changes the lifetime of a mapping,
-i.e. the sealed mapping won’t be unmapped till the process terminates or the
-exec system call is invoked. Applications can apply sealing to any virtual
-memory region from userspace, but it is crucial to thoroughly analyze the
-mapping's lifetime prior to apply the sealing.
+When not to use mseal
+=====================
+Applications can apply sealing to any virtual memory region from userspace,
+but it is *crucial to thoroughly analyze the mapping's lifetime* prior to
+apply the sealing. This is because the sealed mapping *won’t be unmapped*
+until the process terminates or the exec system call is invoked.
For example:
+ - aio/shm
+ aio/shm can call mmap and munmap on behalf of userspace, e.g.
+ ksys_shmdt() in shm.c. The lifetimes of those mapping are not tied to
+ the lifetime of the process. If those memories are sealed from userspace,
+ then munmap will fail, causing leaks in VMA address space during the
+ lifetime of the process.
+
+ - ptr allocated by malloc (heap)
+ Don't use mseal on the memory ptr return from malloc().
+ malloc() is implemented by allocator, e.g. by glibc. Heap manager might
+ allocate a ptr from brk or mapping created by mmap.
+ If an app calls mseal on a ptr returned from malloc(), this can affect
+ the heap manager's ability to manage the mappings; the outcome is
+ non-deterministic.
+
+ Example::
+
+ ptr = malloc(size);
+ /* don't call mseal on ptr return from malloc. */
+ mseal(ptr, size);
+ /* free will success, allocator can't shrink heap lower than ptr */
+ free(ptr);
+
+mseal doesn't block
+===================
+In a nutshell, mseal blocks certain mm syscall from modifying some of VMA's
+attributes, such as protection bits (RWX). Sealed mappings doesn't mean the
+memory is immutable.
-- aio/shm
-
- aio/shm can call mmap()/munmap() on behalf of userspace, e.g. ksys_shmdt() in
- shm.c. The lifetime of those mapping are not tied to the lifetime of the
- process. If those memories are sealed from userspace, then munmap() will fail,
- causing leaks in VMA address space during the lifetime of the process.
-
-- Brk (heap)
-
- Currently, userspace applications can seal parts of the heap by calling
- malloc() and mseal().
- let's assume following calls from user space:
-
- - ptr = malloc(size);
- - mprotect(ptr, size, RO);
- - mseal(ptr, size);
- - free(ptr);
-
- Technically, before mseal() is added, the user can change the protection of
- the heap by calling mprotect(RO). As long as the user changes the protection
- back to RW before free(), the memory range can be reused.
-
- Adding mseal() into the picture, however, the heap is then sealed partially,
- the user can still free it, but the memory remains to be RO. If the address
- is re-used by the heap manager for another malloc, the process might crash
- soon after. Therefore, it is important not to apply sealing to any memory
- that might get recycled.
-
- Furthermore, even if the application never calls the free() for the ptr,
- the heap manager may invoke the brk system call to shrink the size of the
- heap. In the kernel, the brk-shrink will call munmap(). Consequently,
- depending on the location of the ptr, the outcome of brk-shrink is
- nondeterministic.
-
-
-Additional notes:
-=================
As Jann Horn pointed out in [3], there are still a few ways to write
-to RO memory, which is, in a way, by design. Those cases are not covered
-by mseal(). If applications want to block such cases, sandbox tools (such as
-seccomp, LSM, etc) might be considered.
+to RO memory, which is, in a way, by design. And those could be blocked
+by different security measures.
Those cases are:
-- Write to read-only memory through /proc/self/mem interface.
-- Write to read-only memory through ptrace (such as PTRACE_POKETEXT).
-- userfaultfd.
+ - Write to read-only memory through /proc/self/mem interface (FOLL_FORCE).
+ - Write to read-only memory through ptrace (such as PTRACE_POKETEXT).
+ - userfaultfd.
The idea that inspired this patch comes from Stephen Röttger’s work in V8
CFI [4]. Chrome browser in ChromeOS will be the first user of this API.
-Reference:
-==========
-[1] https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274
-
-[2] https://man.openbsd.org/mimmutable.2
-
-[3] https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.com
-
-[4] https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hc
+Reference
+=========
+- [1] https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/osfmk/mach/vm_statistics.h#L274
+- [2] https://man.openbsd.org/mimmutable.2
+- [3] https://lore.kernel.org/lkml/CAG48ez3ShUYey+ZAFsU2i1RpQn0a5eOs2hzQ426FkcgnfUGLvA@mail.gmail.com
+- [4] https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/edit#heading=h.bvaojj9fu6hc
diff --git a/MAINTAINERS b/MAINTAINERS
index f39ab140710f..96b9344c3524 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1174,8 +1174,9 @@ F: Documentation/hid/amd-sfh*
F: drivers/hid/amd-sfh-hid/
AMD SPI DRIVER
-M: Sanjay R Mehta <sanju.mehta@amd.com>
-S: Maintained
+M: Raju Rangoju <Raju.Rangoju@amd.com>
+L: linux-spi@vger.kernel.org
+S: Supported
F: drivers/spi/spi-amd.c
AMD XGBE DRIVER
@@ -2852,7 +2853,7 @@ F: Documentation/devicetree/bindings/arm/qcom.yaml
F: Documentation/devicetree/bindings/bus/qcom*
F: Documentation/devicetree/bindings/cache/qcom,llcc.yaml
F: Documentation/devicetree/bindings/firmware/qcom,scm.yaml
-F: Documentation/devicetree/bindings/reserved-memory/qcom
+F: Documentation/devicetree/bindings/reserved-memory/qcom*
F: Documentation/devicetree/bindings/soc/qcom/
F: arch/arm/boot/dts/qcom/
F: arch/arm/configs/qcom_defconfig
@@ -3745,6 +3746,7 @@ F: drivers/spi/spi-axi-spi-engine.c
AXI PWM GENERATOR
M: Michael Hennerich <michael.hennerich@analog.com>
M: Nuno Sá <nuno.sa@analog.com>
+R: Trevor Gamblin <tgamblin@baylibre.com>
L: linux-pwm@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -8996,9 +8998,16 @@ F: drivers/dma/fsl-edma*.*
FREESCALE ENETC ETHERNET DRIVERS
M: Claudiu Manoil <claudiu.manoil@nxp.com>
M: Vladimir Oltean <vladimir.oltean@nxp.com>
+M: Wei Fang <wei.fang@nxp.com>
+M: Clark Wang <xiaoning.wang@nxp.com>
+L: imx@lists.linux.dev
L: netdev@vger.kernel.org
S: Maintained
+F: Documentation/devicetree/bindings/net/fsl,enetc*.yaml
+F: Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
F: drivers/net/ethernet/freescale/enetc/
+F: include/linux/fsl/enetc_mdio.h
+F: include/linux/fsl/netc_global.h
FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
M: Claudiu Manoil <claudiu.manoil@nxp.com>
@@ -9723,6 +9732,7 @@ F: include/dt-bindings/gpio/
F: include/linux/gpio.h
F: include/linux/gpio/
F: include/linux/of_gpio.h
+K: (devm_)?gpio_(request|free|direction|get|set)
GPIO UAPI
M: Bartosz Golaszewski <brgl@bgdev.pl>
@@ -14146,6 +14156,15 @@ S: Maintained
T: git git://linuxtv.org/media_tree.git
F: drivers/media/platform/nxp/imx-pxp.[ch]
+MEDIA DRIVERS FOR ASCOT2E
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/dvb-frontends/ascot2e*
+
MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS
M: Jasmin Jessich <jasmin@anw.at>
L: linux-media@vger.kernel.org
@@ -14154,6 +14173,15 @@ W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/dvb-frontends/cxd2099*
+MEDIA DRIVERS FOR CXD2841ER
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/dvb-frontends/cxd2841er*
+
MEDIA DRIVERS FOR CXD2880
M: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
L: linux-media@vger.kernel.org
@@ -14198,6 +14226,33 @@ F: drivers/media/platform/nxp/imx-mipi-csis.c
F: drivers/media/platform/nxp/imx7-media-csi.c
F: drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+MEDIA DRIVERS FOR HELENE
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/dvb-frontends/helene*
+
+MEDIA DRIVERS FOR HORUS3A
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/dvb-frontends/horus3a*
+
+MEDIA DRIVERS FOR LNBH25
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/dvb-frontends/lnbh25*
+
MEDIA DRIVERS FOR MXL5XX TUNER DEMODULATORS
L: linux-media@vger.kernel.org
S: Orphan
@@ -14205,6 +14260,15 @@ W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/dvb-frontends/mxl5xx*
+MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
+M: Abylay Ospan <aospan@amazon.com>
+L: linux-media@vger.kernel.org
+S: Supported
+W: https://linuxtv.org
+W: http://netup.tv/
+T: git git://linuxtv.org/media_tree.git
+F: drivers/media/pci/netup_unidvb/*
+
MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
M: Dmitry Osipenko <digetx@gmail.com>
L: linux-media@vger.kernel.org
@@ -14376,8 +14440,10 @@ M: Qingfang Deng <dqfext@gmail.com>
M: SkyLake Huang <SkyLake.Huang@mediatek.com>
L: netdev@vger.kernel.org
S: Maintained
-F: drivers/net/phy/mediatek-ge-soc.c
-F: drivers/net/phy/mediatek-ge.c
+F: drivers/net/phy/mediatek/mtk-ge-soc.c
+F: drivers/net/phy/mediatek/mtk-phy-lib.c
+F: drivers/net/phy/mediatek/mtk-ge.c
+F: drivers/net/phy/mediatek/mtk.h
F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c
MEDIATEK I2C CONTROLLER DRIVER
@@ -14992,6 +15058,7 @@ F: drivers/spi/spi-at91-usart.c
MICROCHIP AUDIO ASOC DRIVERS
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
+M: Andrei Simion <andrei.simion@microchip.com>
L: linux-sound@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/sound/atmel*
@@ -15091,6 +15158,13 @@ S: Maintained
F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml
F: drivers/irqchip/irq-lan966x-oic.c
+MICROCHIP LAN969X ETHERNET DRIVER
+M: Daniel Machon <daniel.machon@microchip.com>
+M: UNGLinuxDriver@microchip.com
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/microchip/lan969x/*
+
MICROCHIP LCDFB DRIVER
M: Nicolas Ferre <nicolas.ferre@microchip.com>
L: linux-fbdev@vger.kernel.org
@@ -15100,6 +15174,7 @@ F: include/video/atmel_lcdc.h
MICROCHIP MCP16502 PMIC DRIVER
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
+M: Andrei Simion <andrei.simion@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: Documentation/devicetree/bindings/regulator/microchip,mcp16502.yaml
@@ -15230,6 +15305,7 @@ F: drivers/spi/spi-atmel.*
MICROCHIP SSC DRIVER
M: Claudiu Beznea <claudiu.beznea@tuxon.dev>
+M: Andrei Simion <andrei.simion@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Supported
F: Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@ -16031,7 +16107,6 @@ F: drivers/net/wireless/
NETWORKING [DSA]
M: Andrew Lunn <andrew@lunn.ch>
-M: Florian Fainelli <f.fainelli@gmail.com>
M: Vladimir Oltean <olteanv@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/
@@ -19535,6 +19610,17 @@ S: Supported
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.yaml
F: drivers/i2c/busses/i2c-emev2.c
+RENESAS ETHERNET AVB DRIVER
+M: Paul Barker <paul.barker.ct@bp.renesas.com>
+M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
+L: netdev@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/net/renesas,etheravb.yaml
+F: drivers/net/ethernet/renesas/Kconfig
+F: drivers/net/ethernet/renesas/Makefile
+F: drivers/net/ethernet/renesas/ravb*
+
RENESAS ETHERNET SWITCH DRIVER
R: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: netdev@vger.kernel.org
@@ -19584,6 +19670,14 @@ F: Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
F: drivers/i2c/busses/i2c-rcar.c
F: drivers/i2c/busses/i2c-sh_mobile.c
+RENESAS R-CAR SATA DRIVER
+M: Geert Uytterhoeven <geert+renesas@glider.be>
+L: linux-ide@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml
+F: drivers/ata/sata_rcar.c
+
RENESAS R-CAR THERMAL DRIVERS
M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
L: linux-renesas-soc@vger.kernel.org
@@ -19659,6 +19753,17 @@ S: Supported
F: Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
F: drivers/i2c/busses/i2c-rzv2m.c
+RENESAS SUPERH ETHERNET DRIVER
+M: Niklas Söderlund <niklas.soderlund@ragnatech.se>
+L: netdev@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/net/renesas,ether.yaml
+F: drivers/net/ethernet/renesas/Kconfig
+F: drivers/net/ethernet/renesas/Makefile
+F: drivers/net/ethernet/renesas/sh_eth*
+F: include/linux/sh_eth.h
+
RENESAS USB PHY DRIVER
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-renesas-soc@vger.kernel.org
@@ -19803,12 +19908,10 @@ L: linux-riscv@lists.infradead.org
S: Maintained
Q: https://patchwork.kernel.org/project/linux-riscv/list/
T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
-F: Documentation/devicetree/bindings/riscv/
-F: arch/riscv/boot/dts/
-X: arch/riscv/boot/dts/allwinner/
-X: arch/riscv/boot/dts/renesas/
-X: arch/riscv/boot/dts/sophgo/
-X: arch/riscv/boot/dts/thead/
+F: arch/riscv/boot/dts/canaan/
+F: arch/riscv/boot/dts/microchip/
+F: arch/riscv/boot/dts/sifive/
+F: arch/riscv/boot/dts/starfive/
RISC-V PMU DRIVERS
M: Atish Patra <atishp@atishpatra.org>
@@ -19827,8 +19930,10 @@ L: linux-riscv@lists.infradead.org
S: Maintained
T: git https://github.com/pdp7/linux.git
F: Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml
+F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml
F: arch/riscv/boot/dts/thead/
F: drivers/clk/thead/clk-th1520-ap.c
+F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
F: include/dt-bindings/clock/thead,th1520-clk-ap.h
RNBD BLOCK DRIVERS
@@ -20204,6 +20309,12 @@ F: Documentation/arch/s390/pci.rst
F: arch/s390/pci/
F: drivers/pci/hotplug/s390_pci_hpc.c
+S390 PTP DRIVER
+M: Sven Schnelle <svens@linux.ibm.com>
+L: linux-s390@vger.kernel.org
+S: Supported
+F: drivers/ptp/ptp_s390.c
+
S390 SCM DRIVER
M: Vineeth Vijayan <vneethv@linux.ibm.com>
L: linux-s390@vger.kernel.org
@@ -21575,6 +21686,15 @@ S: Supported
W: https://github.com/thesofproject/linux/
F: sound/soc/sof/
+SOUND - GENERIC SOUND CARD (Simple-Audio-Card, Audio-Graph-Card)
+M: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+S: Supported
+L: linux-sound@vger.kernel.org
+F: sound/soc/generic/
+F: include/sound/simple_card*
+F: Documentation/devicetree/bindings/sound/simple-card.yaml
+F: Documentation/devicetree/bindings/sound/audio-graph*.yaml
+
SOUNDWIRE SUBSYSTEM
M: Vinod Koul <vkoul@kernel.org>
M: Bard Liao <yung-chuan.liao@linux.intel.com>
@@ -23154,7 +23274,7 @@ F: Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml
F: drivers/iio/adc/ti-lmp92064.c
TI PCM3060 ASoC CODEC DRIVER
-M: Kirill Marinushkin <kmarinushkin@birdec.com>
+M: Kirill Marinushkin <k.marinushkin@gmail.com>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/pcm3060.txt
diff --git a/Makefile b/Makefile
index a9a7d9ffaa98..79192a3024bf 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 6
PATCHLEVEL = 12
SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc7
NAME = Baby Opossum Posse
# *DOCUMENTATION*
diff --git a/arch/Kconfig b/arch/Kconfig
index 00163e4a237c..bd9f095d69fa 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -855,14 +855,14 @@ config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
def_bool y
depends on $(cc-option,-fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers)
# With GCOV/KASAN we need this fix: https://github.com/llvm/llvm-project/pull/104826
- depends on CLANG_VERSION >= 190000 || (!GCOV_KERNEL && !KASAN_GENERIC && !KASAN_SW_TAGS)
+ depends on CLANG_VERSION >= 190103 || (!GCOV_KERNEL && !KASAN_GENERIC && !KASAN_SW_TAGS)
config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
def_bool y
depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS_CLANG
depends on RUSTC_VERSION >= 107900
# With GCOV/KASAN we need this fix: https://github.com/rust-lang/rust/pull/129373
- depends on (RUSTC_LLVM_VERSION >= 190000 && RUSTC_VERSION >= 108200) || \
+ depends on (RUSTC_LLVM_VERSION >= 190103 && RUSTC_VERSION >= 108200) || \
(!GCOV_KERNEL && !KASAN_GENERIC && !KASAN_SW_TAGS)
config CFI_PERMISSIVE
diff --git a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts
index e32c73d32f0a..2f84e2805712 100644
--- a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts
+++ b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts
@@ -325,8 +325,8 @@
&i2c2 {
status = "okay";
- rt5616: rt5616@1b {
- compatible = "rt5616";
+ rt5616: audio-codec@1b {
+ compatible = "realtek,rt5616";
reg = <0x1b>;
clocks = <&cru SCLK_I2S_OUT>;
clock-names = "mclk";
diff --git a/arch/arm/boot/dts/rockchip/rk3036.dtsi b/arch/arm/boot/dts/rockchip/rk3036.dtsi
index 96279d1e02fe..63b9912be06a 100644
--- a/arch/arm/boot/dts/rockchip/rk3036.dtsi
+++ b/arch/arm/boot/dts/rockchip/rk3036.dtsi
@@ -384,12 +384,13 @@
};
};
- acodec: acodec-ana@20030000 {
- compatible = "rk3036-codec";
+ acodec: audio-codec@20030000 {
+ compatible = "rockchip,rk3036-codec";
reg = <0x20030000 0x4000>;
- rockchip,grf = <&grf>;
clock-names = "acodec_pclk";
clocks = <&cru PCLK_ACODEC>;
+ rockchip,grf = <&grf>;
+ #sound-dai-cells = <0>;
status = "disabled";
};
@@ -399,7 +400,6 @@
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI>;
clock-names = "pclk";
- rockchip,grf = <&grf>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_ctl>;
#sound-dai-cells = <0>;
@@ -553,11 +553,11 @@
};
spi: spi@20074000 {
- compatible = "rockchip,rockchip-spi";
+ compatible = "rockchip,rk3036-spi";
reg = <0x20074000 0x1000>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&cru PCLK_SPI>, <&cru SCLK_SPI>;
- clock-names = "apb-pclk","spi_pclk";
+ clocks = <&cru SCLK_SPI>, <&cru PCLK_SPI>;
+ clock-names = "spiclk", "apb_pclk";
dmas = <&pdma 8>, <&pdma 9>;
dma-names = "tx", "rx";
pinctrl-names = "default";
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd9df6dcc593..70d7f4f20225 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2214,6 +2214,7 @@ config ARM64_SME
bool "ARM Scalable Matrix Extension support"
default y
depends on ARM64_SVE
+ depends on BROKEN
help
The Scalable Matrix Extension (SME) is an extension to the AArch64
execution state which utilises a substantial subset of the SVE
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-lvds0.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-lvds0.dtsi
index d00036204a8c..dad0dc8fb431 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-lvds0.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-lvds0.dtsi
@@ -14,7 +14,7 @@ lvds0_subsys: bus@56240000 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x56243000 0x4>;
#clock-cells = <1>;
- clock-output-names = "mipi1_lis_lpcg_ipg_clk";
+ clock-output-names = "lvds0_lis_lpcg_ipg_clk";
power-domains = <&pd IMX_SC_R_MIPI_1>;
};
@@ -22,9 +22,9 @@ lvds0_subsys: bus@56240000 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x5624300c 0x4>;
#clock-cells = <1>;
- clock-output-names = "mipi1_pwm_lpcg_clk",
- "mipi1_pwm_lpcg_ipg_clk",
- "mipi1_pwm_lpcg_32k_clk";
+ clock-output-names = "lvds0_pwm_lpcg_clk",
+ "lvds0_pwm_lpcg_ipg_clk",
+ "lvds0_pwm_lpcg_32k_clk";
power-domains = <&pd IMX_SC_R_MIPI_1_PWM_0>;
};
@@ -32,8 +32,8 @@ lvds0_subsys: bus@56240000 {
compatible = "fsl,imx8qxp-lpcg";
reg = <0x56243010 0x4>;
#clock-cells = <1>;
- clock-output-names = "mipi1_i2c0_lpcg_clk",
- "mipi1_i2c0_lpcg_ipg_clk";
+ clock-output-names = "lvds0_i2c0_lpcg_clk",
+ "lvds0_i2c0_lpcg_ipg_clk";
power-domains = <&pd IMX_SC_R_MIPI_1_I2C_0>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-vpu.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-vpu.dtsi
index c6540768bdb9..87211c18d65a 100644
--- a/arch/arm64/boot/dts/freescale/imx8-ss-vpu.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-vpu.dtsi
@@ -15,7 +15,7 @@ vpu: vpu@2c000000 {
mu_m0: mailbox@2d000000 {
compatible = "fsl,imx6sx-mu";
reg = <0x2d000000 0x20000>;
- interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>;
#mbox-cells = <2>;
power-domains = <&pd IMX_SC_R_VPU_MU_0>;
status = "disabled";
@@ -24,7 +24,7 @@ vpu: vpu@2c000000 {
mu1_m0: mailbox@2d020000 {
compatible = "fsl,imx6sx-mu";
reg = <0x2d020000 0x20000>;
- interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>;
#mbox-cells = <2>;
power-domains = <&pd IMX_SC_R_VPU_MU_1>;
status = "disabled";
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
index 50debe821c42..9c102acb8052 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
@@ -218,6 +218,18 @@
};
};
+&media_blk_ctrl {
+ /*
+ * The LVDS panel on this device uses 72.4 MHz pixel clock,
+ * set IMX8MP_VIDEO_PLL1 to 72.4 * 7 = 506.8 MHz so the LDB
+ * serializer and LCDIFv3 scanout engine can reach accurate
+ * pixel clock of exactly 72.4 MHz.
+ */
+ assigned-clock-rates = <500000000>, <200000000>,
+ <0>, <0>, <500000000>,
+ <506800000>;
+};
+
&snvs_pwrkey {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
index 3c2efdc59bfa..30962922b361 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts
@@ -71,6 +71,7 @@
assigned-clock-rates = <500000000>, <200000000>, <0>,
/* IMX8MP_CLK_MEDIA_DISP2_PIX = pixelclk of lvds panel */
<68900000>,
+ <500000000>,
/* IMX8MP_VIDEO_PLL1 = IMX8MP_CLK_MEDIA_LDB * 2 */
<964600000>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
index f3531cfb0d79..40e847bc0b7f 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi
@@ -1261,7 +1261,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b40000 0x10000>;
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk IMX8MP_CLK_DUMMY>,
+ clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC1_ROOT>;
clock-names = "ipg", "ahb", "per";
@@ -1275,7 +1275,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b50000 0x10000>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk IMX8MP_CLK_DUMMY>,
+ clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC2_ROOT>;
clock-names = "ipg", "ahb", "per";
@@ -1289,7 +1289,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b60000 0x10000>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk IMX8MP_CLK_DUMMY>,
+ clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC3_ROOT>;
clock-names = "ipg", "ahb", "per";
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi
index 7894a3ab26d6..f81937b5fb72 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi
@@ -5,6 +5,14 @@
* Author: Alexander Stein
*/
+&mu_m0 {
+ interrupts = <GIC_SPI 469 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&mu1_m0 {
+ interrupts = <GIC_SPI 470 IRQ_TYPE_LEVEL_HIGH>;
+};
+
&vpu_core0 {
reg = <0x2d040000 0x10000>;
};
diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index e32d5afcf4a9..43f543768444 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -384,7 +384,7 @@
};
flexspi2: spi@29810000 {
- compatible = "nxp,imx8mm-fspi";
+ compatible = "nxp,imx8ulp-fspi";
reg = <0x29810000 0x10000>, <0x60000000 0x10000000>;
reg-names = "fspi_base", "fspi_mmap";
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi
index 28634789a8a9..7af210789879 100644
--- a/arch/arm64/boot/dts/qcom/msm8939.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi
@@ -248,7 +248,7 @@
smd-edge {
interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
- mboxes = <&apcs1_mbox 0>;
+ qcom,ipc = <&apcs1_mbox 8 0>;
qcom,smd-edge = <15>;
rpm_requests: rpm-requests {
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 9bafb3b350ff..38cb524cc568 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -1973,7 +1973,7 @@
clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
<&gcc GCC_PCIE_1_PIPE_CLK_SRC>,
- <&pcie1_phy>,
+ <&pcie1_phy QMP_PCIE_PIPE_CLK>,
<&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_PCIE_1_AUX_CLK>,
<&gcc GCC_PCIE_1_CFG_AHB_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts
index 941dfddd6713..fdde988ae01e 100644
--- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts
+++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts
@@ -139,6 +139,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
+
+ regulator-boot-on;
};
vph_pwr: regulator-vph-pwr {
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
index 20616bd4aa6c..fb4a48a1e2a8 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts
@@ -134,6 +134,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
+
+ regulator-boot-on;
};
};
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
index 10b28d870f08..c6e0356ed9a2 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts
@@ -177,9 +177,9 @@
compatible = "qcom,x1e80100-sndcard";
model = "X1E80100-CRD";
audio-routing = "WooferLeft IN", "WSA WSA_SPK1 OUT",
- "TwitterLeft IN", "WSA WSA_SPK2 OUT",
+ "TweeterLeft IN", "WSA WSA_SPK2 OUT",
"WooferRight IN", "WSA2 WSA_SPK2 OUT",
- "TwitterRight IN", "WSA2 WSA_SPK2 OUT",
+ "TweeterRight IN", "WSA2 WSA_SPK2 OUT",
"IN1_HPHL", "HPHL_OUT",
"IN2_HPHR", "HPHR_OUT",
"AMIC2", "MIC BIAS2",
@@ -300,6 +300,8 @@
pinctrl-names = "default";
pinctrl-0 = <&nvme_reg_en>;
+
+ regulator-boot-on;
};
vreg_wwan: regulator-wwan {
@@ -933,7 +935,7 @@
reg = <0 1>;
reset-gpios = <&lpass_tlmm 12 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
- sound-name-prefix = "TwitterLeft";
+ sound-name-prefix = "TweeterLeft";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l12b_1p2>;
qcom,port-mapping = <4 5 6 7 11 13>;
@@ -986,7 +988,7 @@
reg = <0 1>;
reset-gpios = <&lpass_tlmm 13 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
- sound-name-prefix = "TwitterRight";
+ sound-name-prefix = "TweeterRight";
vdd-1p8-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l12b_1p2>;
qcom,port-mapping = <4 5 6 7 11 13>;
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
index 3c13331a9ef4..0cdaff9c8cf0 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts
@@ -205,6 +205,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
+
+ regulator-boot-on;
};
};
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
index 42e02ad6a9c3..cdb401767c42 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi
@@ -164,6 +164,8 @@
pinctrl-0 = <&nvme_reg_en>;
pinctrl-names = "default";
+
+ regulator-boot-on;
};
};
diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
index 1c3a6a7b3ed6..5ef030c60abe 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
+++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts
@@ -253,6 +253,8 @@
pinctrl-names = "default";
pinctrl-0 = <&nvme_reg_en>;
+
+ regulator-boot-on;
};
};
diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi
index a36076e3c56b..0510abc0edf0 100644
--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi
@@ -2924,14 +2924,14 @@
"mhi";
#address-cells = <3>;
#size-cells = <2>;
- ranges = <0x01000000 0 0x00000000 0 0x70200000 0 0x100000>,
- <0x02000000 0 0x70300000 0 0x70300000 0 0x3d00000>;
- bus-range = <0 0xff>;
+ ranges = <0x01000000 0x0 0x00000000 0x0 0x70200000 0x0 0x100000>,
+ <0x02000000 0x0 0x70300000 0x0 0x70300000 0x0 0x1d00000>;
+ bus-range = <0x00 0xff>;
dma-coherent;
linux,pci-domain = <6>;
- num-lanes = <2>;
+ num-lanes = <4>;
interrupts = <GIC_SPI 773 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 774 IRQ_TYPE_LEVEL_HIGH>,
@@ -2997,19 +2997,22 @@
};
pcie6a_phy: phy@1bfc000 {
- compatible = "qcom,x1e80100-qmp-gen4x2-pcie-phy";
- reg = <0 0x01bfc000 0 0x2000>;
+ compatible = "qcom,x1e80100-qmp-gen4x4-pcie-phy";
+ reg = <0 0x01bfc000 0 0x2000>,
+ <0 0x01bfe000 0 0x2000>;
clocks = <&gcc GCC_PCIE_6A_PHY_AUX_CLK>,
<&gcc GCC_PCIE_6A_CFG_AHB_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&tcsr TCSR_PCIE_4L_CLKREF_EN>,
<&gcc GCC_PCIE_6A_PHY_RCHNG_CLK>,
- <&gcc GCC_PCIE_6A_PIPE_CLK>;
+ <&gcc GCC_PCIE_6A_PIPE_CLK>,
+ <&gcc GCC_PCIE_6A_PIPEDIV2_CLK>;
clock-names = "aux",
"cfg_ahb",
"ref",
"rchng",
- "pipe";
+ "pipe",
+ "pipediv2";
resets = <&gcc GCC_PCIE_6A_PHY_BCR>,
<&gcc GCC_PCIE_6A_NOCSR_COM_PHY_BCR>;
@@ -3021,6 +3024,8 @@
power-domains = <&gcc GCC_PCIE_6_PHY_GDSC>;
+ qcom,4ln-config-sel = <&tcsr 0x1a000 0>;
+
#clock-cells = <0>;
clock-output-names = "pcie6a_pipe_clk";
@@ -3097,7 +3102,7 @@
assigned-clocks = <&gcc GCC_PCIE_5_AUX_CLK>;
assigned-clock-rates = <19200000>;
- interconnects = <&pcie_south_anoc MASTER_PCIE_5 QCOM_ICC_TAG_ALWAYS
+ interconnects = <&pcie_north_anoc MASTER_PCIE_5 QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
&cnoc_main SLAVE_PCIE_5 QCOM_ICC_TAG_ALWAYS>;
@@ -3124,14 +3129,16 @@
clocks = <&gcc GCC_PCIE_5_AUX_CLK>,
<&gcc GCC_PCIE_5_CFG_AHB_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&tcsr TCSR_PCIE_2L_5_CLKREF_EN>,
<&gcc GCC_PCIE_5_PHY_RCHNG_CLK>,
- <&gcc GCC_PCIE_5_PIPE_CLK>;
+ <&gcc GCC_PCIE_5_PIPE_CLK>,
+ <&gcc GCC_PCIE_5_PIPEDIV2_CLK>;
clock-names = "aux",
"cfg_ahb",
"ref",
"rchng",
- "pipe";
+ "pipe",
+ "pipediv2";
resets = <&gcc GCC_PCIE_5_PHY_BCR>;
reset-names = "phy";
@@ -3166,8 +3173,8 @@
"mhi";
#address-cells = <3>;
#size-cells = <2>;
- ranges = <0x01000000 0 0x00000000 0 0x7c200000 0 0x100000>,
- <0x02000000 0 0x7c300000 0 0x7c300000 0 0x3d00000>;
+ ranges = <0x01000000 0x0 0x00000000 0x0 0x7c200000 0x0 0x100000>,
+ <0x02000000 0x0 0x7c300000 0x0 0x7c300000 0x0 0x1d00000>;
bus-range = <0x00 0xff>;
dma-coherent;
@@ -3217,7 +3224,7 @@
assigned-clocks = <&gcc GCC_PCIE_4_AUX_CLK>;
assigned-clock-rates = <19200000>;
- interconnects = <&pcie_south_anoc MASTER_PCIE_4 QCOM_ICC_TAG_ALWAYS
+ interconnects = <&pcie_north_anoc MASTER_PCIE_4 QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
&cnoc_main SLAVE_PCIE_4 QCOM_ICC_TAG_ALWAYS>;
@@ -3254,14 +3261,16 @@
clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
<&gcc GCC_PCIE_4_CFG_AHB_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&tcsr TCSR_PCIE_2L_4_CLKREF_EN>,
<&gcc GCC_PCIE_4_PHY_RCHNG_CLK>,
- <&gcc GCC_PCIE_4_PIPE_CLK>;
+ <&gcc GCC_PCIE_4_PIPE_CLK>,
+ <&gcc GCC_PCIE_4_PIPEDIV2_CLK>;
clock-names = "aux",
"cfg_ahb",
"ref",
"rchng",
- "pipe";
+ "pipe",
+ "pipediv2";
resets = <&gcc GCC_PCIE_4_PHY_BCR>;
reset-names = "phy";
@@ -6084,7 +6093,8 @@
<0 0x25a00000 0 0x200000>,
<0 0x25c00000 0 0x200000>,
<0 0x25e00000 0 0x200000>,
- <0 0x26000000 0 0x200000>;
+ <0 0x26000000 0 0x200000>,
+ <0 0x26200000 0 0x200000>;
reg-names = "llcc0_base",
"llcc1_base",
"llcc2_base",
@@ -6093,7 +6103,8 @@
"llcc5_base",
"llcc6_base",
"llcc7_base",
- "llcc_broadcast_base";
+ "llcc_broadcast_base",
+ "llcc_broadcast_and_base";
interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
};
diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
index bb1aea82e666..b7163ed74232 100644
--- a/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi
@@ -66,7 +66,6 @@
bus-width = <8>;
cap-mmc-highspeed;
mmc-hs200-1_8v;
- supports-emmc;
mmc-pwrseq = <&emmc_pwrseq>;
non-removable;
vmmc-supply = <&vcc_3v3>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
index 9232357f4fec..d9e191ad1d77 100644
--- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
@@ -36,14 +36,14 @@
power_led: led-0 {
label = "firefly:red:power";
- linux,default-trigger = "ir-power-click";
+ linux,default-trigger = "default-on";
default-state = "on";
gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
};
user_led: led-1 {
label = "firefly:blue:user";
- linux,default-trigger = "ir-user-click";
+ linux,default-trigger = "rc-feedback";
default-state = "off";
gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts
index cb81ba3f23ff..4b9ced67742d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts
@@ -24,9 +24,7 @@
disable-wp;
mmc-hs200-1_8v;
non-removable;
- num-slots = <1>;
pinctrl-names = "default";
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
- supports-emmc;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 16b4faa22e4f..c01a4cad48f3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -754,8 +754,7 @@
compatible = "rockchip,rk3328-dw-hdmi";
reg = <0x0 0xff3c0000 0x0 0x20000>;
reg-io-width = <4>;
- interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI>,
<&cru SCLK_HDMI_SFC>,
<&cru SCLK_RTC32K>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
index 8ac8acf4082d..ab3fda69a1fb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi
@@ -61,7 +61,6 @@
fan: fan@18 {
compatible = "ti,amc6821";
reg = <0x18>;
- #cooling-cells = <2>;
};
rtc_twi: rtc@6f {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts
index 1489eb32e266..4feb78797982 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts
@@ -541,7 +541,7 @@
status = "okay";
rt5651: audio-codec@1a {
- compatible = "rockchip,rt5651";
+ compatible = "realtek,rt5651";
reg = <0x1a>;
clocks = <&cru SCLK_I2S_8CH_OUT>;
clock-names = "mclk";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 1a44582a49fb..09a016ea8c76 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -166,7 +166,6 @@
regulator-max-microvolt = <1800000>;
vin-supply = <&vcc3v3_sys>;
gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
};
/* MIPI DSI panel 2.8v supply */
@@ -178,7 +177,6 @@
regulator-max-microvolt = <2800000>;
vin-supply = <&vcc3v3_sys>;
gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
};
vibrator {
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
index 7ba1c28f70a9..2f06bfdd70bf 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts
@@ -114,7 +114,6 @@
es8388: es8388@11 {
compatible = "everest,es8388";
reg = <0x11>;
- clock-names = "mclk";
clocks = <&cru SCLK_I2S_8CH_OUT>;
#sound-dai-cells = <0>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
index 8146f870d2bd..ab890e7b6c59 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi
@@ -576,7 +576,7 @@
bluetooth {
compatible = "brcm,bcm43438-bt";
clocks = <&rk808 1>;
- clock-names = "ext_clock";
+ clock-names = "txco";
device-wakeup-gpios = <&gpio2 RK_PD3 GPIO_ACTIVE_HIGH>;
host-wakeup-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
index dbec2b7173a0..31ea3d0182c0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts
@@ -163,7 +163,7 @@
status = "okay";
rt5651: rt5651@1a {
- compatible = "rockchip,rt5651";
+ compatible = "realtek,rt5651";
reg = <0x1a>;
clocks = <&cru SCLK_I2S_8CH_OUT>;
clock-names = "mclk";
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
index a73cf30801ec..9816a4ed4599 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts
@@ -92,7 +92,7 @@
};
&i2c2 {
- pintctrl-names = "default";
+ pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts
index e9954a33e8cd..a79a5614bcc8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts
@@ -79,7 +79,7 @@
};
&i2c2 {
- pintctrl-names = "default";
+ pinctrl-names = "default";
pinctrl-0 = <&i2c2m1_xfer>;
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
index 0c18406e4c59..7d4680933823 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
@@ -449,9 +449,9 @@
bluetooth {
compatible = "brcm,bcm43438-bt";
clocks = <&pmucru CLK_RTC_32K>;
- clock-names = "ext_clock";
- device-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
- host-wake-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
+ clock-names = "txco";
+ device-wakeup-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts
index c1194d1e438d..9a2f59a351de 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts
@@ -507,7 +507,6 @@
non-removable;
pinctrl-names = "default";
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
- supports-emmc;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
index ae2536c65a83..0131f2cdd312 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi
@@ -684,11 +684,11 @@
compatible = "brcm,bcm43438-bt";
clocks = <&rk817 1>;
clock-names = "lpo";
- device-wake-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
- host-wake-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_LOW>;
+ device-wakeup-gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>;
+ host-wakeup-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&bt_enable_h>, <&bt_host_wake_l>, <&bt_wake_h>;
pinctrl-names = "default";
+ shutdown-gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>;
vbat-supply = <&vcc_wl>;
vddio-supply = <&vcca_1v8_pmu>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi
index 45de2630bb50..1e36f73840da 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi
@@ -402,9 +402,9 @@
clock-names = "lpo";
device-wakeup-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_HIGH>;
host-wakeup-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&bt_host_wake_h &bt_reg_on_h &bt_wake_host_h>;
+ shutdown-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
vbat-supply = <&vcc_3v3>;
vddio-supply = <&vcc_1v8>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts b/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts
index a3112d5df200..b505a4537ee8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts
@@ -589,7 +589,6 @@
non-removable;
pinctrl-names = "default";
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd>;
- supports-emmc;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts
index e333449ead04..2fa89a0eeafc 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts
@@ -272,7 +272,6 @@
regulator-name = "vdd_logic";
regulator-always-on;
regulator-boot-on;
- regulator-init-microvolt = <900000>;
regulator-initial-mode = <0x2>;
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1350000>;
@@ -285,7 +284,6 @@
vdd_gpu: DCDC_REG2 {
regulator-name = "vdd_gpu";
- regulator-init-microvolt = <900000>;
regulator-initial-mode = <0x2>;
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1350000>;
@@ -309,7 +307,6 @@
vdd_npu: DCDC_REG4 {
regulator-name = "vdd_npu";
- regulator-init-microvolt = <900000>;
regulator-initial-mode = <0x2>;
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1350000>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index d97d84b88837..fc67585b64b7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -337,15 +337,19 @@
cache-unified;
next-level-cache = <&l3_cache>;
};
+ };
- l3_cache: l3-cache {
- compatible = "cache";
- cache-size = <3145728>;
- cache-line-size = <64>;
- cache-sets = <4096>;
- cache-level = <3>;
- cache-unified;
- };
+ /*
+ * The L3 cache belongs to the DynamIQ Shared Unit (DSU),
+ * so it's represented here, outside the "cpus" node
+ */
+ l3_cache: l3-cache {
+ compatible = "cache";
+ cache-size = <3145728>;
+ cache-line-size = <64>;
+ cache-sets = <4096>;
+ cache-level = <3>;
+ cache-unified;
};
display_subsystem: display-subsystem {
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
index c3a6812cc93a..dd4c79bcad87 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts
@@ -328,7 +328,6 @@
compatible = "everest,es8388";
reg = <0x11>;
clocks = <&cru I2S0_8CH_MCLKOUT>;
- clock-names = "mclk";
AVDD-supply = <&vcc_1v8_s0>;
DVDD-supply = <&vcc_1v8_s0>;
HPVDD-supply = <&vcc_3v3_s0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts
index e4a20cda65ed..b38dab009ccc 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts
@@ -316,7 +316,6 @@
assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
assigned-clock-rates = <12288000>;
clocks = <&cru I2S0_8CH_MCLKOUT>;
- clock-names = "mclk";
AVDD-supply = <&avcc_1v8_codec_s0>;
DVDD-supply = <&avcc_1v8_codec_s0>;
HPVDD-supply = <&vcc_3v3_s0>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
index 966bbc582d89..6bd06e46a101 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts
@@ -304,12 +304,12 @@
};
cooling-maps {
- map1 {
+ map0 {
trip = <&package_fan0>;
cooling-device = <&fan THERMAL_NO_LIMIT 1>;
};
- map2 {
+ map1 {
trip = <&package_fan1>;
cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts
index d0021524e7f9..328dcb894ccb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts
@@ -428,7 +428,6 @@
regulator-boot-on;
regulator-min-microvolt = <550000>;
regulator-max-microvolt = <950000>;
- regulator-init-microvolt = <750000>;
regulator-ramp-delay = <12500>;
regulator-state-mem {
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
index dbaa94ca69f4..432133251e31 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi
@@ -296,6 +296,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+ system-power-controller;
vcc1-supply = <&vcc5v0_sys>;
vcc2-supply = <&vcc5v0_sys>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts
index d8c50fdcca3b..8ba111d9283f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts
@@ -377,7 +377,6 @@
assigned-clock-rates = <12288000>;
assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
AVDD-supply = <&vcc_3v3_s3>;
- clock-names = "mclk";
clocks = <&cru I2S0_8CH_MCLKOUT>;
DVDD-supply = <&vcc_1v8_s3>;
HPVDD-supply = <&vcc_3v3_s3>;
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
index 9e39217b4afb..798d965760d4 100644
--- a/arch/arm64/include/asm/mman.h
+++ b/arch/arm64/include/asm/mman.h
@@ -6,6 +6,8 @@
#ifndef BUILD_VDSO
#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
#include <linux/types.h>
static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
@@ -31,19 +33,21 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot,
}
#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey)
-static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
+static inline unsigned long arch_calc_vm_flag_bits(struct file *file,
+ unsigned long flags)
{
/*
* Only allow MTE on anonymous mappings as these are guaranteed to be
* backed by tags-capable memory. The vm_flags may be overridden by a
* filesystem supporting MTE (RAM-based).
*/
- if (system_supports_mte() && (flags & MAP_ANONYMOUS))
+ if (system_supports_mte() &&
+ ((flags & MAP_ANONYMOUS) || shmem_file(file)))
return VM_MTE_ALLOWED;
return 0;
}
-#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
+#define arch_calc_vm_flag_bits(file, flags) arch_calc_vm_flag_bits(file, flags)
static inline bool arch_validate_prot(unsigned long prot,
unsigned long addr __always_unused)
diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index 5fc3af9f8f29..341174bf9106 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -26,10 +26,6 @@ void update_freq_counters_refs(void);
#define arch_scale_freq_invariant topology_scale_freq_invariant
#define arch_scale_freq_ref topology_get_freq_ref
-#ifdef CONFIG_ACPI_CPPC_LIB
-#define arch_init_invariance_cppc topology_init_cpu_capacity_cppc
-#endif
-
/* Replace task scheduler's default cpu-invariant accounting */
#define arch_scale_cpu_capacity topology_get_cpu_scale
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 77006df20a75..6d21971ae559 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1367,6 +1367,7 @@ static void sve_init_regs(void)
} else {
fpsimd_to_sve(current);
current->thread.fp_type = FP_STATE_SVE;
+ fpsimd_flush_task_state(current);
}
}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 561986947530..c7d311d8b92a 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -19,6 +19,7 @@
#include <linux/ratelimit.h>
#include <linux/rseq.h>
#include <linux/syscalls.h>
+#include <linux/pkeys.h>
#include <asm/daifflags.h>
#include <asm/debug-monitors.h>
@@ -66,10 +67,63 @@ struct rt_sigframe_user_layout {
unsigned long end_offset;
};
+/*
+ * Holds any EL0-controlled state that influences unprivileged memory accesses.
+ * This includes both accesses done in userspace and uaccess done in the kernel.
+ *
+ * This state needs to be carefully managed to ensure that it doesn't cause
+ * uaccess to fail when setting up the signal frame, and the signal handler
+ * itself also expects a well-defined state when entered.
+ */
+struct user_access_state {
+ u64 por_el0;
+};
+
#define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16)
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
+/*
+ * Save the user access state into ua_state and reset it to disable any
+ * restrictions.
+ */
+static void save_reset_user_access_state(struct user_access_state *ua_state)
+{
+ if (system_supports_poe()) {
+ u64 por_enable_all = 0;
+
+ for (int pkey = 0; pkey < arch_max_pkey(); pkey++)
+ por_enable_all |= POE_RXW << (pkey * POR_BITS_PER_PKEY);
+
+ ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0);
+ write_sysreg_s(por_enable_all, SYS_POR_EL0);
+ /* Ensure that any subsequent uaccess observes the updated value */
+ isb();
+ }
+}
+
+/*
+ * Set the user access state for invoking the signal handler.
+ *
+ * No uaccess should be done after that function is called.
+ */
+static void set_handler_user_access_state(void)
+{
+ if (system_supports_poe())
+ write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
+}
+
+/*
+ * Restore the user access state to the values saved in ua_state.
+ *
+ * No uaccess should be done after that function is called.
+ */
+static void restore_user_access_state(const struct user_access_state *ua_state)
+{
+ if (system_supports_poe())
+ write_sysreg_s(ua_state->por_el0, SYS_POR_EL0);
+}
+
static void init_user_layout(struct rt_sigframe_user_layout *user)
{
const size_t reserved_size =
@@ -261,18 +315,20 @@ static int restore_fpmr_context(struct user_ctxs *user)
return err;
}
-static int preserve_poe_context(struct poe_context __user *ctx)
+static int preserve_poe_context(struct poe_context __user *ctx,
+ const struct user_access_state *ua_state)
{
int err = 0;
__put_user_error(POE_MAGIC, &ctx->head.magic, err);
__put_user_error(sizeof(*ctx), &ctx->head.size, err);
- __put_user_error(read_sysreg_s(SYS_POR_EL0), &ctx->por_el0, err);
+ __put_user_error(ua_state->por_el0, &ctx->por_el0, err);
return err;
}
-static int restore_poe_context(struct user_ctxs *user)
+static int restore_poe_context(struct user_ctxs *user,
+ struct user_access_state *ua_state)
{
u64 por_el0;
int err = 0;
@@ -282,7 +338,7 @@ static int restore_poe_context(struct user_ctxs *user)
__get_user_error(por_el0, &(user->poe->por_el0), err);
if (!err)
- write_sysreg_s(por_el0, SYS_POR_EL0);
+ ua_state->por_el0 = por_el0;
return err;
}
@@ -850,7 +906,8 @@ invalid:
}
static int restore_sigframe(struct pt_regs *regs,
- struct rt_sigframe __user *sf)
+ struct rt_sigframe __user *sf,
+ struct user_access_state *ua_state)
{
sigset_t set;
int i, err;
@@ -899,7 +956,7 @@ static int restore_sigframe(struct pt_regs *regs,
err = restore_zt_context(&user);
if (err == 0 && system_supports_poe() && user.poe)
- err = restore_poe_context(&user);
+ err = restore_poe_context(&user, ua_state);
return err;
}
@@ -908,6 +965,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
{
struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame;
+ struct user_access_state ua_state;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
@@ -924,12 +982,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
if (!access_ok(frame, sizeof (*frame)))
goto badframe;
- if (restore_sigframe(regs, frame))
+ if (restore_sigframe(regs, frame, &ua_state))
goto badframe;
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
+ restore_user_access_state(&ua_state);
+
return regs->regs[0];
badframe:
@@ -1035,7 +1095,8 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
}
static int setup_sigframe(struct rt_sigframe_user_layout *user,
- struct pt_regs *regs, sigset_t *set)
+ struct pt_regs *regs, sigset_t *set,
+ const struct user_access_state *ua_state)
{
int i, err = 0;
struct rt_sigframe __user *sf = user->sigframe;
@@ -1097,10 +1158,9 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
struct poe_context __user *poe_ctx =
apply_user_offset(user, user->poe_offset);
- err |= preserve_poe_context(poe_ctx);
+ err |= preserve_poe_context(poe_ctx, ua_state);
}
-
/* ZA state if present */
if (system_supports_sme() && err == 0 && user->za_offset) {
struct za_context __user *za_ctx =
@@ -1237,9 +1297,6 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
sme_smstop();
}
- if (system_supports_poe())
- write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
-
if (ka->sa.sa_flags & SA_RESTORER)
sigtramp = ka->sa.sa_restorer;
else
@@ -1253,6 +1310,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
{
struct rt_sigframe_user_layout user;
struct rt_sigframe __user *frame;
+ struct user_access_state ua_state;
int err = 0;
fpsimd_signal_preserve_current_state();
@@ -1260,13 +1318,14 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
if (get_sigframe(&user, ksig, regs))
return 1;
+ save_reset_user_access_state(&ua_state);
frame = user.sigframe;
__put_user_error(0, &frame->uc.uc_flags, err);
__put_user_error(NULL, &frame->uc.uc_link, err);
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
- err |= setup_sigframe(&user, regs, set);
+ err |= setup_sigframe(&user, regs, set, &ua_state);
if (err == 0) {
setup_return(regs, &ksig->ka, &user, usig);
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
@@ -1276,6 +1335,11 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
}
}
+ if (err == 0)
+ set_handler_user_access_state();
+ else
+ restore_user_access_state(&ua_state);
+
return err;
}
diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S
index 487381164ff6..2def9d0dd3dd 100644
--- a/arch/arm64/kernel/smccc-call.S
+++ b/arch/arm64/kernel/smccc-call.S
@@ -7,48 +7,19 @@
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
-#include <asm/thread_info.h>
-
-/*
- * If we have SMCCC v1.3 and (as is likely) no SVE state in
- * the registers then set the SMCCC hint bit to say there's no
- * need to preserve it. Do this by directly adjusting the SMCCC
- * function value which is already stored in x0 ready to be called.
- */
-SYM_FUNC_START(__arm_smccc_sve_check)
-
- ldr_l x16, smccc_has_sve_hint
- cbz x16, 2f
-
- get_current_task x16
- ldr x16, [x16, #TSK_TI_FLAGS]
- tbnz x16, #TIF_FOREIGN_FPSTATE, 1f // Any live FP state?
- tbnz x16, #TIF_SVE, 2f // Does that state include SVE?
-
-1: orr x0, x0, ARM_SMCCC_1_3_SVE_HINT
-
-2: ret
-SYM_FUNC_END(__arm_smccc_sve_check)
-EXPORT_SYMBOL(__arm_smccc_sve_check)
.macro SMCCC instr
- stp x29, x30, [sp, #-16]!
- mov x29, sp
-alternative_if ARM64_SVE
- bl __arm_smccc_sve_check
-alternative_else_nop_endif
\instr #0
- ldr x4, [sp, #16]
+ ldr x4, [sp]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
- ldr x4, [sp, #24]
+ ldr x4, [sp, #8]
cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
-1: ldp x29, x30, [sp], #16
- ret
+1: ret
.endm
/*
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 8bbd0b20136a..5db82bfc9dc1 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -2220,7 +2220,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
emit(A64_STR64I(A64_R(20), A64_SP, regs_off + 8), ctx);
if (flags & BPF_TRAMP_F_CALL_ORIG) {
- emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
+ /* for the first pass, assume the worst case */
+ if (!ctx->image)
+ ctx->idx += 4;
+ else
+ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
emit_call((const u64)__bpf_tramp_enter, ctx);
}
@@ -2264,7 +2268,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
if (flags & BPF_TRAMP_F_CALL_ORIG) {
im->ip_epilogue = ctx->ro_image + ctx->idx;
- emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
+ /* for the first pass, assume the worst case */
+ if (!ctx->image)
+ ctx->idx += 4;
+ else
+ emit_a64_mov_i64(A64_R(0), (const u64)im, ctx);
emit_call((const u64)__bpf_tramp_exit, ctx);
}
diff --git a/arch/loongarch/include/asm/kasan.h b/arch/loongarch/include/asm/kasan.h
index c6bce5fbff57..7f52bd31b9d4 100644
--- a/arch/loongarch/include/asm/kasan.h
+++ b/arch/loongarch/include/asm/kasan.h
@@ -25,6 +25,7 @@
/* 64-bit segment value. */
#define XKPRANGE_UC_SEG (0x8000)
#define XKPRANGE_CC_SEG (0x9000)
+#define XKPRANGE_WC_SEG (0xa000)
#define XKVRANGE_VC_SEG (0xffff)
/* Cached */
@@ -41,20 +42,28 @@
#define XKPRANGE_UC_SHADOW_SIZE (XKPRANGE_UC_SIZE >> KASAN_SHADOW_SCALE_SHIFT)
#define XKPRANGE_UC_SHADOW_END (XKPRANGE_UC_KASAN_OFFSET + XKPRANGE_UC_SHADOW_SIZE)
+/* WriteCombine */
+#define XKPRANGE_WC_START WRITECOMBINE_BASE
+#define XKPRANGE_WC_SIZE XRANGE_SIZE
+#define XKPRANGE_WC_KASAN_OFFSET XKPRANGE_UC_SHADOW_END
+#define XKPRANGE_WC_SHADOW_SIZE (XKPRANGE_WC_SIZE >> KASAN_SHADOW_SCALE_SHIFT)
+#define XKPRANGE_WC_SHADOW_END (XKPRANGE_WC_KASAN_OFFSET + XKPRANGE_WC_SHADOW_SIZE)
+
/* VMALLOC (Cached or UnCached) */
#define XKVRANGE_VC_START MODULES_VADDR
#define XKVRANGE_VC_SIZE round_up(KFENCE_AREA_END - MODULES_VADDR + 1, PGDIR_SIZE)
-#define XKVRANGE_VC_KASAN_OFFSET XKPRANGE_UC_SHADOW_END
+#define XKVRANGE_VC_KASAN_OFFSET XKPRANGE_WC_SHADOW_END
#define XKVRANGE_VC_SHADOW_SIZE (XKVRANGE_VC_SIZE >> KASAN_SHADOW_SCALE_SHIFT)
#define XKVRANGE_VC_SHADOW_END (XKVRANGE_VC_KASAN_OFFSET + XKVRANGE_VC_SHADOW_SIZE)
/* KAsan shadow memory start right after vmalloc. */
#define KASAN_SHADOW_START round_up(KFENCE_AREA_END, PGDIR_SIZE)
#define KASAN_SHADOW_SIZE (XKVRANGE_VC_SHADOW_END - XKPRANGE_CC_KASAN_OFFSET)
-#define KASAN_SHADOW_END round_up(KASAN_SHADOW_START + KASAN_SHADOW_SIZE, PGDIR_SIZE)
+#define KASAN_SHADOW_END (round_up(KASAN_SHADOW_START + KASAN_SHADOW_SIZE, PGDIR_SIZE) - 1)
#define XKPRANGE_CC_SHADOW_OFFSET (KASAN_SHADOW_START + XKPRANGE_CC_KASAN_OFFSET)
#define XKPRANGE_UC_SHADOW_OFFSET (KASAN_SHADOW_START + XKPRANGE_UC_KASAN_OFFSET)
+#define XKPRANGE_WC_SHADOW_OFFSET (KASAN_SHADOW_START + XKPRANGE_WC_KASAN_OFFSET)
#define XKVRANGE_VC_SHADOW_OFFSET (KASAN_SHADOW_START + XKVRANGE_VC_KASAN_OFFSET)
extern bool kasan_early_stage;
diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
index e85df33f11c7..8f21567a3188 100644
--- a/arch/loongarch/include/asm/page.h
+++ b/arch/loongarch/include/asm/page.h
@@ -113,10 +113,7 @@ struct page *tlb_virt_to_page(unsigned long kaddr);
extern int __virt_addr_valid(volatile void *kaddr);
#define virt_addr_valid(kaddr) __virt_addr_valid((volatile void *)(kaddr))
-#define VM_DATA_DEFAULT_FLAGS \
- (VM_READ | VM_WRITE | \
- ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_TSK_EXEC
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index f1a74b80f22c..382a09a7152c 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -58,48 +58,48 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
return ioremap_cache(phys, size);
}
-static int cpu_enumerated = 0;
-
#ifdef CONFIG_SMP
-static int set_processor_mask(u32 id, u32 flags)
+static int set_processor_mask(u32 id, u32 pass)
{
- int nr_cpus;
- int cpu, cpuid = id;
-
- if (!cpu_enumerated)
- nr_cpus = NR_CPUS;
- else
- nr_cpus = nr_cpu_ids;
+ int cpu = -1, cpuid = id;
- if (num_processors >= nr_cpus) {
+ if (num_processors >= NR_CPUS) {
pr_warn(PREFIX "nr_cpus limit of %i reached."
- " processor 0x%x ignored.\n", nr_cpus, cpuid);
+ " processor 0x%x ignored.\n", NR_CPUS, cpuid);
return -ENODEV;
}
+
if (cpuid == loongson_sysconf.boot_cpu_id)
cpu = 0;
- else
- cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
-
- if (!cpu_enumerated)
- set_cpu_possible(cpu, true);
- if (flags & ACPI_MADT_ENABLED) {
+ switch (pass) {
+ case 1: /* Pass 1 handle enabled processors */
+ if (cpu < 0)
+ cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
num_processors++;
set_cpu_present(cpu, true);
- __cpu_number_map[cpuid] = cpu;
- __cpu_logical_map[cpu] = cpuid;
- } else
+ break;
+ case 2: /* Pass 2 handle disabled processors */
+ if (cpu < 0)
+ cpu = find_first_zero_bit(cpumask_bits(cpu_possible_mask), NR_CPUS);
disabled_cpus++;
+ break;
+ default:
+ return cpu;
+ }
+
+ set_cpu_possible(cpu, true);
+ __cpu_number_map[cpuid] = cpu;
+ __cpu_logical_map[cpu] = cpuid;
return cpu;
}
#endif
static int __init
-acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long end)
+acpi_parse_p1_processor(union acpi_subtable_headers *header, const unsigned long end)
{
struct acpi_madt_core_pic *processor = NULL;
@@ -110,13 +110,30 @@ acpi_parse_processor(union acpi_subtable_headers *header, const unsigned long en
acpi_table_print_madt_entry(&header->common);
#ifdef CONFIG_SMP
acpi_core_pic[processor->core_id] = *processor;
- set_processor_mask(processor->core_id, processor->flags);
+ if (processor->flags & ACPI_MADT_ENABLED)
+ set_processor_mask(processor->core_id, 1);
#endif
return 0;
}
static int __init
+acpi_parse_p2_processor(union acpi_subtable_headers *header, const unsigned long end)
+{
+ struct acpi_madt_core_pic *processor = NULL;
+
+ processor = (struct acpi_madt_core_pic *)header;
+ if (BAD_MADT_ENTRY(processor, end))
+ return -EINVAL;
+
+#ifdef CONFIG_SMP
+ if (!(processor->flags & ACPI_MADT_ENABLED))
+ set_processor_mask(processor->core_id, 2);
+#endif
+
+ return 0;
+}
+static int __init
acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long end)
{
static int core = 0;
@@ -143,12 +160,14 @@ static void __init acpi_process_madt(void)
}
#endif
acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC,
- acpi_parse_processor, MAX_CORE_PIC);
+ acpi_parse_p1_processor, MAX_CORE_PIC);
+
+ acpi_table_parse_madt(ACPI_MADT_TYPE_CORE_PIC,
+ acpi_parse_p2_processor, MAX_CORE_PIC);
acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
acpi_parse_eio_master, MAX_IO_PICS);
- cpu_enumerated = 1;
loongson_sysconf.nr_cpus = num_processors;
}
@@ -310,6 +329,10 @@ static int __ref acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
int nid;
nid = acpi_get_node(handle);
+
+ if (nid != NUMA_NO_NODE)
+ nid = early_cpu_to_node(cpu);
+
if (nid != NUMA_NO_NODE) {
set_cpuid_to_node(physid, nid);
node_set(nid, numa_nodes_parsed);
@@ -324,12 +347,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu
{
int cpu;
- cpu = set_processor_mask(physid, ACPI_MADT_ENABLED);
- if (cpu < 0) {
+ cpu = cpu_number_map(physid);
+ if (cpu < 0 || cpu >= nr_cpu_ids) {
pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
- return cpu;
+ return -ERANGE;
}
+ num_processors++;
+ set_cpu_present(cpu, true);
acpi_map_cpu2node(handle, cpu, physid);
*pcpu = cpu;
diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
index a5fc61f8b348..e5a39bbad078 100644
--- a/arch/loongarch/kernel/paravirt.c
+++ b/arch/loongarch/kernel/paravirt.c
@@ -51,11 +51,18 @@ static u64 paravt_steal_clock(int cpu)
}
#ifdef CONFIG_SMP
+static struct smp_ops native_ops;
+
static void pv_send_ipi_single(int cpu, unsigned int action)
{
int min, old;
irq_cpustat_t *info = &per_cpu(irq_stat, cpu);
+ if (unlikely(action == ACTION_BOOT_CPU)) {
+ native_ops.send_ipi_single(cpu, action);
+ return;
+ }
+
old = atomic_fetch_or(BIT(action), &info->message);
if (old)
return;
@@ -75,6 +82,11 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action)
if (cpumask_empty(mask))
return;
+ if (unlikely(action == ACTION_BOOT_CPU)) {
+ native_ops.send_ipi_mask(mask, action);
+ return;
+ }
+
action = BIT(action);
for_each_cpu(i, mask) {
info = &per_cpu(irq_stat, i);
@@ -147,6 +159,8 @@ static void pv_init_ipi(void)
{
int r, swi;
+ /* Init native ipi irq for ACTION_BOOT_CPU */
+ native_ops.init_ipi();
swi = get_percpu_irq(INT_SWI0);
if (swi < 0)
panic("SWI0 IRQ mapping failed\n");
@@ -193,6 +207,7 @@ int __init pv_ipi_init(void)
return 0;
#ifdef CONFIG_SMP
+ native_ops = mp_ops;
mp_ops.init_ipi = pv_init_ipi;
mp_ops.send_ipi_single = pv_send_ipi_single;
mp_ops.send_ipi_mask = pv_send_ipi_mask;
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 9afc2d8b3414..5d59e9ce2772 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -302,7 +302,7 @@ static void __init fdt_smp_setup(void)
__cpu_number_map[cpuid] = cpu;
__cpu_logical_map[cpu] = cpuid;
- early_numa_add_cpu(cpu, 0);
+ early_numa_add_cpu(cpuid, 0);
set_cpuid_to_node(cpuid, 0);
}
@@ -331,11 +331,11 @@ void __init loongson_prepare_cpus(unsigned int max_cpus)
int i = 0;
parse_acpi_topology();
+ cpu_data[0].global_id = cpu_logical_map(0);
for (i = 0; i < loongson_sysconf.nr_cpus; i++) {
set_cpu_present(i, true);
csr_mail_send(0, __cpu_logical_map[i], 0);
- cpu_data[i].global_id = __cpu_logical_map[i];
}
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
@@ -380,6 +380,7 @@ void loongson_init_secondary(void)
cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core :
cpu_logical_map(cpu) % loongson_sysconf.cores_per_package;
+ cpu_data[cpu].global_id = cpu_logical_map(cpu);
}
void loongson_smp_finish(void)
diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c
index 427d6b1aec09..d2681272d8f0 100644
--- a/arch/loongarch/mm/kasan_init.c
+++ b/arch/loongarch/mm/kasan_init.c
@@ -13,6 +13,13 @@
static pgd_t kasan_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
+#ifdef __PAGETABLE_P4D_FOLDED
+#define __pgd_none(early, pgd) (0)
+#else
+#define __pgd_none(early, pgd) (early ? (pgd_val(pgd) == 0) : \
+(__pa(pgd_val(pgd)) == (unsigned long)__pa(kasan_early_shadow_p4d)))
+#endif
+
#ifdef __PAGETABLE_PUD_FOLDED
#define __p4d_none(early, p4d) (0)
#else
@@ -55,6 +62,9 @@ void *kasan_mem_to_shadow(const void *addr)
case XKPRANGE_UC_SEG:
offset = XKPRANGE_UC_SHADOW_OFFSET;
break;
+ case XKPRANGE_WC_SEG:
+ offset = XKPRANGE_WC_SHADOW_OFFSET;
+ break;
case XKVRANGE_VC_SEG:
offset = XKVRANGE_VC_SHADOW_OFFSET;
break;
@@ -79,6 +89,8 @@ const void *kasan_shadow_to_mem(const void *shadow_addr)
if (addr >= XKVRANGE_VC_SHADOW_OFFSET)
return (void *)(((addr - XKVRANGE_VC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKVRANGE_VC_START);
+ else if (addr >= XKPRANGE_WC_SHADOW_OFFSET)
+ return (void *)(((addr - XKPRANGE_WC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_WC_START);
else if (addr >= XKPRANGE_UC_SHADOW_OFFSET)
return (void *)(((addr - XKPRANGE_UC_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT) + XKPRANGE_UC_START);
else if (addr >= XKPRANGE_CC_SHADOW_OFFSET)
@@ -142,6 +154,19 @@ static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node,
return pud_offset(p4dp, addr);
}
+static p4d_t *__init kasan_p4d_offset(pgd_t *pgdp, unsigned long addr, int node, bool early)
+{
+ if (__pgd_none(early, pgdp_get(pgdp))) {
+ phys_addr_t p4d_phys = early ?
+ __pa_symbol(kasan_early_shadow_p4d) : kasan_alloc_zeroed_page(node);
+ if (!early)
+ memcpy(__va(p4d_phys), kasan_early_shadow_p4d, sizeof(kasan_early_shadow_p4d));
+ pgd_populate(&init_mm, pgdp, (p4d_t *)__va(p4d_phys));
+ }
+
+ return p4d_offset(pgdp, addr);
+}
+
static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
unsigned long end, int node, bool early)
{
@@ -178,19 +203,19 @@ static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
do {
next = pud_addr_end(addr, end);
kasan_pmd_populate(pudp, addr, next, node, early);
- } while (pudp++, addr = next, addr != end);
+ } while (pudp++, addr = next, addr != end && __pud_none(early, READ_ONCE(*pudp)));
}
static void __init kasan_p4d_populate(pgd_t *pgdp, unsigned long addr,
unsigned long end, int node, bool early)
{
unsigned long next;
- p4d_t *p4dp = p4d_offset(pgdp, addr);
+ p4d_t *p4dp = kasan_p4d_offset(pgdp, addr, node, early);
do {
next = p4d_addr_end(addr, end);
kasan_pud_populate(p4dp, addr, next, node, early);
- } while (p4dp++, addr = next, addr != end);
+ } while (p4dp++, addr = next, addr != end && __p4d_none(early, READ_ONCE(*p4dp)));
}
static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
@@ -218,7 +243,7 @@ static void __init kasan_map_populate(unsigned long start, unsigned long end,
asmlinkage void __init kasan_early_init(void)
{
BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_START, PGDIR_SIZE));
- BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE));
+ BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END + 1, PGDIR_SIZE));
}
static inline void kasan_set_pgd(pgd_t *pgdp, pgd_t pgdval)
@@ -233,7 +258,7 @@ static void __init clear_pgds(unsigned long start, unsigned long end)
* swapper_pg_dir. pgd_clear() can't be used
* here because it's nop on 2,3-level pagetable setups
*/
- for (; start < end; start += PGDIR_SIZE)
+ for (; start < end; start = pgd_addr_end(start, end))
kasan_set_pgd((pgd_t *)pgd_offset_k(start), __pgd(0));
}
@@ -243,6 +268,17 @@ void __init kasan_init(void)
phys_addr_t pa_start, pa_end;
/*
+ * If PGDIR_SIZE is too large for cpu_vabits, KASAN_SHADOW_END will
+ * overflow UINTPTR_MAX and then looks like a user space address.
+ * For example, PGDIR_SIZE of CONFIG_4KB_4LEVEL is 2^39, which is too
+ * large for Loongson-2K series whose cpu_vabits = 39.
+ */
+ if (KASAN_SHADOW_END < vm_map_base) {
+ pr_warn("PGDIR_SIZE too large for cpu_vabits, KernelAddressSanitizer disabled.\n");
+ return;
+ }
+
+ /*
* PGD was populated as invalid_pmd_table or invalid_pud_table
* in pagetable_init() which depends on how many levels of page
* table you are using, but we had to clean the gpd of kasan
diff --git a/arch/mips/kernel/cmpxchg.c b/arch/mips/kernel/cmpxchg.c
index e974a4954df8..c371def2302d 100644
--- a/arch/mips/kernel/cmpxchg.c
+++ b/arch/mips/kernel/cmpxchg.c
@@ -102,3 +102,4 @@ unsigned long __cmpxchg_small(volatile void *ptr, unsigned long old,
return old;
}
}
+EXPORT_SYMBOL(__cmpxchg_small);
diff --git a/arch/parisc/include/asm/mman.h b/arch/parisc/include/asm/mman.h
index 89b6beeda0b8..663f587dc789 100644
--- a/arch/parisc/include/asm/mman.h
+++ b/arch/parisc/include/asm/mman.h
@@ -2,6 +2,7 @@
#ifndef __ASM_MMAN_H__
#define __ASM_MMAN_H__
+#include <linux/fs.h>
#include <uapi/asm/mman.h>
/* PARISC cannot allow mdwe as it needs writable stacks */
@@ -11,7 +12,7 @@ static inline bool arch_memory_deny_write_exec_supported(void)
}
#define arch_memory_deny_write_exec_supported arch_memory_deny_write_exec_supported
-static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
+static inline unsigned long arch_calc_vm_flag_bits(struct file *file, unsigned long flags)
{
/*
* The stack on parisc grows upwards, so if userspace requests memory
@@ -23,6 +24,6 @@ static inline unsigned long arch_calc_vm_flag_bits(unsigned long flags)
return 0;
}
-#define arch_calc_vm_flag_bits(flags) arch_calc_vm_flag_bits(flags)
+#define arch_calc_vm_flag_bits(file, flags) arch_calc_vm_flag_bits(file, flags)
#endif /* __ASM_MMAN_H__ */
diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c
index 4818f3db84a5..59d8c15d81bd 100644
--- a/arch/parisc/lib/checksum.c
+++ b/arch/parisc/lib/checksum.c
@@ -25,15 +25,6 @@
: "=r"(_t) \
: "r"(_r), "0"(_t));
-static inline unsigned short from32to16(unsigned int x)
-{
- /* 32 bits --> 16 bits + carry */
- x = (x & 0xffff) + (x >> 16);
- /* 16 bits + carry --> 16 bits including carry */
- x = (x & 0xffff) + (x >> 16);
- return (unsigned short)x;
-}
-
static inline unsigned int do_csum(const unsigned char * buff, int len)
{
int odd, count;
@@ -85,7 +76,7 @@ static inline unsigned int do_csum(const unsigned char * buff, int len)
}
if (len & 1)
result += le16_to_cpu(*buff);
- result = from32to16(result);
+ result = csum_from32to16(result);
if (odd)
result = swab16(result);
out:
@@ -102,7 +93,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum)
{
unsigned int result = do_csum(buff, len);
addc(result, sum);
- return (__force __wsum)from32to16(result);
+ return (__force __wsum)csum_from32to16(result);
}
EXPORT_SYMBOL(csum_partial);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index ba0492f9de65..ad8dc4ccdaab 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -4898,6 +4898,18 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit,
BOOK3S_INTERRUPT_EXTERNAL, 0);
else
lpcr |= LPCR_MER;
+ } else {
+ /*
+ * L1's copy of L2's LPCR (vcpu->arch.vcore->lpcr) can get its MER bit
+ * unexpectedly set - for e.g. during NMI handling when all register
+ * states are synchronized from L0 to L1. L1 needs to inform L0 about
+ * MER=1 only when there are pending external interrupts.
+ * In the above if check, MER bit is set if there are pending
+ * external interrupts. Hence, explicity mask off MER bit
+ * here as otherwise it may generate spurious interrupts in L2 KVM
+ * causing an endless loop, which results in L2 guest getting hung.
+ */
+ lpcr &= ~LPCR_MER;
}
} else if (vcpu->arch.pending_exceptions ||
vcpu->arch.doorbell_request ||
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 62545946ecf4..f4c570538d55 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -177,7 +177,7 @@ config RISCV
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RETHOOK if !XIP_KERNEL
select HAVE_RSEQ
- select HAVE_RUST if RUSTC_SUPPORTS_RISCV
+ select HAVE_RUST if RUSTC_SUPPORTS_RISCV && CC_IS_CLANG
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
select HAVE_STACKPROTECTOR
diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
index 4e5fa6591623..e62ac51ac55a 100644
--- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi
@@ -112,7 +112,7 @@
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
- snps,nr-gpios = <32>;
+ ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -134,7 +134,7 @@
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
- snps,nr-gpios = <32>;
+ ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -156,7 +156,7 @@
compatible = "snps,dw-apb-gpio-port";
gpio-controller;
#gpio-cells = <2>;
- snps,nr-gpios = <32>;
+ ngpios = <32>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
index c7771b3b6475..d6c55f1cc96a 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
@@ -128,7 +128,6 @@
assigned-clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>,
<&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>;
assigned-clock-rates = <49500000>, <198000000>;
- status = "okay";
ports {
#address-cells = <1>;
@@ -151,7 +150,6 @@
&csi2rx {
assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>;
assigned-clock-rates = <297000000>;
- status = "okay";
ports {
#address-cells = <1>;
diff --git a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
index b720cdd15ed6..8e39fdc73ecb 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
+++ b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
@@ -44,8 +44,7 @@
};
&phy0 {
- rx-internal-delay-ps = <1900>;
- tx-internal-delay-ps = <1500>;
+ rx-internal-delay-ps = <1500>;
motorcomm,rx-clk-drv-microamp = <2910>;
motorcomm,rx-data-drv-microamp = <2910>;
motorcomm,tx-clk-adj-enabled;
diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile
index 8a2739485123..f0da9d7b39c3 100644
--- a/arch/riscv/errata/Makefile
+++ b/arch/riscv/errata/Makefile
@@ -2,6 +2,12 @@ ifdef CONFIG_RELOCATABLE
KBUILD_CFLAGS += -fno-pie
endif
+ifdef CONFIG_RISCV_ALTERNATIVE_EARLY
+ifdef CONFIG_FORTIFY_SOURCE
+KBUILD_CFLAGS += -D__NO_FORTIFY
+endif
+endif
+
obj-$(CONFIG_ERRATA_ANDES) += andes/
obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
obj-$(CONFIG_ERRATA_THEAD) += thead/
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 7f88cc4931f5..69dc8aaab3fb 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -36,6 +36,11 @@ KASAN_SANITIZE_alternative.o := n
KASAN_SANITIZE_cpufeature.o := n
KASAN_SANITIZE_sbi_ecall.o := n
endif
+ifdef CONFIG_FORTIFY_SOURCE
+CFLAGS_alternative.o += -D__NO_FORTIFY
+CFLAGS_cpufeature.o += -D__NO_FORTIFY
+CFLAGS_sbi_ecall.o += -D__NO_FORTIFY
+endif
endif
extra-y += vmlinux.lds
diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
index 6e0d333f57e5..2fd29695a788 100644
--- a/arch/riscv/kernel/acpi.c
+++ b/arch/riscv/kernel/acpi.c
@@ -210,7 +210,7 @@ void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
if (!size)
return NULL;
- return early_ioremap(phys, size);
+ return early_memremap(phys, size);
}
void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
@@ -218,7 +218,7 @@ void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
if (!map || !size)
return;
- early_iounmap(map, size);
+ early_memunmap(map, size);
}
void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index e94180ba432f..c2f3129a8e5c 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -4,8 +4,6 @@
* Copyright (C) 2017 SiFive
*/
-#define GENERATING_ASM_OFFSETS
-
#include <linux/kbuild.h>
#include <linux/mm.h>
#include <linux/sched.h>
diff --git a/arch/riscv/kernel/cacheinfo.c b/arch/riscv/kernel/cacheinfo.c
index b320b1d9aa01..2d40736fc37c 100644
--- a/arch/riscv/kernel/cacheinfo.c
+++ b/arch/riscv/kernel/cacheinfo.c
@@ -80,8 +80,7 @@ int populate_cache_leaves(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *this_leaf = this_cpu_ci->info_list;
- struct device_node *np = of_cpu_device_node_get(cpu);
- struct device_node *prev = NULL;
+ struct device_node *np, *prev;
int levels = 1, level = 1;
if (!acpi_disabled) {
@@ -105,6 +104,10 @@ int populate_cache_leaves(unsigned int cpu)
return 0;
}
+ np = of_cpu_device_node_get(cpu);
+ if (!np)
+ return -ENOENT;
+
if (of_property_read_bool(np, "cache-size"))
ci_leaf_init(this_leaf++, CACHE_TYPE_UNIFIED, level);
if (of_property_read_bool(np, "i-cache-size"))
diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c
index 28b58fc5ad19..a1e38ecfc8be 100644
--- a/arch/riscv/kernel/cpu-hotplug.c
+++ b/arch/riscv/kernel/cpu-hotplug.c
@@ -58,7 +58,7 @@ void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
if (cpu_ops->cpu_is_stopped)
ret = cpu_ops->cpu_is_stopped(cpu);
if (ret)
- pr_warn("CPU%d may not have stopped: %d\n", cpu, ret);
+ pr_warn("CPU%u may not have stopped: %d\n", cpu, ret);
}
/*
diff --git a/arch/riscv/kernel/efi-header.S b/arch/riscv/kernel/efi-header.S
index 515b2dfbca75..c5f17c2710b5 100644
--- a/arch/riscv/kernel/efi-header.S
+++ b/arch/riscv/kernel/efi-header.S
@@ -64,7 +64,7 @@ extra_header_fields:
.long efi_header_end - _start // SizeOfHeaders
.long 0 // CheckSum
.short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem
- .short 0 // DllCharacteristics
+ .short IMAGE_DLL_CHARACTERISTICS_NX_COMPAT // DllCharacteristics
.quad 0 // SizeOfStackReserve
.quad 0 // SizeOfStackCommit
.quad 0 // SizeOfHeapReserve
diff --git a/arch/riscv/kernel/pi/Makefile b/arch/riscv/kernel/pi/Makefile
index d5bf1bc7de62..81d69d45c06c 100644
--- a/arch/riscv/kernel/pi/Makefile
+++ b/arch/riscv/kernel/pi/Makefile
@@ -16,8 +16,12 @@ KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
KBUILD_CFLAGS += -mcmodel=medany
CFLAGS_cmdline_early.o += -D__NO_FORTIFY
-CFLAGS_lib-fdt_ro.o += -D__NO_FORTIFY
CFLAGS_fdt_early.o += -D__NO_FORTIFY
+# lib/string.c already defines __NO_FORTIFY
+CFLAGS_ctype.o += -D__NO_FORTIFY
+CFLAGS_lib-fdt.o += -D__NO_FORTIFY
+CFLAGS_lib-fdt_ro.o += -D__NO_FORTIFY
+CFLAGS_archrandom_early.o += -D__NO_FORTIFY
$(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \
--remove-section=.note.gnu.property \
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index d4fd8af7aaf5..1b9867136b61 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -136,8 +136,6 @@
#define REG_PTR(insn, pos, regs) \
(ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))
-#define GET_RM(insn) (((insn) >> 12) & 7)
-
#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs))
#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs))
#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs))
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile
index 960feb1526ca..3f1c4b2d0b06 100644
--- a/arch/riscv/kernel/vdso/Makefile
+++ b/arch/riscv/kernel/vdso/Makefile
@@ -18,6 +18,7 @@ obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o
ccflags-y := -fno-stack-protector
ccflags-y += -DDISABLE_BRANCH_PROFILING
+ccflags-y += -fno-builtin
ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y)
diff --git a/arch/s390/include/asm/stp.h b/arch/s390/include/asm/stp.h
index 4d74d7e33340..827cb208de86 100644
--- a/arch/s390/include/asm/stp.h
+++ b/arch/s390/include/asm/stp.h
@@ -94,5 +94,6 @@ struct stp_stzi {
int stp_sync_check(void);
int stp_island_check(void);
void stp_queue_work(void);
+bool stp_enabled(void);
#endif /* __S390_STP_H */
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 640901f2fbc3..642fd303ce01 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -93,6 +93,7 @@ extern unsigned char ptff_function_mask[16];
#define PTFF_QAF 0x00 /* query available functions */
#define PTFF_QTO 0x01 /* query tod offset */
#define PTFF_QSI 0x02 /* query steering information */
+#define PTFF_QPT 0x03 /* query physical clock */
#define PTFF_QUI 0x04 /* query UTC information */
#define PTFF_ATO 0x40 /* adjust tod offset */
#define PTFF_STO 0x41 /* set tod offset */
@@ -250,6 +251,11 @@ static __always_inline unsigned long tod_to_ns(unsigned long todval)
return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9);
}
+static __always_inline u128 eitod_to_ns(u128 todval)
+{
+ return (todval * 125) >> 9;
+}
+
/**
* tod_after - compare two 64 bit TOD values
* @a: first 64 bit TOD timestamp
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index b713effe0579..cc60b16a7dd0 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -255,6 +255,7 @@ static struct clocksource clocksource_tod = {
.shift = 24,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.vdso_clock_mode = VDSO_CLOCKMODE_TOD,
+ .id = CSID_S390_TOD,
};
struct clocksource * __init clocksource_default_clock(void)
@@ -468,6 +469,12 @@ static void __init stp_reset(void)
}
}
+bool stp_enabled(void)
+{
+ return test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online;
+}
+EXPORT_SYMBOL(stp_enabled);
+
static void stp_timeout(struct timer_list *unused)
{
queue_work(time_sync_wq, &stp_work);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2852fcd82cbd..16354dfa6d96 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2257,6 +2257,7 @@ config RANDOMIZE_MEMORY_PHYSICAL_PADDING
config ADDRESS_MASKING
bool "Linear Address Masking support"
depends on X86_64
+ depends on COMPILE_TEST || !CPU_MITIGATIONS # wait for LASS
help
Linear Address Masking (LAM) modifies the checking that is applied
to 64-bit linear addresses, allowing software to use of the
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index 6f3b6aef47ba..d0caac26533f 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -116,7 +116,10 @@ static inline bool amd_gart_present(void)
#define amd_nb_num(x) 0
#define amd_nb_has_feature(x) false
-#define node_to_amd_nb(x) NULL
+static inline struct amd_northbridge *node_to_amd_nb(int node)
+{
+ return NULL;
+}
#define amd_gart_present(x) false
#endif
diff --git a/arch/x86/include/asm/runtime-const.h b/arch/x86/include/asm/runtime-const.h
index 24e3a53ca255..6652ebddfd02 100644
--- a/arch/x86/include/asm/runtime-const.h
+++ b/arch/x86/include/asm/runtime-const.h
@@ -6,7 +6,7 @@
typeof(sym) __ret; \
asm_inline("mov %1,%0\n1:\n" \
".pushsection runtime_ptr_" #sym ",\"a\"\n\t" \
- ".long 1b - %c2 - .\n\t" \
+ ".long 1b - %c2 - .\n" \
".popsection" \
:"=r" (__ret) \
:"i" ((unsigned long)0x0123456789abcdefull), \
@@ -20,7 +20,7 @@
typeof(0u+(val)) __ret = (val); \
asm_inline("shrl $12,%k0\n1:\n" \
".pushsection runtime_shift_" #sym ",\"a\"\n\t" \
- ".long 1b - 1 - .\n\t" \
+ ".long 1b - 1 - .\n" \
".popsection" \
:"+r" (__ret)); \
__ret; })
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index aef70336d624..92f3664dd933 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -305,9 +305,4 @@ static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled
extern void arch_scale_freq_tick(void);
#define arch_scale_freq_tick arch_scale_freq_tick
-#ifdef CONFIG_ACPI_CPPC_LIB
-void init_freq_invariance_cppc(void);
-#define arch_init_invariance_cppc init_freq_invariance_cppc
-#endif
-
#endif /* _ASM_X86_TOPOLOGY_H */
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index afce8ee5d7b7..b0a887209400 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -12,6 +12,13 @@
#include <asm/cpufeatures.h>
#include <asm/page.h>
#include <asm/percpu.h>
+#include <asm/runtime-const.h>
+
+/*
+ * Virtual variable: there's no actual backing store for this,
+ * it can purely be used as 'runtime_const_ptr(USER_PTR_MAX)'
+ */
+extern unsigned long USER_PTR_MAX;
#ifdef CONFIG_ADDRESS_MASKING
/*
@@ -46,19 +53,24 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
#endif
-/*
- * The virtual address space space is logically divided into a kernel
- * half and a user half. When cast to a signed type, user pointers
- * are positive and kernel pointers are negative.
- */
-#define valid_user_address(x) ((__force long)(x) >= 0)
+#define valid_user_address(x) \
+ ((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
/*
* Masking the user address is an alternative to a conditional
* user_access_begin that can avoid the fencing. This only works
* for dense accesses starting at the address.
*/
-#define mask_user_address(x) ((typeof(x))((long)(x)|((long)(x)>>63)))
+static inline void __user *mask_user_address(const void __user *ptr)
+{
+ unsigned long mask;
+ asm("cmp %1,%0\n\t"
+ "sbb %0,%0"
+ :"=r" (mask)
+ :"r" (ptr),
+ "0" (runtime_const_ptr(USER_PTR_MAX)));
+ return (__force void __user *)(mask | (__force unsigned long)ptr);
+}
#define masked_user_access_begin(x) ({ \
__auto_type __masked_ptr = (x); \
__masked_ptr = mask_user_address(__masked_ptr); \
@@ -69,23 +81,16 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
* arbitrary values in those bits rather then masking them off.
*
* Enforce two rules:
- * 1. 'ptr' must be in the user half of the address space
+ * 1. 'ptr' must be in the user part of the address space
* 2. 'ptr+size' must not overflow into kernel addresses
*
- * Note that addresses around the sign change are not valid addresses,
- * and will GP-fault even with LAM enabled if the sign bit is set (see
- * "CR3.LAM_SUP" that can narrow the canonicality check if we ever
- * enable it, but not remove it entirely).
- *
- * So the "overflow into kernel addresses" does not imply some sudden
- * exact boundary at the sign bit, and we can allow a lot of slop on the
- * size check.
+ * Note that we always have at least one guard page between the
+ * max user address and the non-canonical gap, allowing us to
+ * ignore small sizes entirely.
*
* In fact, we could probably remove the size check entirely, since
* any kernel accesses will be in increasing address order starting
- * at 'ptr', and even if the end might be in kernel space, we'll
- * hit the GP faults for non-canonical accesses before we ever get
- * there.
+ * at 'ptr'.
*
* That's a separate optimization, for now just handle the small
* constant case.
diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c
index 956984054bf3..aab9d0570841 100644
--- a/arch/x86/kernel/acpi/cppc.c
+++ b/arch/x86/kernel/acpi/cppc.c
@@ -110,7 +110,7 @@ static void amd_set_max_freq_ratio(void)
static DEFINE_MUTEX(freq_invariance_lock);
-void init_freq_invariance_cppc(void)
+static inline void init_freq_invariance_cppc(void)
{
static bool init_done;
@@ -127,6 +127,11 @@ void init_freq_invariance_cppc(void)
mutex_unlock(&freq_invariance_lock);
}
+void acpi_processor_init_invariance_cppc(void)
+{
+ init_freq_invariance_cppc();
+}
+
/*
* Get the highest performance register value.
* @cpu: CPU from which to get highest performance.
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f1040cb64841..a5f221ea5688 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -69,6 +69,7 @@
#include <asm/sev.h>
#include <asm/tdx.h>
#include <asm/posted_intr.h>
+#include <asm/runtime-const.h>
#include "cpu.h"
@@ -2389,6 +2390,15 @@ void __init arch_cpu_finalize_init(void)
alternative_instructions();
if (IS_ENABLED(CONFIG_X86_64)) {
+ unsigned long USER_PTR_MAX = TASK_SIZE_MAX-1;
+
+ /*
+ * Enable this when LAM is gated on LASS support
+ if (cpu_feature_enabled(X86_FEATURE_LAM))
+ USER_PTR_MAX = (1ul << 63) - PAGE_SIZE - 1;
+ */
+ runtime_const_init(ptr, USER_PTR_MAX);
+
/*
* Make sure the first 2MB area is not mapped by huge pages
* There are typically fixed size MTRRs in there and overlapping
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index f63b051f25a0..31a73715d755 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -584,7 +584,7 @@ void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_
native_rdmsr(MSR_AMD64_PATCH_LEVEL, ed->new_rev, dummy);
}
-static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
+static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size);
static int __init save_microcode_in_initrd(void)
{
@@ -605,7 +605,7 @@ static int __init save_microcode_in_initrd(void)
if (!desc.mc)
return -EINVAL;
- ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
+ ret = _load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
if (ret > UCODE_UPDATED)
return -EINVAL;
@@ -613,16 +613,19 @@ static int __init save_microcode_in_initrd(void)
}
early_initcall(save_microcode_in_initrd);
-static inline bool patch_cpus_equivalent(struct ucode_patch *p, struct ucode_patch *n)
+static inline bool patch_cpus_equivalent(struct ucode_patch *p,
+ struct ucode_patch *n,
+ bool ignore_stepping)
{
/* Zen and newer hardcode the f/m/s in the patch ID */
if (x86_family(bsp_cpuid_1_eax) >= 0x17) {
union cpuid_1_eax p_cid = ucode_rev_to_cpuid(p->patch_id);
union cpuid_1_eax n_cid = ucode_rev_to_cpuid(n->patch_id);
- /* Zap stepping */
- p_cid.stepping = 0;
- n_cid.stepping = 0;
+ if (ignore_stepping) {
+ p_cid.stepping = 0;
+ n_cid.stepping = 0;
+ }
return p_cid.full == n_cid.full;
} else {
@@ -644,13 +647,13 @@ static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equi
WARN_ON_ONCE(!n.patch_id);
list_for_each_entry(p, &microcode_cache, plist)
- if (patch_cpus_equivalent(p, &n))
+ if (patch_cpus_equivalent(p, &n, false))
return p;
return NULL;
}
-static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
+static inline int patch_newer(struct ucode_patch *p, struct ucode_patch *n)
{
/* Zen and newer hardcode the f/m/s in the patch ID */
if (x86_family(bsp_cpuid_1_eax) >= 0x17) {
@@ -659,6 +662,9 @@ static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
zp.ucode_rev = p->patch_id;
zn.ucode_rev = n->patch_id;
+ if (zn.stepping != zp.stepping)
+ return -1;
+
return zn.rev > zp.rev;
} else {
return n->patch_id > p->patch_id;
@@ -668,10 +674,14 @@ static inline bool patch_newer(struct ucode_patch *p, struct ucode_patch *n)
static void update_cache(struct ucode_patch *new_patch)
{
struct ucode_patch *p;
+ int ret;
list_for_each_entry(p, &microcode_cache, plist) {
- if (patch_cpus_equivalent(p, new_patch)) {
- if (!patch_newer(p, new_patch)) {
+ if (patch_cpus_equivalent(p, new_patch, true)) {
+ ret = patch_newer(p, new_patch);
+ if (ret < 0)
+ continue;
+ else if (!ret) {
/* we already have the latest patch */
kfree(new_patch->data);
kfree(new_patch);
@@ -944,21 +954,30 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
return UCODE_OK;
}
-static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
+static enum ucode_state _load_microcode_amd(u8 family, const u8 *data, size_t size)
{
- struct cpuinfo_x86 *c;
- unsigned int nid, cpu;
- struct ucode_patch *p;
enum ucode_state ret;
/* free old equiv table */
free_equiv_cpu_table();
ret = __load_microcode_amd(family, data, size);
- if (ret != UCODE_OK) {
+ if (ret != UCODE_OK)
cleanup();
+
+ return ret;
+}
+
+static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
+{
+ struct cpuinfo_x86 *c;
+ unsigned int nid, cpu;
+ struct ucode_patch *p;
+ enum ucode_state ret;
+
+ ret = _load_microcode_amd(family, data, size);
+ if (ret != UCODE_OK)
return ret;
- }
for_each_node(nid) {
cpu = cpumask_first(cpumask_of_node(nid));
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index d05392db5d0f..2dbadf347b5f 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -261,12 +261,6 @@ static noinstr bool handle_bug(struct pt_regs *regs)
int ud_type;
u32 imm;
- /*
- * Normally @regs are unpoisoned by irqentry_enter(), but handle_bug()
- * is a rare case that uses @regs without passing them to
- * irqentry_enter().
- */
- kmsan_unpoison_entry_regs(regs);
ud_type = decode_bug(regs->ip, &imm);
if (ud_type == BUG_NONE)
return handled;
@@ -276,6 +270,12 @@ static noinstr bool handle_bug(struct pt_regs *regs)
*/
instrumentation_begin();
/*
+ * Normally @regs are unpoisoned by irqentry_enter(), but handle_bug()
+ * is a rare case that uses @regs without passing them to
+ * irqentry_enter().
+ */
+ kmsan_unpoison_entry_regs(regs);
+ /*
* Since we're emulating a CALL with exceptions, restore the interrupt
* state to what it was at the exception site.
*/
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 6726be89b7a6..b8c5741d2fb4 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -358,6 +358,7 @@ SECTIONS
#endif
RUNTIME_CONST_VARIABLES
+ RUNTIME_CONST(ptr, USER_PTR_MAX)
. = ALIGN(PAGE_SIZE);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 2098dc689088..95c6beb8ce27 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2629,19 +2629,26 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
- if (apic->apicv_active) {
- /* irr_pending is always true when apicv is activated. */
- apic->irr_pending = true;
+ /*
+ * When APICv is enabled, KVM must always search the IRR for a pending
+ * IRQ, as other vCPUs and devices can set IRR bits even if the vCPU
+ * isn't running. If APICv is disabled, KVM _should_ search the IRR
+ * for a pending IRQ. But KVM currently doesn't ensure *all* hardware,
+ * e.g. CPUs and IOMMUs, has seen the change in state, i.e. searching
+ * the IRR at this time could race with IRQ delivery from hardware that
+ * still sees APICv as being enabled.
+ *
+ * FIXME: Ensure other vCPUs and devices observe the change in APICv
+ * state prior to updating KVM's metadata caches, so that KVM
+ * can safely search the IRR and set irr_pending accordingly.
+ */
+ apic->irr_pending = true;
+
+ if (apic->apicv_active)
apic->isr_count = 1;
- } else {
- /*
- * Don't clear irr_pending, searching the IRR can race with
- * updates from the CPU as APICv is still active from hardware's
- * perspective. The flag will be cleared as appropriate when
- * KVM injects the interrupt.
- */
+ else
apic->isr_count = count_vectors(apic->regs + APIC_ISR);
- }
+
apic->highest_isr_cache = -1;
}
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 0b851ef937f2..fb854cf20ac3 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -450,8 +450,11 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
goto e_free;
/* This needs to happen after SEV/SNP firmware initialization. */
- if (vm_type == KVM_X86_SNP_VM && snp_guest_req_init(kvm))
- goto e_free;
+ if (vm_type == KVM_X86_SNP_VM) {
+ ret = snp_guest_req_init(kvm);
+ if (ret)
+ goto e_free;
+ }
INIT_LIST_HEAD(&sev->regions_list);
INIT_LIST_HEAD(&sev->mirror_vms);
@@ -2212,10 +2215,6 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
if (sev->snp_context)
return -EINVAL;
- sev->snp_context = snp_context_create(kvm, argp);
- if (!sev->snp_context)
- return -ENOTTY;
-
if (params.flags)
return -EINVAL;
@@ -2230,6 +2229,10 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
if (params.policy & SNP_POLICY_MASK_SINGLE_SOCKET)
return -EINVAL;
+ sev->snp_context = snp_context_create(kvm, argp);
+ if (!sev->snp_context)
+ return -ENOTTY;
+
start.gctx_paddr = __psp_pa(sev->snp_context);
start.policy = params.policy;
memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw));
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index a8e7bc04d9bf..931a7361c30f 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -1197,11 +1197,14 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
kvm_hv_nested_transtion_tlb_flush(vcpu, enable_ept);
/*
- * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
- * for *all* contexts to be flushed on VM-Enter/VM-Exit, i.e. it's a
- * full TLB flush from the guest's perspective. This is required even
- * if VPID is disabled in the host as KVM may need to synchronize the
- * MMU in response to the guest TLB flush.
+ * If VPID is disabled, then guest TLB accesses use VPID=0, i.e. the
+ * same VPID as the host, and so architecturally, linear and combined
+ * mappings for VPID=0 must be flushed at VM-Enter and VM-Exit. KVM
+ * emulates L2 sharing L1's VPID=0 by using vpid01 while running L2,
+ * and so KVM must also emulate TLB flush of VPID=0, i.e. vpid01. This
+ * is required if VPID is disabled in KVM, as a TLB flush (there are no
+ * VPIDs) still occurs from L1's perspective, and KVM may need to
+ * synchronize the MMU in response to the guest TLB flush.
*
* Note, using TLB_FLUSH_GUEST is correct even if nested EPT is in use.
* EPT is a special snowflake, as guest-physical mappings aren't
@@ -2315,6 +2318,17 @@ static void prepare_vmcs02_early_rare(struct vcpu_vmx *vmx,
vmcs_write64(VMCS_LINK_POINTER, INVALID_GPA);
+ /*
+ * If VPID is disabled, then guest TLB accesses use VPID=0, i.e. the
+ * same VPID as the host. Emulate this behavior by using vpid01 for L2
+ * if VPID is disabled in vmcs12. Note, if VPID is disabled, VM-Enter
+ * and VM-Exit are architecturally required to flush VPID=0, but *only*
+ * VPID=0. I.e. using vpid02 would be ok (so long as KVM emulates the
+ * required flushes), but doing so would cause KVM to over-flush. E.g.
+ * if L1 runs L2 X with VPID12=1, then runs L2 Y with VPID12 disabled,
+ * and then runs L2 X again, then KVM can and should retain TLB entries
+ * for VPID12=1.
+ */
if (enable_vpid) {
if (nested_cpu_has_vpid(vmcs12) && vmx->nested.vpid02)
vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->nested.vpid02);
@@ -5950,6 +5964,12 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
return nested_vmx_fail(vcpu,
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+ /*
+ * Always flush the effective vpid02, i.e. never flush the current VPID
+ * and never explicitly flush vpid01. INVVPID targets a VPID, not a
+ * VMCS, and so whether or not the current vmcs12 has VPID enabled is
+ * irrelevant (and there may not be a loaded vmcs12).
+ */
vpid02 = nested_get_vpid02(vcpu);
switch (type) {
case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 81ed596e4454..d28618e9277e 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -217,9 +217,11 @@ module_param(ple_window_shrink, uint, 0444);
static unsigned int ple_window_max = KVM_VMX_DEFAULT_PLE_WINDOW_MAX;
module_param(ple_window_max, uint, 0444);
-/* Default is SYSTEM mode, 1 for host-guest mode */
+/* Default is SYSTEM mode, 1 for host-guest mode (which is BROKEN) */
int __read_mostly pt_mode = PT_MODE_SYSTEM;
+#ifdef CONFIG_BROKEN
module_param(pt_mode, int, S_IRUGO);
+#endif
struct x86_pmu_lbr __ro_after_init vmx_lbr_caps;
@@ -3216,7 +3218,7 @@ void vmx_flush_tlb_all(struct kvm_vcpu *vcpu)
static inline int vmx_get_current_vpid(struct kvm_vcpu *vcpu)
{
- if (is_guest_mode(vcpu))
+ if (is_guest_mode(vcpu) && nested_cpu_has_vpid(get_vmcs12(vcpu)))
return nested_get_vpid02(vcpu);
return to_vmx(vcpu)->vpid;
}
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index d066aecf8aeb..4357ec2a0bfc 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -39,8 +39,13 @@
.macro check_range size:req
.if IS_ENABLED(CONFIG_X86_64)
- mov %rax, %rdx
- sar $63, %rdx
+ movq $0x0123456789abcdef,%rdx
+ 1:
+ .pushsection runtime_ptr_USER_PTR_MAX,"a"
+ .long 1b - 8 - .
+ .popsection
+ cmp %rax, %rdx
+ sbb %rdx, %rdx
or %rdx, %rax
.else
cmp $TASK_SIZE_MAX-\size+1, %eax
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 0ce17766c0e5..9a6a943d8e41 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -173,6 +173,8 @@ static void __init __snp_fixup_e820_tables(u64 pa)
e820__range_update(pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
e820__range_update_table(e820_table_kexec, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
e820__range_update_table(e820_table_firmware, pa, PMD_SIZE, E820_TYPE_RAM, E820_TYPE_RESERVED);
+ if (!memblock_is_region_reserved(pa, PMD_SIZE))
+ memblock_reserve(pa, PMD_SIZE);
}
}
diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
index 4db56ef052d2..8665d57991dd 100644
--- a/arch/xtensa/include/asm/page.h
+++ b/arch/xtensa/include/asm/page.h
@@ -109,26 +109,8 @@ typedef struct page *pgtable_t;
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-/*
- * Pure 2^n version of get_order
- * Use 'nsau' instructions if supported by the processor or the generic version.
- */
-
-#if XCHAL_HAVE_NSA
-
-static inline __attribute_const__ int get_order(unsigned long size)
-{
- int lz;
- asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT));
- return 32 - lz;
-}
-
-#else
-
# include <asm-generic/getorder.h>
-#endif
-
struct page;
struct vm_area_struct;
extern void clear_page(void *page);
diff --git a/block/blk-map.c b/block/blk-map.c
index 0e1167b23934..b5fd1d857461 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -561,57 +561,33 @@ EXPORT_SYMBOL(blk_rq_append_bio);
/* Prepare bio for passthrough IO given ITER_BVEC iter */
static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter)
{
- struct request_queue *q = rq->q;
- size_t nr_iter = iov_iter_count(iter);
- size_t nr_segs = iter->nr_segs;
- struct bio_vec *bvecs, *bvprvp = NULL;
- const struct queue_limits *lim = &q->limits;
- unsigned int nsegs = 0, bytes = 0;
+ const struct queue_limits *lim = &rq->q->limits;
+ unsigned int max_bytes = lim->max_hw_sectors << SECTOR_SHIFT;
+ unsigned int nsegs;
struct bio *bio;
- size_t i;
+ int ret;
- if (!nr_iter || (nr_iter >> SECTOR_SHIFT) > queue_max_hw_sectors(q))
- return -EINVAL;
- if (nr_segs > queue_max_segments(q))
+ if (!iov_iter_count(iter) || iov_iter_count(iter) > max_bytes)
return -EINVAL;
- /* no iovecs to alloc, as we already have a BVEC iterator */
+ /* reuse the bvecs from the iterator instead of allocating new ones */
bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL);
- if (bio == NULL)
+ if (!bio)
return -ENOMEM;
-
bio_iov_bvec_set(bio, (struct iov_iter *)iter);
- blk_rq_bio_prep(rq, bio, nr_segs);
-
- /* loop to perform a bunch of sanity checks */
- bvecs = (struct bio_vec *)iter->bvec;
- for (i = 0; i < nr_segs; i++) {
- struct bio_vec *bv = &bvecs[i];
- /*
- * If the queue doesn't support SG gaps and adding this
- * offset would create a gap, fallback to copy.
- */
- if (bvprvp && bvec_gap_to_prev(lim, bvprvp, bv->bv_offset)) {
- blk_mq_map_bio_put(bio);
- return -EREMOTEIO;
- }
- /* check full condition */
- if (nsegs >= nr_segs || bytes > UINT_MAX - bv->bv_len)
- goto put_bio;
- if (bytes + bv->bv_len > nr_iter)
- goto put_bio;
- if (bv->bv_offset + bv->bv_len > PAGE_SIZE)
- goto put_bio;
-
- nsegs++;
- bytes += bv->bv_len;
- bvprvp = bv;
+ /* check that the data layout matches the hardware restrictions */
+ ret = bio_split_rw_at(bio, lim, &nsegs, max_bytes);
+ if (ret) {
+ /* if we would have to split the bio, copy instead */
+ if (ret > 0)
+ ret = -EREMOTEIO;
+ blk_mq_map_bio_put(bio);
+ return ret;
}
+
+ blk_rq_bio_prep(rq, bio, nsegs);
return 0;
-put_bio:
- blk_mq_map_bio_put(bio);
- return -EINVAL;
}
/**
diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c
index 6f86f8df30db..8d50981594d1 100644
--- a/drivers/accel/ivpu/ivpu_debugfs.c
+++ b/drivers/accel/ivpu/ivpu_debugfs.c
@@ -108,6 +108,14 @@ static int reset_pending_show(struct seq_file *s, void *v)
return 0;
}
+static int firewall_irq_counter_show(struct seq_file *s, void *v)
+{
+ struct ivpu_device *vdev = seq_to_ivpu(s);
+
+ seq_printf(s, "%d\n", atomic_read(&vdev->hw->firewall_irq_counter));
+ return 0;
+}
+
static const struct drm_debugfs_info vdev_debugfs_list[] = {
{"bo_list", bo_list_show, 0},
{"fw_name", fw_name_show, 0},
@@ -116,6 +124,7 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = {
{"last_bootmode", last_bootmode_show, 0},
{"reset_counter", reset_counter_show, 0},
{"reset_pending", reset_pending_show, 0},
+ {"firewall_irq_counter", firewall_irq_counter_show, 0},
};
static ssize_t
diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c
index 27f0fe4d54e0..e69c0613513f 100644
--- a/drivers/accel/ivpu/ivpu_hw.c
+++ b/drivers/accel/ivpu/ivpu_hw.c
@@ -249,6 +249,7 @@ int ivpu_hw_init(struct ivpu_device *vdev)
platform_init(vdev);
wa_init(vdev);
timeouts_init(vdev);
+ atomic_set(&vdev->hw->firewall_irq_counter, 0);
return 0;
}
diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h
index 1c0c98e3afb8..a96a05b2acda 100644
--- a/drivers/accel/ivpu/ivpu_hw.h
+++ b/drivers/accel/ivpu/ivpu_hw.h
@@ -52,6 +52,7 @@ struct ivpu_hw_info {
int dma_bits;
ktime_t d0i3_entry_host_ts;
u64 d0i3_entry_vpu_ts;
+ atomic_t firewall_irq_counter;
};
int ivpu_hw_init(struct ivpu_device *vdev);
diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c
index dfd2f4a5b526..60b33fc59d96 100644
--- a/drivers/accel/ivpu/ivpu_hw_ip.c
+++ b/drivers/accel/ivpu/ivpu_hw_ip.c
@@ -1062,7 +1062,10 @@ static void irq_wdt_mss_handler(struct ivpu_device *vdev)
static void irq_noc_firewall_handler(struct ivpu_device *vdev)
{
- ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ");
+ atomic_inc(&vdev->hw->firewall_irq_counter);
+
+ ivpu_dbg(vdev, IRQ, "NOC Firewall interrupt detected, counter %d\n",
+ atomic_read(&vdev->hw->firewall_irq_counter));
}
/* Handler for IRQs from NPU core */
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 51470208e6da..7773e6b860e7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -130,6 +130,17 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
},
+ {
+ /*
+ * Samsung galaxybook2 ,initial _LID device notification returns
+ * lid closed.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "750XED"),
+ },
+ .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+ },
{}
};
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index b73b3aa92f3f..5c0cc7aae872 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -671,10 +671,6 @@ static int pcc_data_alloc(int pcc_ss_id)
* )
*/
-#ifndef arch_init_invariance_cppc
-static inline void arch_init_invariance_cppc(void) { }
-#endif
-
/**
* acpi_cppc_processor_probe - Search for per CPU _CPC objects.
* @pr: Ptr to acpi_processor containing this CPU's logical ID.
@@ -867,7 +863,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
/* Store CPU Logical ID */
cpc_ptr->cpu_id = pr->id;
- spin_lock_init(&cpc_ptr->rmw_lock);
+ raw_spin_lock_init(&cpc_ptr->rmw_lock);
/* Parse PSD data for this CPU */
ret = acpi_get_psd(cpc_ptr, handle);
@@ -905,8 +901,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
goto out_free;
}
- arch_init_invariance_cppc();
-
kfree(output.pointer);
return 0;
@@ -1087,6 +1081,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
struct cpc_reg *reg = &reg_res->cpc_entry.reg;
struct cpc_desc *cpc_desc;
+ unsigned long flags;
size = GET_BIT_WIDTH(reg);
@@ -1126,7 +1121,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
return -ENODEV;
}
- spin_lock(&cpc_desc->rmw_lock);
+ raw_spin_lock_irqsave(&cpc_desc->rmw_lock, flags);
switch (size) {
case 8:
prev_val = readb_relaxed(vaddr);
@@ -1141,7 +1136,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
prev_val = readq_relaxed(vaddr);
break;
default:
- spin_unlock(&cpc_desc->rmw_lock);
+ raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags);
return -EFAULT;
}
val = MASK_VAL_WRITE(reg, prev_val, val);
@@ -1174,7 +1169,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
}
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- spin_unlock(&cpc_desc->rmw_lock);
+ raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags);
return ret_val;
}
@@ -1916,9 +1911,15 @@ unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf)
u64 mul, div;
if (caps->lowest_freq && caps->nominal_freq) {
- mul = caps->nominal_freq - caps->lowest_freq;
+ /* Avoid special case when nominal_freq is equal to lowest_freq */
+ if (caps->lowest_freq == caps->nominal_freq) {
+ mul = caps->nominal_freq;
+ div = caps->nominal_perf;
+ } else {
+ mul = caps->nominal_freq - caps->lowest_freq;
+ div = caps->nominal_perf - caps->lowest_perf;
+ }
mul *= KHZ_PER_MHZ;
- div = caps->nominal_perf - caps->lowest_perf;
offset = caps->nominal_freq * KHZ_PER_MHZ -
div64_u64(caps->nominal_perf * mul, div);
} else {
@@ -1939,11 +1940,17 @@ unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq)
{
s64 retval, offset = 0;
static u64 max_khz;
- u64 mul, div;
+ u64 mul, div;
if (caps->lowest_freq && caps->nominal_freq) {
- mul = caps->nominal_perf - caps->lowest_perf;
- div = caps->nominal_freq - caps->lowest_freq;
+ /* Avoid special case when nominal_freq is equal to lowest_freq */
+ if (caps->lowest_freq == caps->nominal_freq) {
+ mul = caps->nominal_perf;
+ div = caps->nominal_freq;
+ } else {
+ mul = caps->nominal_perf - caps->lowest_perf;
+ div = caps->nominal_freq - caps->lowest_freq;
+ }
/*
* We don't need to convert to kHz for computing offset and can
* directly use nominal_freq and lowest_freq as the div64_u64
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c
index 1cfaa5957ac4..747f83f7114d 100644
--- a/drivers/acpi/prmt.c
+++ b/drivers/acpi/prmt.c
@@ -52,7 +52,7 @@ struct prm_context_buffer {
static LIST_HEAD(prm_module_list);
struct prm_handler_info {
- guid_t guid;
+ efi_guid_t guid;
efi_status_t (__efiapi *handler_addr)(u64, void *);
u64 static_data_buffer_addr;
u64 acpi_param_buffer_addr;
@@ -72,17 +72,21 @@ struct prm_module_info {
struct prm_handler_info handlers[] __counted_by(handler_count);
};
-static u64 efi_pa_va_lookup(u64 pa)
+static u64 efi_pa_va_lookup(efi_guid_t *guid, u64 pa)
{
efi_memory_desc_t *md;
u64 pa_offset = pa & ~PAGE_MASK;
u64 page = pa & PAGE_MASK;
for_each_efi_memory_desc(md) {
- if (md->phys_addr < pa && pa < md->phys_addr + PAGE_SIZE * md->num_pages)
+ if ((md->attribute & EFI_MEMORY_RUNTIME) &&
+ (md->phys_addr < pa && pa < md->phys_addr + PAGE_SIZE * md->num_pages)) {
return pa_offset + md->virt_addr + page - md->phys_addr;
+ }
}
+ pr_warn("Failed to find VA for GUID: %pUL, PA: 0x%llx", guid, pa);
+
return 0;
}
@@ -148,9 +152,15 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end)
th = &tm->handlers[cur_handler];
guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
- th->handler_addr = (void *)efi_pa_va_lookup(handler_info->handler_address);
- th->static_data_buffer_addr = efi_pa_va_lookup(handler_info->static_data_buffer_address);
- th->acpi_param_buffer_addr = efi_pa_va_lookup(handler_info->acpi_param_buffer_address);
+ th->handler_addr =
+ (void *)efi_pa_va_lookup(&th->guid, handler_info->handler_address);
+
+ th->static_data_buffer_addr =
+ efi_pa_va_lookup(&th->guid, handler_info->static_data_buffer_address);
+
+ th->acpi_param_buffer_addr =
+ efi_pa_va_lookup(&th->guid, handler_info->acpi_param_buffer_address);
+
} while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
return 0;
@@ -277,6 +287,13 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
if (!handler || !module)
goto invalid_guid;
+ if (!handler->handler_addr ||
+ !handler->static_data_buffer_addr ||
+ !handler->acpi_param_buffer_addr) {
+ buffer->prm_status = PRM_HANDLER_ERROR;
+ return AE_OK;
+ }
+
ACPI_COPY_NAMESEG(context.signature, "PRMC");
context.revision = 0x0;
context.reserved = 0x0;
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index cb52dd000b95..3b281bc1e73c 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -237,6 +237,9 @@ static struct notifier_block acpi_processor_notifier_block = {
.notifier_call = acpi_processor_notifier,
};
+void __weak acpi_processor_init_invariance_cppc(void)
+{ }
+
/*
* We keep the driver loaded even when ACPI is not running.
* This is needed for the powernow-k8 driver, that works even without
@@ -270,6 +273,12 @@ static int __init acpi_processor_driver_init(void)
NULL, acpi_soft_cpu_dead);
acpi_processor_throttling_init();
+
+ /*
+ * Frequency invariance calculations on AMD platforms can't be run until
+ * after acpi_cppc_processor_probe() has been called for all online CPUs
+ */
+ acpi_processor_init_invariance_cppc();
return 0;
err:
driver_unregister(&acpi_processor_driver);
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 129bceb1f4a2..7fe842dae1ec 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "17U70P"),
},
},
+ {
+ /* LG Electronics 16T90SP */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
+ DMI_MATCH(DMI_BOARD_NAME, "16T90SP"),
+ },
+ },
{ }
};
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index fa41ea57a978..3b303d4ae37a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -651,6 +651,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
/* the scmd has an associated qc */
if (!(qc->flags & ATA_QCFLAG_EH)) {
/* which hasn't failed yet, timeout */
+ set_host_byte(scmd, DID_TIME_OUT);
qc->err_mask |= AC_ERR_TIMEOUT;
qc->flags |= ATA_QCFLAG_EH;
nr_timedout++;
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 75fcb75d5515..3ebe77566788 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -366,7 +366,7 @@ void __weak freq_inv_set_max_ratio(int cpu, u64 max_rate)
#ifdef CONFIG_ACPI_CPPC_LIB
#include <acpi/cppc_acpi.h>
-void topology_init_cpu_capacity_cppc(void)
+static inline void topology_init_cpu_capacity_cppc(void)
{
u64 capacity, capacity_scale = 0;
struct cppc_perf_caps perf_caps;
@@ -417,6 +417,10 @@ void topology_init_cpu_capacity_cppc(void)
exit:
free_raw_capacity();
}
+void acpi_processor_init_invariance_cppc(void)
+{
+ topology_init_cpu_capacity_cppc();
+}
#endif
#ifdef CONFIG_CPU_FREQ
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a4c853411a6b..048ff98dbdfd 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -26,7 +26,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
-#include <linux/rcupdate.h>
#include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
@@ -2634,7 +2633,6 @@ static const char *dev_uevent_name(const struct kobject *kobj)
static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
{
const struct device *dev = kobj_to_dev(kobj);
- struct device_driver *driver;
int retval = 0;
/* add device node properties if present */
@@ -2663,12 +2661,8 @@ static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
if (dev->type && dev->type->name)
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
- /* Synchronize with module_remove_driver() */
- rcu_read_lock();
- driver = READ_ONCE(dev->driver);
- if (driver)
- add_uevent_var(env, "DRIVER=%s", driver->name);
- rcu_read_unlock();
+ if (dev->driver)
+ add_uevent_var(env, "DRIVER=%s", dev->driver->name);
/* Add common DT information about the device */
of_device_uevent(dev, env);
@@ -2738,8 +2732,11 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
if (!env)
return -ENOMEM;
+ /* Synchronize with really_probe() */
+ device_lock(dev);
/* let the kset specific function add its keys */
retval = kset->uevent_ops->uevent(&dev->kobj, env);
+ device_unlock(dev);
if (retval)
goto out;
@@ -4038,6 +4035,41 @@ int device_for_each_child_reverse(struct device *parent, void *data,
EXPORT_SYMBOL_GPL(device_for_each_child_reverse);
/**
+ * device_for_each_child_reverse_from - device child iterator in reversed order.
+ * @parent: parent struct device.
+ * @from: optional starting point in child list
+ * @fn: function to be called for each device.
+ * @data: data for the callback.
+ *
+ * Iterate over @parent's child devices, starting at @from, and call @fn
+ * for each, passing it @data. This helper is identical to
+ * device_for_each_child_reverse() when @from is NULL.
+ *
+ * @fn is checked each iteration. If it returns anything other than 0,
+ * iteration stop and that value is returned to the caller of
+ * device_for_each_child_reverse_from();
+ */
+int device_for_each_child_reverse_from(struct device *parent,
+ struct device *from, const void *data,
+ int (*fn)(struct device *, const void *))
+{
+ struct klist_iter i;
+ struct device *child;
+ int error = 0;
+
+ if (!parent->p)
+ return 0;
+
+ klist_iter_init_node(&parent->p->klist_children, &i,
+ (from ? &from->p->knode_parent : NULL));
+ while ((child = prev_device(&i)) && !error)
+ error = fn(child, data);
+ klist_iter_exit(&i);
+ return error;
+}
+EXPORT_SYMBOL_GPL(device_for_each_child_reverse_from);
+
+/**
* device_find_child - device iterator for locating a particular device.
* @parent: parent struct device
* @match: Callback function to check device
diff --git a/drivers/base/module.c b/drivers/base/module.c
index c4eaa1158d54..5bc71bea883a 100644
--- a/drivers/base/module.c
+++ b/drivers/base/module.c
@@ -7,7 +7,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/rcupdate.h>
#include "base.h"
static char *make_driver_name(const struct device_driver *drv)
@@ -102,9 +101,6 @@ void module_remove_driver(const struct device_driver *drv)
if (!drv)
return;
- /* Synchronize with dev_uevent() */
- synchronize_rcu();
-
sysfs_remove_link(&drv->p->kobj, "module");
if (drv->owner)
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index eef00467905e..a1153ada74d2 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -541,11 +541,10 @@ static const struct bcm_subver_table bcm_usb_subver_table[] = {
static const char *btbcm_get_board_name(struct device *dev)
{
#ifdef CONFIG_OF
- struct device_node *root;
+ struct device_node *root __free(device_node) = of_find_node_by_path("/");
char *board_type;
const char *tmp;
- root = of_find_node_by_path("/");
if (!root)
return NULL;
@@ -555,7 +554,6 @@ static const char *btbcm_get_board_name(struct device *dev)
/* get rid of any '/' in the compatible string */
board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
strreplace(board_type, '/', '-');
- of_node_put(root);
return board_type;
#else
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 438b92967bc3..d496cf2c3411 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -1040,7 +1040,7 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
* as needed.
*
* Send set of commands with 4 byte alignment from the
- * firmware data buffer as a single Data fragement.
+ * firmware data buffer as a single Data fragment.
*/
if (!(frag_len % 4)) {
err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
@@ -1252,6 +1252,12 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
struct intel_reset params;
struct sk_buff *skb;
+ /* PCIe transport uses shared hardware reset mechanism for recovery
+ * which gets triggered in pcie *setup* function on error.
+ */
+ if (hdev->bus == HCI_PCI)
+ return;
+
/* Send Intel Reset command. This will result in
* re-enumeration of BT controller.
*
@@ -1267,6 +1273,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
* boot_param: Boot address
*
*/
+
params.reset_type = 0x01;
params.patch_enable = 0x01;
params.ddc_reload = 0x01;
@@ -1841,6 +1848,37 @@ static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
return 0;
}
+static int btintel_boot_wait_d0(struct hci_dev *hdev, ktime_t calltime,
+ int msec)
+{
+ ktime_t delta, rettime;
+ unsigned long long duration;
+ int err;
+
+ bt_dev_info(hdev, "Waiting for device transition to d0");
+
+ err = btintel_wait_on_flag_timeout(hdev, INTEL_WAIT_FOR_D0,
+ TASK_INTERRUPTIBLE,
+ msecs_to_jiffies(msec));
+ if (err == -EINTR) {
+ bt_dev_err(hdev, "Device d0 move interrupted");
+ return -EINTR;
+ }
+
+ if (err) {
+ bt_dev_err(hdev, "Device d0 move timeout");
+ return -ETIMEDOUT;
+ }
+
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long)ktime_to_ns(delta) >> 10;
+
+ bt_dev_info(hdev, "Device moved to D0 in %llu usecs", duration);
+
+ return 0;
+}
+
static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
{
ktime_t calltime;
@@ -1849,6 +1887,7 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
calltime = ktime_get();
btintel_set_flag(hdev, INTEL_BOOTING);
+ btintel_set_flag(hdev, INTEL_WAIT_FOR_D0);
err = btintel_send_intel_reset(hdev, boot_addr);
if (err) {
@@ -1861,13 +1900,28 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
* is done by the operational firmware sending bootup notification.
*
* Booting into operational firmware should not take longer than
- * 1 second. However if that happens, then just fail the setup
+ * 5 second. However if that happens, then just fail the setup
* since something went wrong.
*/
- err = btintel_boot_wait(hdev, calltime, 1000);
- if (err == -ETIMEDOUT)
+ err = btintel_boot_wait(hdev, calltime, 5000);
+ if (err == -ETIMEDOUT) {
btintel_reset_to_bootloader(hdev);
+ goto exit_error;
+ }
+
+ if (hdev->bus == HCI_PCI) {
+ /* In case of PCIe, after receiving bootup event, driver performs
+ * D0 entry by writing 0 to sleep control register (check
+ * btintel_pcie_recv_event())
+ * Firmware acks with alive interrupt indicating host is full ready to
+ * perform BT operation. Lets wait here till INTEL_WAIT_FOR_D0
+ * bit is cleared.
+ */
+ calltime = ktime_get();
+ err = btintel_boot_wait_d0(hdev, calltime, 2000);
+ }
+exit_error:
return err;
}
@@ -2693,20 +2747,32 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver)
struct btintel_dsbr_cmd cmd;
struct sk_buff *skb;
+ u32 dsbr, cnvi;
u8 status;
- u32 dsbr;
- bool apply_dsbr;
int err;
- /* DSBR command needs to be sent for BlazarI + B0 step product after
- * downloading IML image.
+ cnvi = ver->cnvi_top & 0xfff;
+ /* DSBR command needs to be sent for,
+ * 1. BlazarI or BlazarIW + B0 step product in IML image.
+ * 2. Gale Peak2 or BlazarU in OP image.
*/
- apply_dsbr = (ver->img_type == BTINTEL_IMG_IML &&
- ((ver->cnvi_top & 0xfff) == BTINTEL_CNVI_BLAZARI) &&
- INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01);
- if (!apply_dsbr)
+ switch (cnvi) {
+ case BTINTEL_CNVI_BLAZARI:
+ case BTINTEL_CNVI_BLAZARIW:
+ if (ver->img_type == BTINTEL_IMG_IML &&
+ INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01)
+ break;
return 0;
+ case BTINTEL_CNVI_GAP:
+ case BTINTEL_CNVI_BLAZARU:
+ if (ver->img_type == BTINTEL_IMG_OP &&
+ hdev->bus == HCI_USB)
+ break;
+ return 0;
+ default:
+ return 0;
+ }
dsbr = 0;
err = btintel_uefi_get_dsbr(&dsbr);
@@ -2749,6 +2815,13 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
*/
boot_param = 0x00000000;
+ /* In case of PCIe, this function might get called multiple times with
+ * same hdev instance if there is any error on firmware download.
+ * Need to clear stale bits of previous firmware download attempt.
+ */
+ for (int i = 0; i < __INTEL_NUM_FLAGS; i++)
+ btintel_clear_flag(hdev, i);
+
btintel_set_flag(hdev, INTEL_BOOTLOADER);
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
@@ -2835,7 +2908,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
case 0x12: /* ThP */
case 0x13: /* HrP */
case 0x14: /* CcP */
- /* All Intel new genration controllers support the Microsoft vendor
+ /* All Intel new generation controllers support the Microsoft vendor
* extension are using 0xFC1E for VsMsftOpCode.
*/
case 0x17:
@@ -3273,7 +3346,7 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
}
EXPORT_SYMBOL_GPL(btintel_configure_setup);
-static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
+int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
struct intel_tlv *tlv = (void *)&skb->data[5];
@@ -3288,13 +3361,12 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
case INTEL_TLV_TEST_EXCEPTION:
/* Generate devcoredump from exception */
if (!hci_devcd_init(hdev, skb->len)) {
- hci_devcd_append(hdev, skb);
+ hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
hci_devcd_complete(hdev);
} else {
bt_dev_err(hdev, "Failed to generate devcoredump");
- kfree_skb(skb);
}
- return 0;
+ break;
default:
bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
}
@@ -3302,6 +3374,7 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
recv_frame:
return hci_recv_frame(hdev, skb);
}
+EXPORT_SYMBOL_GPL(btintel_diagnostics);
int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -3321,7 +3394,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
* indicating that the bootup completed.
*/
btintel_bootup(hdev, ptr, len);
- break;
+ kfree_skb(skb);
+ return 0;
case 0x06:
/* When the firmware loading completes the
* device sends out a vendor specific event
@@ -3329,7 +3403,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
* loading.
*/
btintel_secure_send_result(hdev, ptr, len);
- break;
+ kfree_skb(skb);
+ return 0;
}
}
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index aa70e4c27416..fa43eb137821 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -53,6 +53,9 @@ struct intel_tlv {
} __packed;
#define BTINTEL_CNVI_BLAZARI 0x900
+#define BTINTEL_CNVI_BLAZARIW 0x901
+#define BTINTEL_CNVI_GAP 0x910
+#define BTINTEL_CNVI_BLAZARU 0x930
#define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
@@ -178,6 +181,7 @@ enum {
INTEL_ROM_LEGACY,
INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
INTEL_ACPI_RESET_ACTIVE,
+ INTEL_WAIT_FOR_D0,
__INTEL_NUM_FLAGS,
};
@@ -249,6 +253,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
int btintel_shutdown_combined(struct hci_dev *hdev);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_print_fseq_info(struct hci_dev *hdev);
+int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb);
#else
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
@@ -382,4 +387,9 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
{
}
+
+static inline int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ return -EOPNOTSUPP;
+}
#endif
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 5252125b003f..2b79952f3628 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -48,6 +48,17 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
#define BTINTEL_PCIE_HCI_EVT_PKT 0x00000004
#define BTINTEL_PCIE_HCI_ISO_PKT 0x00000005
+/* Alive interrupt context */
+enum {
+ BTINTEL_PCIE_ROM,
+ BTINTEL_PCIE_FW_DL,
+ BTINTEL_PCIE_HCI_RESET,
+ BTINTEL_PCIE_INTEL_HCI_RESET1,
+ BTINTEL_PCIE_INTEL_HCI_RESET2,
+ BTINTEL_PCIE_D0,
+ BTINTEL_PCIE_D3
+};
+
static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia,
u16 queue_num)
{
@@ -64,24 +75,6 @@ static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1,
index, urbd1->frbd_tag, urbd1->status, urbd1->fixed);
}
-static int btintel_pcie_poll_bit(struct btintel_pcie_data *data, u32 offset,
- u32 bits, u32 mask, int timeout_us)
-{
- int t = 0;
- u32 reg;
-
- do {
- reg = btintel_pcie_rd_reg32(data, offset);
-
- if ((reg & mask) == (bits & mask))
- return t;
- udelay(POLL_INTERVAL_US);
- t += POLL_INTERVAL_US;
- } while (t < timeout_us);
-
- return -ETIMEDOUT;
-}
-
static struct btintel_pcie_data *btintel_pcie_get_data(struct msix_entry *entry)
{
u8 queue = entry->entry;
@@ -237,10 +230,47 @@ static void btintel_pcie_reset_ia(struct btintel_pcie_data *data)
memset(data->ia.cr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
}
-static void btintel_pcie_reset_bt(struct btintel_pcie_data *data)
+static int btintel_pcie_reset_bt(struct btintel_pcie_data *data)
{
- btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET);
+ u32 reg;
+ int retry = 3;
+
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+
+ reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
+ reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON;
+
+ btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
+
+ do {
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+ if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS)
+ break;
+ usleep_range(10000, 12000);
+
+ } while (--retry > 0);
+ usleep_range(10000, 12000);
+
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+
+ reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
+ reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET;
+ btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
+ usleep_range(10000, 12000);
+
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+ bt_dev_dbg(data->hdev, "csr register after reset: 0x%8.8x", reg);
+
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG);
+
+ /* If shared hardware reset is success then boot stage register shall be
+ * set to 0
+ */
+ return reg == 0 ? 0 : -ENODEV;
}
/* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in
@@ -252,6 +282,7 @@ static void btintel_pcie_reset_bt(struct btintel_pcie_data *data)
static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
{
int err;
+ u32 reg;
data->gp0_received = false;
@@ -267,22 +298,17 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
data->boot_stage_cache = 0x0;
/* Set MAC_INIT bit to start primary bootloader */
- btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+ reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+ reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET);
+ reg |= (BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
+ BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT);
- btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT);
-
- /* Wait until MAC_ACCESS is granted */
- err = btintel_pcie_poll_bit(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS,
- BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS,
- BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US);
- if (err < 0)
- return -ENODEV;
+ btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
/* MAC is ready. Enable BT FUNC */
btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG,
- BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
@@ -290,8 +316,9 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
/* wait for interrupt from the device after booting up to primary
* bootloader.
*/
+ data->alive_intr_ctxt = BTINTEL_PCIE_ROM;
err = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
- msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT));
+ msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
if (!err)
return -ETIME;
@@ -302,12 +329,77 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
return 0;
}
+/* BIT(0) - ROM, BIT(1) - IML and BIT(3) - OP
+ * Sometimes during firmware image switching from ROM to IML or IML to OP image,
+ * the previous image bit is not cleared by firmware when alive interrupt is
+ * received. Driver needs to take care of these sticky bits when deciding the
+ * current image running on controller.
+ * Ex: 0x10 and 0x11 - both represents that controller is running IML
+ */
+static inline bool btintel_pcie_in_rom(struct btintel_pcie_data *data)
+{
+ return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM &&
+ !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) &&
+ !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
+}
+
+static inline bool btintel_pcie_in_op(struct btintel_pcie_data *data)
+{
+ return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW;
+}
+
+static inline bool btintel_pcie_in_iml(struct btintel_pcie_data *data)
+{
+ return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML &&
+ !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
+}
+
+static inline bool btintel_pcie_in_d3(struct btintel_pcie_data *data)
+{
+ return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY;
+}
+
+static inline bool btintel_pcie_in_d0(struct btintel_pcie_data *data)
+{
+ return !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY);
+}
+
+static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
+ u32 dxstate)
+{
+ bt_dev_dbg(data->hdev, "writing sleep_ctl_reg: 0x%8.8x", dxstate);
+ btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate);
+}
+
+static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)
+{
+ switch (alive_intr_ctxt) {
+ case BTINTEL_PCIE_ROM:
+ return "rom";
+ case BTINTEL_PCIE_FW_DL:
+ return "fw_dl";
+ case BTINTEL_PCIE_D0:
+ return "d0";
+ case BTINTEL_PCIE_D3:
+ return "d3";
+ case BTINTEL_PCIE_HCI_RESET:
+ return "hci_reset";
+ case BTINTEL_PCIE_INTEL_HCI_RESET1:
+ return "intel_reset1";
+ case BTINTEL_PCIE_INTEL_HCI_RESET2:
+ return "intel_reset2";
+ default:
+ return "unknown";
+ }
+}
+
/* This function handles the MSI-X interrupt for gp0 cause (bit 0 in
* BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES) which is sent for boot stage and image response.
*/
static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
{
- u32 reg;
+ bool submit_rx, signal_waitq;
+ u32 reg, old_ctxt;
/* This interrupt is for three different causes and it is not easy to
* know what causes the interrupt. So, it compares each register value
@@ -317,20 +409,87 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
if (reg != data->boot_stage_cache)
data->boot_stage_cache = reg;
+ bt_dev_dbg(data->hdev, "Alive context: %s old_boot_stage: 0x%8.8x new_boot_stage: 0x%8.8x",
+ btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt),
+ data->boot_stage_cache, reg);
reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IMG_RESPONSE_REG);
if (reg != data->img_resp_cache)
data->img_resp_cache = reg;
data->gp0_received = true;
- /* If the boot stage is OP or IML, reset IA and start RX again */
- if (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW ||
- data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) {
+ old_ctxt = data->alive_intr_ctxt;
+ submit_rx = false;
+ signal_waitq = false;
+
+ switch (data->alive_intr_ctxt) {
+ case BTINTEL_PCIE_ROM:
+ data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
+ signal_waitq = true;
+ break;
+ case BTINTEL_PCIE_FW_DL:
+ /* Error case is already handled. Ideally control shall not
+ * reach here
+ */
+ break;
+ case BTINTEL_PCIE_INTEL_HCI_RESET1:
+ if (btintel_pcie_in_op(data)) {
+ submit_rx = true;
+ break;
+ }
+
+ if (btintel_pcie_in_iml(data)) {
+ submit_rx = true;
+ data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
+ break;
+ }
+ break;
+ case BTINTEL_PCIE_INTEL_HCI_RESET2:
+ if (btintel_test_and_clear_flag(data->hdev, INTEL_WAIT_FOR_D0)) {
+ btintel_wake_up_flag(data->hdev, INTEL_WAIT_FOR_D0);
+ data->alive_intr_ctxt = BTINTEL_PCIE_D0;
+ }
+ break;
+ case BTINTEL_PCIE_D0:
+ if (btintel_pcie_in_d3(data)) {
+ data->alive_intr_ctxt = BTINTEL_PCIE_D3;
+ signal_waitq = true;
+ break;
+ }
+ break;
+ case BTINTEL_PCIE_D3:
+ if (btintel_pcie_in_d0(data)) {
+ data->alive_intr_ctxt = BTINTEL_PCIE_D0;
+ submit_rx = true;
+ signal_waitq = true;
+ break;
+ }
+ break;
+ case BTINTEL_PCIE_HCI_RESET:
+ data->alive_intr_ctxt = BTINTEL_PCIE_D0;
+ submit_rx = true;
+ signal_waitq = true;
+ break;
+ default:
+ bt_dev_err(data->hdev, "Unknown state: 0x%2.2x",
+ data->alive_intr_ctxt);
+ break;
+ }
+
+ if (submit_rx) {
btintel_pcie_reset_ia(data);
btintel_pcie_start_rx(data);
}
- wake_up(&data->gp0_wait_q);
+ if (signal_waitq) {
+ bt_dev_dbg(data->hdev, "wake up gp0 wait_q");
+ wake_up(&data->gp0_wait_q);
+ }
+
+ if (old_ctxt != data->alive_intr_ctxt)
+ bt_dev_dbg(data->hdev, "alive context changed: %s -> %s",
+ btintel_pcie_alivectxt_state2str(old_ctxt),
+ btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
}
/* This function handles the MSX-X interrupt for rx queue 0 which is for TX
@@ -364,6 +523,83 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
}
}
+static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_event_hdr *hdr = (void *)skb->data;
+ const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
+ struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+
+ if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
+ hdr->plen > 0) {
+ const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
+ unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
+
+ if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
+ switch (skb->data[2]) {
+ case 0x02:
+ /* When switching to the operational firmware
+ * the device sends a vendor specific event
+ * indicating that the bootup completed.
+ */
+ btintel_bootup(hdev, ptr, len);
+
+ /* If bootup event is from operational image,
+ * driver needs to write sleep control register to
+ * move into D0 state
+ */
+ if (btintel_pcie_in_op(data)) {
+ btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0);
+ data->alive_intr_ctxt = BTINTEL_PCIE_INTEL_HCI_RESET2;
+ kfree_skb(skb);
+ return 0;
+ }
+
+ if (btintel_pcie_in_iml(data)) {
+ /* In case of IML, there is no concept
+ * of D0 transition. Just mimic as if
+ * IML moved to D0 by clearing INTEL_WAIT_FOR_D0
+ * bit and waking up the task waiting on
+ * INTEL_WAIT_FOR_D0. This is required
+ * as intel_boot() is common function for
+ * both IML and OP image loading.
+ */
+ if (btintel_test_and_clear_flag(data->hdev,
+ INTEL_WAIT_FOR_D0))
+ btintel_wake_up_flag(data->hdev,
+ INTEL_WAIT_FOR_D0);
+ }
+ kfree_skb(skb);
+ return 0;
+ case 0x06:
+ /* When the firmware loading completes the
+ * device sends out a vendor specific event
+ * indicating the result of the firmware
+ * loading.
+ */
+ btintel_secure_send_result(hdev, ptr, len);
+ kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ /* Handle all diagnostics events separately. May still call
+ * hci_recv_frame.
+ */
+ if (len >= sizeof(diagnostics_hdr) &&
+ memcmp(&skb->data[2], diagnostics_hdr,
+ sizeof(diagnostics_hdr)) == 0) {
+ return btintel_diagnostics(hdev, skb);
+ }
+
+ /* This is a debug event that comes from IML and OP image when it
+ * starts execution. There is no need pass this event to stack.
+ */
+ if (skb->data[2] == 0x97)
+ return 0;
+ }
+
+ return hci_recv_frame(hdev, skb);
+}
/* Process the received rx data
* It check the frame header to identify the data type and create skb
* and calling HCI API
@@ -465,7 +701,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
hdev->stat.byte_rx += plen;
if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT)
- ret = btintel_recv_event(hdev, new_skb);
+ ret = btintel_pcie_recv_event(hdev, new_skb);
else
ret = hci_recv_frame(hdev, new_skb);
@@ -516,10 +752,8 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status
buf += sizeof(*rfh_hdr);
skb = alloc_skb(len, GFP_ATOMIC);
- if (!skb) {
- ret = -ENOMEM;
+ if (!skb)
goto resubmit;
- }
skb_put_data(skb, buf, len);
skb_queue_tail(&data->rx_skb_q, skb);
@@ -734,13 +968,9 @@ static int btintel_pcie_config_pcie(struct pci_dev *pdev,
return err;
}
- err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
- if (err)
- return err;
-
- data->base_addr = pcim_iomap_table(pdev)[0];
- if (!data->base_addr)
- return -ENODEV;
+ data->base_addr = pcim_iomap_region(pdev, 0, KBUILD_MODNAME);
+ if (IS_ERR(data->base_addr))
+ return PTR_ERR(data->base_addr);
err = btintel_pcie_setup_irq(data);
if (err)
@@ -1053,8 +1283,11 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+ struct hci_command_hdr *cmd;
+ __u16 opcode = ~0;
int ret;
u32 type;
+ u32 old_ctxt;
/* Due to the fw limitation, the type header of the packet should be
* 4 bytes unlike 1 byte for UART. In UART, the firmware can read
@@ -1073,6 +1306,8 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
switch (hci_skb_pkt_type(skb)) {
case HCI_COMMAND_PKT:
type = BTINTEL_PCIE_HCI_CMD_PKT;
+ cmd = (void *)skb->data;
+ opcode = le16_to_cpu(cmd->opcode);
if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
struct hci_command_hdr *cmd = (void *)skb->data;
__u16 opcode = le16_to_cpu(cmd->opcode);
@@ -1111,6 +1346,30 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
bt_dev_err(hdev, "Failed to send frame (%d)", ret);
goto exit_error;
}
+
+ if (type == BTINTEL_PCIE_HCI_CMD_PKT &&
+ (opcode == HCI_OP_RESET || opcode == 0xfc01)) {
+ old_ctxt = data->alive_intr_ctxt;
+ data->alive_intr_ctxt =
+ (opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
+ BTINTEL_PCIE_HCI_RESET);
+ bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s",
+ opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
+ btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
+ if (opcode == HCI_OP_RESET) {
+ data->gp0_received = false;
+ ret = wait_event_timeout(data->gp0_wait_q,
+ data->gp0_received,
+ msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
+ if (!ret) {
+ hdev->stat.err_tx++;
+ bt_dev_err(hdev, "No alive interrupt received for %s",
+ btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
+ ret = -ETIME;
+ goto exit_error;
+ }
+ }
+ }
hdev->stat.byte_tx += skb->len;
kfree_skb(skb);
@@ -1128,7 +1387,7 @@ static void btintel_pcie_release_hdev(struct btintel_pcie_data *data)
data->hdev = NULL;
}
-static int btintel_pcie_setup(struct hci_dev *hdev)
+static int btintel_pcie_setup_internal(struct hci_dev *hdev)
{
const u8 param[1] = { 0xFF };
struct intel_version_tlv ver_tlv;
@@ -1219,6 +1478,32 @@ exit_error:
return err;
}
+static int btintel_pcie_setup(struct hci_dev *hdev)
+{
+ int err, fw_dl_retry = 0;
+ struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+
+ while ((err = btintel_pcie_setup_internal(hdev)) && fw_dl_retry++ < 1) {
+ bt_dev_err(hdev, "Firmware download retry count: %d",
+ fw_dl_retry);
+ err = btintel_pcie_reset_bt(data);
+ if (err) {
+ bt_dev_err(hdev, "Failed to do shr reset: %d", err);
+ break;
+ }
+ usleep_range(10000, 12000);
+ btintel_pcie_reset_ia(data);
+ btintel_pcie_config_msix(data);
+ err = btintel_pcie_enable_bt(data);
+ if (err) {
+ bt_dev_err(hdev, "Failed to enable hardware: %d", err);
+ break;
+ }
+ btintel_pcie_start_rx(data);
+ }
+ return err;
+}
+
static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
{
int err;
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index baaff70420f5..f9aada0543c4 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -12,6 +12,7 @@
#define BTINTEL_PCIE_CSR_HW_REV_REG (BTINTEL_PCIE_CSR_BASE + 0x028)
#define BTINTEL_PCIE_CSR_RF_ID_REG (BTINTEL_PCIE_CSR_BASE + 0x09C)
#define BTINTEL_PCIE_CSR_BOOT_STAGE_REG (BTINTEL_PCIE_CSR_BASE + 0x108)
+#define BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG (BTINTEL_PCIE_CSR_BASE + 0x114)
#define BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG (BTINTEL_PCIE_CSR_BASE + 0x118)
#define BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG (BTINTEL_PCIE_CSR_BASE + 0x11C)
#define BTINTEL_PCIE_CSR_IMG_RESPONSE_REG (BTINTEL_PCIE_CSR_BASE + 0x12C)
@@ -22,6 +23,8 @@
#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT (BIT(6))
#define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT (BIT(7))
#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20))
+#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS (BIT(28))
+#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON (BIT(29))
#define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET (BIT(31))
/* Value for BTINTEL_PCIE_CSR_BOOT_STAGE register */
@@ -32,6 +35,7 @@
#define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN (BIT(11))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16))
#define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23))
+#define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY (BIT(24))
/* Registers for MSI-X */
#define BTINTEL_PCIE_CSR_MSIX_BASE (0x2000)
@@ -55,6 +59,16 @@ enum msix_hw_int_causes {
BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0 = BIT(0), /* cause 32 */
};
+/* PCIe device states
+ * Host-Device interface is active
+ * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD)
+ * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD)
+ */
+enum {
+ BTINTEL_PCIE_STATE_D0 = 0,
+ BTINTEL_PCIE_STATE_D3_HOT = 2,
+ BTINTEL_PCIE_STATE_D3_COLD = 3,
+};
#define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)
/* Minimum and Maximum number of MSI-X Vector
@@ -67,7 +81,7 @@ enum msix_hw_int_causes {
#define BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US 200000
/* Default interrupt timeout in msec */
-#define BTINTEL_DEFAULT_INTR_TIMEOUT 3000
+#define BTINTEL_DEFAULT_INTR_TIMEOUT_MS 3000
/* The number of descriptors in TX/RX queues */
#define BTINTEL_DESCS_COUNT 16
@@ -343,6 +357,7 @@ struct rxq {
* @ia: Index Array struct
* @txq: TX Queue struct
* @rxq: RX Queue struct
+ * @alive_intr_ctxt: Alive interrupt context
*/
struct btintel_pcie_data {
struct pci_dev *pdev;
@@ -389,6 +404,7 @@ struct btintel_pcie_data {
struct ia ia;
struct txq txq;
struct rxq rxq;
+ u32 alive_intr_ctxt;
};
static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 9bbf20502163..8a3f7c3fcfec 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -324,7 +324,7 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_params.data = NULL;
wmt_params.status = NULL;
- /* Activate funciton the firmware providing to */
+ /* Activate function the firmware providing to */
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
@@ -1215,7 +1215,6 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev)
struct sk_buff *skb;
int err;
- init_usb_anchor(&btmtk_data->isopkt_anchor);
spin_lock_init(&btmtk_data->isorxlock);
__set_mtk_intr_interface(hdev);
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index 11d33cd7b08f..a1dfcfe43d3a 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -681,7 +681,7 @@ static int btmtksdio_open(struct hci_dev *hdev)
if (err < 0)
goto err_release_irq;
- /* Explitly set write-1-clear method */
+ /* Explicitly set write-1-clear method */
val = sdio_readl(bdev->func, MTK_REG_CHCR, &err);
if (err < 0)
goto err_release_irq;
@@ -1328,6 +1328,8 @@ static int btmtksdio_probe(struct sdio_func *func,
{
struct btmtksdio_dev *bdev;
struct hci_dev *hdev;
+ struct device_node *old_node;
+ bool restore_node;
int err;
bdev = devm_kzalloc(&func->dev, sizeof(*bdev), GFP_KERNEL);
@@ -1396,7 +1398,7 @@ static int btmtksdio_probe(struct sdio_func *func,
if (pm_runtime_enabled(bdev->dev))
pm_runtime_disable(bdev->dev);
- /* As explaination in drivers/mmc/core/sdio_bus.c tells us:
+ /* As explanation in drivers/mmc/core/sdio_bus.c tells us:
* Unbound SDIO functions are always suspended.
* During probe, the function is set active and the usage count
* is incremented. If the driver supports runtime PM,
@@ -1411,13 +1413,24 @@ static int btmtksdio_probe(struct sdio_func *func,
if (err)
bt_dev_err(hdev, "failed to initialize device wakeup");
- bdev->dev->of_node = of_find_compatible_node(NULL, NULL,
- "mediatek,mt7921s-bluetooth");
+ restore_node = false;
+ if (!of_device_is_compatible(bdev->dev->of_node, "mediatek,mt7921s-bluetooth")) {
+ restore_node = true;
+ old_node = bdev->dev->of_node;
+ bdev->dev->of_node = of_find_compatible_node(NULL, NULL,
+ "mediatek,mt7921s-bluetooth");
+ }
+
bdev->reset = devm_gpiod_get_optional(bdev->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(bdev->reset))
err = PTR_ERR(bdev->reset);
+ if (restore_node) {
+ of_node_put(bdev->dev->of_node);
+ bdev->dev->of_node = old_node;
+ }
+
return err;
}
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index 64e4d835af52..c97e260fcb0c 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -327,7 +327,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count,
if (count <= 0)
return NULL;
- /* Tranlate to how much the size of data H4 can handle so far */
+ /* Translate to how much the size of data H4 can handle so far */
*sz_h4 = min_t(int, count, bdev->stp_dlen);
/* Update the remaining size of STP packet */
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 5ea0d23e88c0..569f5b7d6e46 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -16,6 +16,7 @@
#include <linux/crc8.h>
#include <linux/crc32.h>
#include <linux/string_helpers.h>
+#include <linux/gpio/consumer.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -34,16 +35,17 @@
/* NXP HW err codes */
#define BTNXPUART_IR_HW_ERR 0xb0
-#define FIRMWARE_W8987 "uart8987_bt_v0.bin"
+#define FIRMWARE_W8987 "uart8987_bt.bin"
#define FIRMWARE_W8987_OLD "uartuart8987_bt.bin"
#define FIRMWARE_W8997 "uart8997_bt_v4.bin"
#define FIRMWARE_W8997_OLD "uartuart8997_bt_v4.bin"
#define FIRMWARE_W9098 "uart9098_bt_v1.bin"
#define FIRMWARE_W9098_OLD "uartuart9098_bt_v1.bin"
-#define FIRMWARE_IW416 "uartiw416_bt_v0.bin"
+#define FIRMWARE_IW416 "uartiw416_bt.bin"
+#define FIRMWARE_IW416_OLD "uartiw416_bt_v0.bin"
#define FIRMWARE_IW612 "uartspi_n61x_v1.bin.se"
-#define FIRMWARE_IW615 "uartspi_iw610_v0.bin"
-#define FIRMWARE_SECURE_IW615 "uartspi_iw610_v0.bin.se"
+#define FIRMWARE_IW610 "uartspi_iw610.bin"
+#define FIRMWARE_SECURE_IW610 "uartspi_iw610.bin.se"
#define FIRMWARE_IW624 "uartiw624_bt.bin"
#define FIRMWARE_SECURE_IW624 "uartiw624_bt.bin.se"
#define FIRMWARE_AW693 "uartaw693_bt.bin"
@@ -59,8 +61,8 @@
#define CHIP_ID_IW624c 0x8001
#define CHIP_ID_AW693a0 0x8200
#define CHIP_ID_AW693a1 0x8201
-#define CHIP_ID_IW615a0 0x8800
-#define CHIP_ID_IW615a1 0x8801
+#define CHIP_ID_IW610a0 0x8800
+#define CHIP_ID_IW610a1 0x8801
#define FW_SECURE_MASK 0xc0
#define FW_OPEN 0x00
@@ -81,6 +83,7 @@
#define WAKEUP_METHOD_BREAK 1
#define WAKEUP_METHOD_EXT_BREAK 2
#define WAKEUP_METHOD_RTS 3
+#define WAKEUP_METHOD_GPIO 4
#define WAKEUP_METHOD_INVALID 0xff
/* power save mode status */
@@ -134,6 +137,7 @@ struct ps_data {
bool driver_sent_cmd;
u16 h2c_ps_interval;
u16 c2h_ps_interval;
+ struct gpio_desc *h2c_ps_gpio;
struct hci_dev *hdev;
struct work_struct work;
struct timer_list ps_timer;
@@ -364,7 +368,7 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
struct ps_data *psdata = &nxpdev->psdata;
- int status;
+ int status = 0;
if (psdata->ps_state == ps_state ||
!test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state))
@@ -372,6 +376,14 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)
mutex_lock(&psdata->ps_lock);
switch (psdata->cur_h2c_wakeupmode) {
+ case WAKEUP_METHOD_GPIO:
+ if (ps_state == PS_STATE_AWAKE)
+ gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0);
+ else
+ gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 1);
+ bt_dev_dbg(hdev, "Set h2c_ps_gpio: %s",
+ str_high_low(ps_state == PS_STATE_SLEEP));
+ break;
case WAKEUP_METHOD_DTR:
if (ps_state == PS_STATE_AWAKE)
status = serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
@@ -421,15 +433,29 @@ static void ps_timeout_func(struct timer_list *t)
}
}
-static void ps_setup(struct hci_dev *hdev)
+static int ps_setup(struct hci_dev *hdev)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
+ struct serdev_device *serdev = nxpdev->serdev;
struct ps_data *psdata = &nxpdev->psdata;
+ psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(psdata->h2c_ps_gpio)) {
+ bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld",
+ PTR_ERR(psdata->h2c_ps_gpio));
+ return PTR_ERR(psdata->h2c_ps_gpio);
+ }
+
+ if (!psdata->h2c_ps_gpio)
+ psdata->h2c_wakeup_gpio = 0xff;
+
psdata->hdev = hdev;
INIT_WORK(&psdata->work, ps_work_func);
mutex_init(&psdata->ps_lock);
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
+
+ return 0;
}
static bool ps_wakeup(struct btnxpuart_dev *nxpdev)
@@ -515,6 +541,9 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data)
pcmd.c2h_wakeupmode = psdata->c2h_wakeupmode;
pcmd.c2h_wakeup_gpio = psdata->c2h_wakeup_gpio;
switch (psdata->h2c_wakeupmode) {
+ case WAKEUP_METHOD_GPIO:
+ pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_GPIO;
+ break;
case WAKEUP_METHOD_DTR:
pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_DSR;
break;
@@ -549,6 +578,7 @@ static void ps_init(struct hci_dev *hdev)
{
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
struct ps_data *psdata = &nxpdev->psdata;
+ u8 default_h2c_wakeup_mode = DEFAULT_H2C_WAKEUP_MODE;
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_RTS);
usleep_range(5000, 10000);
@@ -560,8 +590,17 @@ static void ps_init(struct hci_dev *hdev)
psdata->c2h_wakeup_gpio = 0xff;
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
+ if (psdata->h2c_ps_gpio)
+ default_h2c_wakeup_mode = WAKEUP_METHOD_GPIO;
+
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
- switch (DEFAULT_H2C_WAKEUP_MODE) {
+
+ switch (default_h2c_wakeup_mode) {
+ case WAKEUP_METHOD_GPIO:
+ psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO;
+ gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0);
+ usleep_range(5000, 10000);
+ break;
case WAKEUP_METHOD_DTR:
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
@@ -946,12 +985,12 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
- case CHIP_ID_IW615a0:
- case CHIP_ID_IW615a1:
+ case CHIP_ID_IW610a0:
+ case CHIP_ID_IW610a1:
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
- fw_name = FIRMWARE_IW615;
+ fw_name = FIRMWARE_IW610;
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
- fw_name = FIRMWARE_SECURE_IW615;
+ fw_name = FIRMWARE_SECURE_IW610;
else
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
break;
@@ -971,6 +1010,9 @@ static char *nxp_get_old_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
case CHIP_ID_W9098:
fw_name_old = FIRMWARE_W9098_OLD;
break;
+ case CHIP_ID_IW416:
+ fw_name_old = FIRMWARE_IW416_OLD;
+ break;
}
return fw_name_old;
}
@@ -1275,6 +1317,9 @@ static int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb)
psdata->c2h_wakeup_gpio = wakeup_parm.c2h_wakeup_gpio;
psdata->h2c_wakeup_gpio = wakeup_parm.h2c_wakeup_gpio;
switch (wakeup_parm.h2c_wakeupmode) {
+ case BT_CTRL_WAKEUP_METHOD_GPIO:
+ psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO;
+ break;
case BT_CTRL_WAKEUP_METHOD_DSR:
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
break;
@@ -1505,13 +1550,17 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
if (hci_register_dev(hdev) < 0) {
dev_err(&serdev->dev, "Can't register HCI device\n");
- hci_free_dev(hdev);
- return -ENODEV;
+ goto probe_fail;
}
- ps_setup(hdev);
+ if (ps_setup(hdev))
+ goto probe_fail;
return 0;
+
+probe_fail:
+ hci_free_dev(hdev);
+ return -ENODEV;
}
static void nxp_serdev_remove(struct serdev_device *serdev)
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 0bcb44cf7b31..83025f457ca0 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -1371,7 +1371,7 @@ int btrtl_shutdown_realtek(struct hci_dev *hdev)
/* According to the vendor driver, BT must be reset on close to avoid
* firmware crash.
*/
- skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "HCI reset during shutdown failed");
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e9534fbc92e3..279fe6c115fa 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -371,6 +371,12 @@ static const struct usb_device_id quirks_table[] = {
/* QCA WCN785x chipset */
{ USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe0fc), .driver_info = BTUSB_QCA_WCN6855 |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe0f3), .driver_info = BTUSB_QCA_WCN6855 |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3623), .driver_info = BTUSB_QCA_WCN6855 |
+ BTUSB_WIDEBAND_SPEECH },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@@ -524,6 +530,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
@@ -563,6 +571,16 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x043e, 0x3109), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
+ /* Additional MediaTek MT7920 Bluetooth devices */
+ { USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3622), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+
/* Additional MediaTek MT7921 Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
@@ -630,12 +648,24 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
/* Additional MediaTek MT7925 Bluetooth devices */
+ { USB_DEVICE(0x0489, 0xe111), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe113), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe118), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe11e), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe124), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0489, 0xe151), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK |
@@ -846,6 +876,7 @@ struct btusb_data {
int (*suspend)(struct hci_dev *hdev);
int (*resume)(struct hci_dev *hdev);
+ int (*disconnect)(struct hci_dev *hdev);
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
unsigned cmd_timeout_cnt;
@@ -1061,7 +1092,7 @@ static inline void btusb_free_frags(struct btusb_data *data)
static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb)
{
if (data->intr_interval) {
- /* Trigger dequeue immediatelly if an event is received */
+ /* Trigger dequeue immediately if an event is received */
schedule_delayed_work(&data->rx_work, 0);
}
@@ -2616,13 +2647,14 @@ static void btusb_mtk_claim_iso_intf(struct btusb_data *data)
}
set_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
+ init_usb_anchor(&btmtk_data->isopkt_anchor);
}
-static void btusb_mtk_release_iso_intf(struct btusb_data *data)
+static void btusb_mtk_release_iso_intf(struct hci_dev *hdev)
{
- struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
+ struct btmtk_data *btmtk_data = hci_get_priv(hdev);
- if (btmtk_data->isopkt_intf) {
+ if (test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) {
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
@@ -2636,6 +2668,16 @@ static void btusb_mtk_release_iso_intf(struct btusb_data *data)
clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
}
+static int btusb_mtk_disconnect(struct hci_dev *hdev)
+{
+ /* This function describes the specific additional steps taken by MediaTek
+ * when Bluetooth usb driver's resume function is called.
+ */
+ btusb_mtk_release_iso_intf(hdev);
+
+ return 0;
+}
+
static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2652,8 +2694,8 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
if (err < 0)
return err;
- if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
- btusb_mtk_release_iso_intf(data);
+ /* Release MediaTek ISO data interface */
+ btusb_mtk_release_iso_intf(hdev);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
@@ -2698,22 +2740,24 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
btmtk_data->reset_sync = btusb_mtk_reset;
/* Claim ISO data interface and endpoint */
- btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM);
- if (btmtk_data->isopkt_intf)
+ if (!test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) {
+ btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM);
btusb_mtk_claim_iso_intf(data);
+ }
return btmtk_usb_setup(hdev);
}
static int btusb_mtk_shutdown(struct hci_dev *hdev)
{
- struct btusb_data *data = hci_get_drvdata(hdev);
- struct btmtk_data *btmtk_data = hci_get_priv(hdev);
+ int ret;
- if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
- btusb_mtk_release_iso_intf(data);
+ ret = btmtk_usb_shutdown(hdev);
- return btmtk_usb_shutdown(hdev);
+ /* Release MediaTek iso interface after shutdown */
+ btusb_mtk_release_iso_intf(hdev);
+
+ return ret;
}
#ifdef CONFIG_PM
@@ -3825,6 +3869,7 @@ static int btusb_probe(struct usb_interface *intf,
data->recv_acl = btmtk_usb_recv_acl;
data->suspend = btmtk_usb_suspend;
data->resume = btmtk_usb_resume;
+ data->disconnect = btusb_mtk_disconnect;
}
if (id->driver_info & BTUSB_SWAVE) {
@@ -3896,6 +3941,8 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks);
+ set_bit(HCI_QUIRK_BROKEN_EXT_CREATE_CONN, &hdev->quirks);
+ set_bit(HCI_QUIRK_BROKEN_WRITE_AUTH_PAYLOAD_TIMEOUT, &hdev->quirks);
}
if (!reset)
@@ -4013,6 +4060,9 @@ static void btusb_disconnect(struct usb_interface *intf)
if (data->diag)
usb_set_intfdata(data->diag, NULL);
+ if (data->disconnect)
+ data->disconnect(hdev);
+
hci_unregister_dev(hdev);
if (intf == data->intf) {
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 89d4c2224546..521b785f2908 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -1068,17 +1068,17 @@ static struct clk *bcm_get_txco(struct device *dev)
struct clk *clk;
/* New explicit name */
- clk = devm_clk_get(dev, "txco");
- if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
+ clk = devm_clk_get_optional(dev, "txco");
+ if (clk)
return clk;
/* Deprecated name */
- clk = devm_clk_get(dev, "extclk");
- if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
+ clk = devm_clk_get_optional(dev, "extclk");
+ if (clk)
return clk;
/* Original code used no name at all */
- return devm_clk_get(dev, NULL);
+ return devm_clk_get_optional(dev, NULL);
}
static int bcm_get_resources(struct bcm_device *dev)
@@ -1093,21 +1093,12 @@ static int bcm_get_resources(struct bcm_device *dev)
return 0;
dev->txco_clk = bcm_get_txco(dev->dev);
-
- /* Handle deferred probing */
- if (dev->txco_clk == ERR_PTR(-EPROBE_DEFER))
- return PTR_ERR(dev->txco_clk);
-
- /* Ignore all other errors as before */
if (IS_ERR(dev->txco_clk))
- dev->txco_clk = NULL;
-
- dev->lpo_clk = devm_clk_get(dev->dev, "lpo");
- if (dev->lpo_clk == ERR_PTR(-EPROBE_DEFER))
- return PTR_ERR(dev->lpo_clk);
+ return PTR_ERR(dev->txco_clk);
+ dev->lpo_clk = devm_clk_get_optional(dev->dev, "lpo");
if (IS_ERR(dev->lpo_clk))
- dev->lpo_clk = NULL;
+ return PTR_ERR(dev->lpo_clk);
/* Check if we accidentally fetched the lpo clock twice */
if (dev->lpo_clk && clk_is_match(dev->lpo_clk, dev->txco_clk)) {
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 395d66e32a2e..d2d6ba8d2f8b 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -594,7 +594,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
* Called by tty low level driver when receive data is
* available.
*
- * Arguments: tty pointer to tty isntance data
+ * Arguments: tty pointer to tty instance data
* data pointer to received data
* flags pointer to flags for data
* count count of received data in bytes
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 4a0b5c3160c2..e19e9bd49555 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -305,7 +305,7 @@ static void ll_device_woke_up(struct hci_uart *hu)
hci_uart_tx_wakeup(hu);
}
-/* Enqueue frame for transmittion (padding, crc, etc) */
+/* Enqueue frame for transmission (padding, crc, etc) */
/* may be called from two simultaneous tasklets */
static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c
index 49bbe4975be4..9fc10a16fd96 100644
--- a/drivers/bluetooth/hci_nokia.c
+++ b/drivers/bluetooth/hci_nokia.c
@@ -501,7 +501,7 @@ static int nokia_close(struct hci_uart *hu)
return 0;
}
-/* Enqueue frame for transmittion (padding, crc, etc) */
+/* Enqueue frame for transmission (padding, crc, etc) */
static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct nokia_bt_dev *btdev = hu->priv;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 37fddf6055be..37129e6cb0eb 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -873,7 +873,7 @@ static void device_woke_up(struct hci_uart *hu)
hci_uart_tx_wakeup(hu);
}
-/* Enqueue frame for transmittion (padding, crc, etc) may be called from
+/* Enqueue frame for transmission (padding, crc, etc) may be called from
* two simultaneous tasklets.
*/
static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
@@ -1059,7 +1059,7 @@ static void qca_controller_memdump(struct work_struct *work)
if (!seq_no) {
/* This is the first frame of memdump packet from
- * the controller, Disable IBS to recevie dump
+ * the controller, Disable IBS to receive dump
* with out any interruption, ideally time required for
* the controller to send the dump is 8 seconds. let us
* start timer to handle this asynchronous activity.
@@ -2294,13 +2294,6 @@ static int qca_init_regulators(struct qca_power *qca,
return 0;
}
-static void qca_clk_disable_unprepare(void *data)
-{
- struct clk *clk = data;
-
- clk_disable_unprepare(clk);
-}
-
static int qca_serdev_probe(struct serdev_device *serdev)
{
struct qca_serdev *qcadev;
@@ -2358,7 +2351,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
* Backward compatibility with old DT sources. If the
* node doesn't have the 'enable-gpios' property then
* let's use the power sequencer. Otherwise, let's
- * drive everything outselves.
+ * drive everything ourselves.
*/
qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev,
"bluetooth");
@@ -2433,25 +2426,12 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->bt_en)
power_ctrl_enabled = false;
- qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
+ qcadev->susclk = devm_clk_get_optional_enabled_with_rate(
+ &serdev->dev, NULL, SUSCLK_RATE_32KHZ);
if (IS_ERR(qcadev->susclk)) {
dev_warn(&serdev->dev, "failed to acquire clk\n");
return PTR_ERR(qcadev->susclk);
}
- err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ);
- if (err)
- return err;
-
- err = clk_prepare_enable(qcadev->susclk);
- if (err)
- return err;
-
- err = devm_add_action_or_reset(&serdev->dev,
- qca_clk_disable_unprepare,
- qcadev->susclk);
- if (err)
- return err;
-
}
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
@@ -2530,7 +2510,7 @@ static void qca_serdev_shutdown(struct device *dev)
hci_dev_test_flag(hdev, HCI_SETUP))
return;
- /* The serdev must be in open state when conrol logic arrives
+ /* The serdev must be in open state when control logic arrives
* here, so also fix the use-after-free issue caused by that
* the serdev is flushed or wrote after it is closed.
*/
diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
index cad0048bcc3c..e49a19fea3bd 100644
--- a/drivers/char/tpm/tpm-buf.c
+++ b/drivers/char/tpm/tpm-buf.c
@@ -147,6 +147,26 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
/**
+ * tpm_buf_append_handle() - Add a handle
+ * @chip: &tpm_chip instance
+ * @buf: &tpm_buf instance
+ * @handle: a TPM object handle
+ *
+ * Add a handle to the buffer, and increase the count tracking the number of
+ * handles in the command buffer. Works only for command buffers.
+ */
+void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle)
+{
+ if (buf->flags & TPM_BUF_TPM2B) {
+ dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n");
+ return;
+ }
+
+ tpm_buf_append_u32(buf, handle);
+ buf->handles++;
+}
+
+/**
* tpm_buf_read() - Read from a TPM buffer
* @buf: &tpm_buf instance
* @offset: offset within the buffer
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 854546000c92..7df7abaf3e52 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -525,10 +525,6 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
- /* Give back zero bytes, as TPM chip has not yet fully resumed: */
- if (chip->flags & TPM_CHIP_FLAG_SUSPENDED)
- return 0;
-
return tpm_get_random(chip, data, max);
}
@@ -674,6 +670,16 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
*/
void tpm_chip_unregister(struct tpm_chip *chip)
{
+#ifdef CONFIG_TCG_TPM2_HMAC
+ int rc;
+
+ rc = tpm_try_get_ops(chip);
+ if (!rc) {
+ tpm2_end_auth_session(chip);
+ tpm_put_ops(chip);
+ }
+#endif
+
tpm_del_legacy_sysfs(chip);
if (tpm_is_hwrng_enabled(chip))
hwrng_unregister(&chip->hwrng);
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index c3fbbf4d3db7..48ff87444f85 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -27,6 +27,9 @@ static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space,
struct tpm_header *header = (void *)buf;
ssize_t ret, len;
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ tpm2_end_auth_session(chip);
+
ret = tpm2_prepare_space(chip, space, buf, bufsiz);
/* If the command is not implemented by the TPM, synthesize a
* response with a TPM2_RC_COMMAND_CODE return for user-space.
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 5da134f12c9a..b1daa0d7b341 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -370,6 +370,13 @@ int tpm_pm_suspend(struct device *dev)
if (!chip)
return -ENODEV;
+ rc = tpm_try_get_ops(chip);
+ if (rc) {
+ /* Can be safely set out of locks, as no action cannot race: */
+ chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
+ goto out;
+ }
+
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
goto suspended;
@@ -377,19 +384,19 @@ int tpm_pm_suspend(struct device *dev)
!pm_suspend_via_firmware())
goto suspended;
- rc = tpm_try_get_ops(chip);
- if (!rc) {
- if (chip->flags & TPM_CHIP_FLAG_TPM2)
- tpm2_shutdown(chip, TPM2_SU_STATE);
- else
- rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
-
- tpm_put_ops(chip);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ tpm2_end_auth_session(chip);
+ tpm2_shutdown(chip, TPM2_SU_STATE);
+ goto suspended;
}
+ rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
+
suspended:
chip->flags |= TPM_CHIP_FLAG_SUSPENDED;
+ tpm_put_ops(chip);
+out:
if (rc)
dev_err(dev, "Ignoring error %d while suspending\n", rc);
return 0;
@@ -438,11 +445,18 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
if (!chip)
return -ENODEV;
+ /* Give back zero bytes, as TPM chip has not yet fully resumed: */
+ if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) {
+ rc = 0;
+ goto out;
+ }
+
if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_get_random(chip, out, max);
else
rc = tpm1_get_random(chip, out, max);
+out:
tpm_put_ops(chip);
return rc;
}
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 1e856259219e..dfdcbd009720 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -14,6 +14,10 @@
#include "tpm.h"
#include <crypto/hash_info.h>
+static bool disable_pcr_integrity;
+module_param(disable_pcr_integrity, bool, 0444);
+MODULE_PARM_DESC(disable_pcr_integrity, "Disable integrity protection of TPM2_PCR_Extend");
+
static struct tpm2_hash tpm2_hash_map[] = {
{HASH_ALGO_SHA1, TPM_ALG_SHA1},
{HASH_ALGO_SHA256, TPM_ALG_SHA256},
@@ -232,18 +236,26 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
int rc;
int i;
- rc = tpm2_start_auth_session(chip);
- if (rc)
- return rc;
+ if (!disable_pcr_integrity) {
+ rc = tpm2_start_auth_session(chip);
+ if (rc)
+ return rc;
+ }
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc) {
- tpm2_end_auth_session(chip);
+ if (!disable_pcr_integrity)
+ tpm2_end_auth_session(chip);
return rc;
}
- tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
- tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ if (!disable_pcr_integrity) {
+ tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
+ tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
+ } else {
+ tpm_buf_append_handle(chip, &buf, pcr_idx);
+ tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
+ }
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
@@ -253,9 +265,11 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
chip->allocated_banks[i].digest_size);
}
- tpm_buf_fill_hmac_session(chip, &buf);
+ if (!disable_pcr_integrity)
+ tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
- rc = tpm_buf_check_hmac_response(chip, &buf, rc);
+ if (!disable_pcr_integrity)
+ rc = tpm_buf_check_hmac_response(chip, &buf, rc);
tpm_buf_destroy(&buf);
diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
index 511c67061728..b0f13c8ea79c 100644
--- a/drivers/char/tpm/tpm2-sessions.c
+++ b/drivers/char/tpm/tpm2-sessions.c
@@ -237,9 +237,7 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
#endif
if (!tpm2_chip_auth(chip)) {
- tpm_buf_append_u32(buf, handle);
- /* count the number of handles in the upper bits of flags */
- buf->handles++;
+ tpm_buf_append_handle(chip, buf, handle);
return;
}
@@ -272,6 +270,31 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
+void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
+ u8 attributes, u8 *passphrase, int passphrase_len)
+{
+ /* offset tells us where the sessions area begins */
+ int offset = buf->handles * 4 + TPM_HEADER_SIZE;
+ u32 len = 9 + passphrase_len;
+
+ if (tpm_buf_length(buf) != offset) {
+ /* not the first session so update the existing length */
+ len += get_unaligned_be32(&buf->data[offset]);
+ put_unaligned_be32(len, &buf->data[offset]);
+ } else {
+ tpm_buf_append_u32(buf, len);
+ }
+ /* auth handle */
+ tpm_buf_append_u32(buf, TPM2_RS_PW);
+ /* nonce */
+ tpm_buf_append_u16(buf, 0);
+ /* attributes */
+ tpm_buf_append_u8(buf, 0);
+ /* passphrase */
+ tpm_buf_append_u16(buf, passphrase_len);
+ tpm_buf_append(buf, passphrase, passphrase_len);
+}
+
/**
* tpm_buf_append_hmac_session() - Append a TPM session element
* @chip: the TPM chip structure
@@ -309,30 +332,15 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
#endif
if (!tpm2_chip_auth(chip)) {
- /* offset tells us where the sessions area begins */
- int offset = buf->handles * 4 + TPM_HEADER_SIZE;
- u32 len = 9 + passphrase_len;
-
- if (tpm_buf_length(buf) != offset) {
- /* not the first session so update the existing length */
- len += get_unaligned_be32(&buf->data[offset]);
- put_unaligned_be32(len, &buf->data[offset]);
- } else {
- tpm_buf_append_u32(buf, len);
- }
- /* auth handle */
- tpm_buf_append_u32(buf, TPM2_RS_PW);
- /* nonce */
- tpm_buf_append_u16(buf, 0);
- /* attributes */
- tpm_buf_append_u8(buf, 0);
- /* passphrase */
- tpm_buf_append_u16(buf, passphrase_len);
- tpm_buf_append(buf, passphrase, passphrase_len);
+ tpm_buf_append_auth(chip, buf, attributes, passphrase,
+ passphrase_len);
return;
}
#ifdef CONFIG_TCG_TPM2_HMAC
+ /* The first write to /dev/tpm{rm0} will flush the session. */
+ attributes |= TPM2_SA_CONTINUE_SESSION;
+
/*
* The Architecture Guide requires us to strip trailing zeros
* before computing the HMAC
@@ -484,7 +492,8 @@ static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
sha256_final(&sctx, out);
}
-static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
+static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
+ struct tpm2_auth *auth)
{
struct crypto_kpp *kpp;
struct kpp_request *req;
@@ -543,7 +552,7 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
sg_set_buf(&s[0], chip->null_ec_key_x, EC_PT_SZ);
sg_set_buf(&s[1], chip->null_ec_key_y, EC_PT_SZ);
kpp_request_set_input(req, s, EC_PT_SZ*2);
- sg_init_one(d, chip->auth->salt, EC_PT_SZ);
+ sg_init_one(d, auth->salt, EC_PT_SZ);
kpp_request_set_output(req, d, EC_PT_SZ);
crypto_kpp_compute_shared_secret(req);
kpp_request_free(req);
@@ -554,8 +563,7 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
* This works because KDFe fully consumes the secret before it
* writes the salt
*/
- tpm2_KDFe(chip->auth->salt, "SECRET", x, chip->null_ec_key_x,
- chip->auth->salt);
+ tpm2_KDFe(auth->salt, "SECRET", x, chip->null_ec_key_x, auth->salt);
out:
crypto_free_kpp(kpp);
@@ -853,7 +861,9 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
if (rc)
/* manually close the session if it wasn't consumed */
tpm2_flush_context(chip, auth->handle);
- memzero_explicit(auth, sizeof(*auth));
+
+ kfree_sensitive(auth);
+ chip->auth = NULL;
} else {
/* reset for next use */
auth->session = TPM_HEADER_SIZE;
@@ -881,7 +891,8 @@ void tpm2_end_auth_session(struct tpm_chip *chip)
return;
tpm2_flush_context(chip, auth->handle);
- memzero_explicit(auth, sizeof(*auth));
+ kfree_sensitive(auth);
+ chip->auth = NULL;
}
EXPORT_SYMBOL(tpm2_end_auth_session);
@@ -915,32 +926,39 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
{
- int rc;
unsigned int offset = 0; /* dummy offset for null seed context */
u8 name[SHA256_DIGEST_SIZE + 2];
+ u32 tmp_null_key;
+ int rc;
rc = tpm2_load_context(chip, chip->null_key_context, &offset,
- null_key);
- if (rc != -EINVAL)
- return rc;
+ &tmp_null_key);
+ if (rc != -EINVAL) {
+ if (!rc)
+ *null_key = tmp_null_key;
+ goto err;
+ }
- /* an integrity failure may mean the TPM has been reset */
- dev_err(&chip->dev, "NULL key integrity failure!\n");
- /* check the null name against what we know */
- tpm2_create_primary(chip, TPM2_RH_NULL, NULL, name);
- if (memcmp(name, chip->null_key_name, sizeof(name)) == 0)
- /* name unchanged, assume transient integrity failure */
- return rc;
- /*
- * Fatal TPM failure: the NULL seed has actually changed, so
- * the TPM must have been illegally reset. All in-kernel TPM
- * operations will fail because the NULL primary can't be
- * loaded to salt the sessions, but disable the TPM anyway so
- * userspace programmes can't be compromised by it.
- */
- dev_err(&chip->dev, "NULL name has changed, disabling TPM due to interference\n");
- chip->flags |= TPM_CHIP_FLAG_DISABLE;
+ /* Try to re-create null key, given the integrity failure: */
+ rc = tpm2_create_primary(chip, TPM2_RH_NULL, &tmp_null_key, name);
+ if (rc)
+ goto err;
+
+ /* Return null key if the name has not been changed: */
+ if (!memcmp(name, chip->null_key_name, sizeof(name))) {
+ *null_key = tmp_null_key;
+ return 0;
+ }
+
+ /* Deduce from the name change TPM interference: */
+ dev_err(&chip->dev, "null key integrity check failed\n");
+ tpm2_flush_context(chip, tmp_null_key);
+err:
+ if (rc) {
+ chip->flags |= TPM_CHIP_FLAG_DISABLE;
+ rc = -ENODEV;
+ }
return rc;
}
@@ -958,16 +976,20 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
*/
int tpm2_start_auth_session(struct tpm_chip *chip)
{
+ struct tpm2_auth *auth;
struct tpm_buf buf;
- struct tpm2_auth *auth = chip->auth;
- int rc;
u32 null_key;
+ int rc;
- if (!auth) {
- dev_warn_once(&chip->dev, "auth session is not active\n");
+ if (chip->auth) {
+ dev_warn_once(&chip->dev, "auth session is active\n");
return 0;
}
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth)
+ return -ENOMEM;
+
rc = tpm2_load_null(chip, &null_key);
if (rc)
goto out;
@@ -988,7 +1010,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
/* append encrypted salt and squirrel away unencrypted in auth */
- tpm_buf_append_salt(&buf, chip);
+ tpm_buf_append_salt(&buf, chip, auth);
/* session type (HMAC, audit or policy) */
tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
@@ -1010,10 +1032,13 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
tpm_buf_destroy(&buf);
- if (rc)
- goto out;
+ if (rc == TPM2_RC_SUCCESS) {
+ chip->auth = auth;
+ return 0;
+ }
- out:
+out:
+ kfree_sensitive(auth);
return rc;
}
EXPORT_SYMBOL(tpm2_start_auth_session);
@@ -1347,18 +1372,21 @@ static int tpm2_create_null_primary(struct tpm_chip *chip)
*
* Derive and context save the null primary and allocate memory in the
* struct tpm_chip for the authorizations.
+ *
+ * Return:
+ * * 0 - OK
+ * * -errno - A system error
+ * * TPM_RC - A TPM error
*/
int tpm2_sessions_init(struct tpm_chip *chip)
{
int rc;
rc = tpm2_create_null_primary(chip);
- if (rc)
- dev_err(&chip->dev, "TPM: security failed (NULL seed derivation): %d\n", rc);
-
- chip->auth = kmalloc(sizeof(*chip->auth), GFP_KERNEL);
- if (!chip->auth)
- return -ENOMEM;
+ if (rc) {
+ dev_err(&chip->dev, "null key creation failed with %d\n", rc);
+ return rc;
+ }
return rc;
}
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index f9105443d7db..be9bee6ab65f 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -40,7 +40,7 @@
#define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL])
# define PLL_POST_DIV_SHIFT 8
-# define PLL_POST_DIV_MASK(p) GENMASK((p)->width - 1, 0)
+# define PLL_POST_DIV_MASK(p) GENMASK((p)->width ? (p)->width - 1 : 3, 0)
# define PLL_ALPHA_MSB BIT(15)
# define PLL_ALPHA_EN BIT(24)
# define PLL_ALPHA_MODE BIT(25)
diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c
index 0f578771071f..8ea25aa25dff 100644
--- a/drivers/clk/qcom/gcc-x1e80100.c
+++ b/drivers/clk/qcom/gcc-x1e80100.c
@@ -3123,7 +3123,7 @@ static struct clk_branch gcc_pcie_3_pipe_clk = {
static struct clk_branch gcc_pcie_3_pipediv2_clk = {
.halt_reg = 0x58060,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52020,
.enable_mask = BIT(5),
@@ -3248,7 +3248,7 @@ static struct clk_branch gcc_pcie_4_pipe_clk = {
static struct clk_branch gcc_pcie_4_pipediv2_clk = {
.halt_reg = 0x6b054,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52010,
.enable_mask = BIT(27),
@@ -3373,7 +3373,7 @@ static struct clk_branch gcc_pcie_5_pipe_clk = {
static struct clk_branch gcc_pcie_5_pipediv2_clk = {
.halt_reg = 0x2f054,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52018,
.enable_mask = BIT(19),
@@ -3511,7 +3511,7 @@ static struct clk_branch gcc_pcie_6a_pipe_clk = {
static struct clk_branch gcc_pcie_6a_pipediv2_clk = {
.halt_reg = 0x31060,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52018,
.enable_mask = BIT(28),
@@ -3649,7 +3649,7 @@ static struct clk_branch gcc_pcie_6b_pipe_clk = {
static struct clk_branch gcc_pcie_6b_pipediv2_clk = {
.halt_reg = 0x8d060,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_SKIP,
.clkr = {
.enable_reg = 0x52010,
.enable_mask = BIT(28),
@@ -6155,7 +6155,7 @@ static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = {
.pd = {
.name = "gcc_usb3_mp_ss1_phy_gdsc",
},
- .pwrsts = PWRSTS_OFF_ON,
+ .pwrsts = PWRSTS_RET_ON,
.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
diff --git a/drivers/clk/qcom/videocc-sm8350.c b/drivers/clk/qcom/videocc-sm8350.c
index 5bd6fe3e1298..874d4da95ff8 100644
--- a/drivers/clk/qcom/videocc-sm8350.c
+++ b/drivers/clk/qcom/videocc-sm8350.c
@@ -452,7 +452,7 @@ static struct gdsc mvs0_gdsc = {
.pd = {
.name = "mvs0_gdsc",
},
- .flags = HW_CTRL | RETAIN_FF_ENABLE,
+ .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
.pwrsts = PWRSTS_OFF_ON,
};
@@ -461,7 +461,7 @@ static struct gdsc mvs1_gdsc = {
.pd = {
.name = "mvs1_gdsc",
},
- .flags = HW_CTRL | RETAIN_FF_ENABLE,
+ .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
.pwrsts = PWRSTS_OFF_ON,
};
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index b0018f371ea3..400337f3b572 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1028,26 +1028,29 @@ static void hybrid_update_cpu_capacity_scaling(void)
}
}
-static void __hybrid_init_cpu_capacity_scaling(void)
+static void __hybrid_refresh_cpu_capacity_scaling(void)
{
hybrid_max_perf_cpu = NULL;
hybrid_update_cpu_capacity_scaling();
}
-static void hybrid_init_cpu_capacity_scaling(void)
+static void hybrid_refresh_cpu_capacity_scaling(void)
{
- bool disable_itmt = false;
+ guard(mutex)(&hybrid_capacity_lock);
- mutex_lock(&hybrid_capacity_lock);
+ __hybrid_refresh_cpu_capacity_scaling();
+}
+static void hybrid_init_cpu_capacity_scaling(bool refresh)
+{
/*
* If hybrid_max_perf_cpu is set at this point, the hybrid CPU capacity
* scaling has been enabled already and the driver is just changing the
* operation mode.
*/
- if (hybrid_max_perf_cpu) {
- __hybrid_init_cpu_capacity_scaling();
- goto unlock;
+ if (refresh) {
+ hybrid_refresh_cpu_capacity_scaling();
+ return;
}
/*
@@ -1056,19 +1059,25 @@ static void hybrid_init_cpu_capacity_scaling(void)
* do not do that when SMT is in use.
*/
if (hwp_is_hybrid && !sched_smt_active() && arch_enable_hybrid_capacity_scale()) {
- __hybrid_init_cpu_capacity_scaling();
- disable_itmt = true;
+ hybrid_refresh_cpu_capacity_scaling();
+ /*
+ * Disabling ITMT causes sched domains to be rebuilt to disable asym
+ * packing and enable asym capacity.
+ */
+ sched_clear_itmt_support();
}
+}
-unlock:
- mutex_unlock(&hybrid_capacity_lock);
+static bool hybrid_clear_max_perf_cpu(void)
+{
+ bool ret;
- /*
- * Disabling ITMT causes sched domains to be rebuilt to disable asym
- * packing and enable asym capacity.
- */
- if (disable_itmt)
- sched_clear_itmt_support();
+ guard(mutex)(&hybrid_capacity_lock);
+
+ ret = !!hybrid_max_perf_cpu;
+ hybrid_max_perf_cpu = NULL;
+
+ return ret;
}
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
@@ -1392,7 +1401,7 @@ static void intel_pstate_update_limits_for_all(void)
mutex_lock(&hybrid_capacity_lock);
if (hybrid_max_perf_cpu)
- __hybrid_init_cpu_capacity_scaling();
+ __hybrid_refresh_cpu_capacity_scaling();
mutex_unlock(&hybrid_capacity_lock);
}
@@ -2263,6 +2272,11 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
} else {
cpu->pstate.scaling = perf_ctl_scaling;
}
+ /*
+ * If the CPU is going online for the first time and it was
+ * offline initially, asym capacity scaling needs to be updated.
+ */
+ hybrid_update_capacity(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
cpu->pstate.max_pstate = pstate_funcs.get_max(cpu->cpu);
@@ -3352,6 +3366,7 @@ static void intel_pstate_driver_cleanup(void)
static int intel_pstate_register_driver(struct cpufreq_driver *driver)
{
+ bool refresh_cpu_cap_scaling;
int ret;
if (driver == &intel_pstate)
@@ -3364,6 +3379,8 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
arch_set_max_freq_ratio(global.turbo_disabled);
+ refresh_cpu_cap_scaling = hybrid_clear_max_perf_cpu();
+
intel_pstate_driver = driver;
ret = cpufreq_register_driver(intel_pstate_driver);
if (ret) {
@@ -3373,7 +3390,7 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
global.min_perf_pct = min_perf_pct_min();
- hybrid_init_cpu_capacity_scaling();
+ hybrid_init_cpu_capacity_scaling(refresh_cpu_cap_scaling);
return 0;
}
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 29c192f20082..876469e23f7a 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -60,6 +60,7 @@ config CXL_ACPI
default CXL_BUS
select ACPI_TABLE_LIB
select ACPI_HMAT
+ select CXL_PORT
help
Enable support for host managed device memory (HDM) resources
published by a platform's ACPI CXL memory layout description. See
diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
index db321f48ba52..2caa90fa4bf2 100644
--- a/drivers/cxl/Makefile
+++ b/drivers/cxl/Makefile
@@ -1,13 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
+
+# Order is important here for the built-in case:
+# - 'core' first for fundamental init
+# - 'port' before platform root drivers like 'acpi' so that CXL-root ports
+# are immediately enabled
+# - 'mem' and 'pmem' before endpoint drivers so that memdevs are
+# immediately enabled
+# - 'pci' last, also mirrors the hardware enumeration hierarchy
obj-y += core/
-obj-$(CONFIG_CXL_PCI) += cxl_pci.o
-obj-$(CONFIG_CXL_MEM) += cxl_mem.o
+obj-$(CONFIG_CXL_PORT) += cxl_port.o
obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o
obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o
-obj-$(CONFIG_CXL_PORT) += cxl_port.o
+obj-$(CONFIG_CXL_MEM) += cxl_mem.o
+obj-$(CONFIG_CXL_PCI) += cxl_pci.o
-cxl_mem-y := mem.o
-cxl_pci-y := pci.o
+cxl_port-y := port.o
cxl_acpi-y := acpi.o
cxl_pmem-y := pmem.o security.o
-cxl_port-y := port.o
+cxl_mem-y := mem.o
+cxl_pci-y := pci.o
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 82b78e331d8e..432b7cfd12a8 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -924,6 +924,13 @@ static void __exit cxl_acpi_exit(void)
/* load before dax_hmem sees 'Soft Reserved' CXL ranges */
subsys_initcall(cxl_acpi_init);
+
+/*
+ * Arrange for host-bridge ports to be active synchronous with
+ * cxl_acpi_probe() exit.
+ */
+MODULE_SOFTDEP("pre: cxl_port");
+
module_exit(cxl_acpi_exit);
MODULE_DESCRIPTION("CXL ACPI: Platform Support");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
index ef1621d40f05..e9cd7939c407 100644
--- a/drivers/cxl/core/cdat.c
+++ b/drivers/cxl/core/cdat.c
@@ -641,6 +641,9 @@ static int cxl_endpoint_gather_bandwidth(struct cxl_region *cxlr,
void *ptr;
int rc;
+ if (!dev_is_pci(cxlds->dev))
+ return -ENODEV;
+
if (cxlds->rcd)
return -ENODEV;
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 3df10517a327..223c273c0cd1 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -712,7 +712,44 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld)
return 0;
}
-static int cxl_decoder_reset(struct cxl_decoder *cxld)
+static int commit_reap(struct device *dev, const void *data)
+{
+ struct cxl_port *port = to_cxl_port(dev->parent);
+ struct cxl_decoder *cxld;
+
+ if (!is_switch_decoder(dev) && !is_endpoint_decoder(dev))
+ return 0;
+
+ cxld = to_cxl_decoder(dev);
+ if (port->commit_end == cxld->id &&
+ ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)) {
+ port->commit_end--;
+ dev_dbg(&port->dev, "reap: %s commit_end: %d\n",
+ dev_name(&cxld->dev), port->commit_end);
+ }
+
+ return 0;
+}
+
+void cxl_port_commit_reap(struct cxl_decoder *cxld)
+{
+ struct cxl_port *port = to_cxl_port(cxld->dev.parent);
+
+ lockdep_assert_held_write(&cxl_region_rwsem);
+
+ /*
+ * Once the highest committed decoder is disabled, free any other
+ * decoders that were pinned allocated by out-of-order release.
+ */
+ port->commit_end--;
+ dev_dbg(&port->dev, "reap: %s commit_end: %d\n", dev_name(&cxld->dev),
+ port->commit_end);
+ device_for_each_child_reverse_from(&port->dev, &cxld->dev, NULL,
+ commit_reap);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_commit_reap, CXL);
+
+static void cxl_decoder_reset(struct cxl_decoder *cxld)
{
struct cxl_port *port = to_cxl_port(cxld->dev.parent);
struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
@@ -721,14 +758,14 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
u32 ctrl;
if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
- return 0;
+ return;
- if (port->commit_end != id) {
+ if (port->commit_end == id)
+ cxl_port_commit_reap(cxld);
+ else
dev_dbg(&port->dev,
"%s: out of order reset, expected decoder%d.%d\n",
dev_name(&cxld->dev), port->id, port->commit_end);
- return -EBUSY;
- }
down_read(&cxl_dpa_rwsem);
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
@@ -741,7 +778,6 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
up_read(&cxl_dpa_rwsem);
- port->commit_end--;
cxld->flags &= ~CXL_DECODER_F_ENABLE;
/* Userspace is now responsible for reconfiguring this decoder */
@@ -751,8 +787,6 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
cxled = to_cxl_endpoint_decoder(&cxld->dev);
cxled->state = CXL_DECODER_STATE_MANUAL;
}
-
- return 0;
}
static int cxl_setup_hdm_decoder_from_dvsec(
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index e666ec6a9085..af92c67bc954 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -2084,11 +2084,18 @@ static void cxl_bus_remove(struct device *dev)
static struct workqueue_struct *cxl_bus_wq;
-static void cxl_bus_rescan_queue(struct work_struct *w)
+static int cxl_rescan_attach(struct device *dev, void *data)
{
- int rc = bus_rescan_devices(&cxl_bus_type);
+ int rc = device_attach(dev);
+
+ dev_vdbg(dev, "rescan: %s\n", rc ? "attach" : "detached");
- pr_debug("CXL bus rescan result: %d\n", rc);
+ return 0;
+}
+
+static void cxl_bus_rescan_queue(struct work_struct *w)
+{
+ bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_rescan_attach);
}
void cxl_bus_rescan(void)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index e701e4b04032..dff618c708dc 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -232,8 +232,8 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
"Bypassing cpu_cache_invalidate_memregion() for testing!\n");
return 0;
} else {
- dev_err(&cxlr->dev,
- "Failed to synchronize CPU cache state\n");
+ dev_WARN(&cxlr->dev,
+ "Failed to synchronize CPU cache state\n");
return -ENXIO;
}
}
@@ -242,19 +242,17 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
return 0;
}
-static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
+static void cxl_region_decode_reset(struct cxl_region *cxlr, int count)
{
struct cxl_region_params *p = &cxlr->params;
- int i, rc = 0;
+ int i;
/*
- * Before region teardown attempt to flush, and if the flush
- * fails cancel the region teardown for data consistency
- * concerns
+ * Before region teardown attempt to flush, evict any data cached for
+ * this region, or scream loudly about missing arch / platform support
+ * for CXL teardown.
*/
- rc = cxl_region_invalidate_memregion(cxlr);
- if (rc)
- return rc;
+ cxl_region_invalidate_memregion(cxlr);
for (i = count - 1; i >= 0; i--) {
struct cxl_endpoint_decoder *cxled = p->targets[i];
@@ -277,23 +275,17 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
cxl_rr = cxl_rr_load(iter, cxlr);
cxld = cxl_rr->decoder;
if (cxld->reset)
- rc = cxld->reset(cxld);
- if (rc)
- return rc;
+ cxld->reset(cxld);
set_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags);
}
endpoint_reset:
- rc = cxled->cxld.reset(&cxled->cxld);
- if (rc)
- return rc;
+ cxled->cxld.reset(&cxled->cxld);
set_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags);
}
/* all decoders associated with this region have been torn down */
clear_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags);
-
- return 0;
}
static int commit_decoder(struct cxl_decoder *cxld)
@@ -409,16 +401,8 @@ static ssize_t commit_store(struct device *dev, struct device_attribute *attr,
* still pending.
*/
if (p->state == CXL_CONFIG_RESET_PENDING) {
- rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
- /*
- * Revert to committed since there may still be active
- * decoders associated with this region, or move forward
- * to active to mark the reset successful
- */
- if (rc)
- p->state = CXL_CONFIG_COMMIT;
- else
- p->state = CXL_CONFIG_ACTIVE;
+ cxl_region_decode_reset(cxlr, p->interleave_ways);
+ p->state = CXL_CONFIG_ACTIVE;
}
}
@@ -794,26 +778,50 @@ out:
return rc;
}
+static int check_commit_order(struct device *dev, const void *data)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ /*
+ * if port->commit_end is not the only free decoder, then out of
+ * order shutdown has occurred, block further allocations until
+ * that is resolved
+ */
+ if (((cxld->flags & CXL_DECODER_F_ENABLE) == 0))
+ return -EBUSY;
+ return 0;
+}
+
static int match_free_decoder(struct device *dev, void *data)
{
+ struct cxl_port *port = to_cxl_port(dev->parent);
struct cxl_decoder *cxld;
- int *id = data;
+ int rc;
if (!is_switch_decoder(dev))
return 0;
cxld = to_cxl_decoder(dev);
- /* enforce ordered allocation */
- if (cxld->id != *id)
+ if (cxld->id != port->commit_end + 1)
return 0;
- if (!cxld->region)
- return 1;
-
- (*id)++;
+ if (cxld->region) {
+ dev_dbg(dev->parent,
+ "next decoder to commit (%s) is already reserved (%s)\n",
+ dev_name(dev), dev_name(&cxld->region->dev));
+ return 0;
+ }
- return 0;
+ rc = device_for_each_child_reverse_from(dev->parent, dev, NULL,
+ check_commit_order);
+ if (rc) {
+ dev_dbg(dev->parent,
+ "unable to allocate %s due to out of order shutdown\n",
+ dev_name(dev));
+ return 0;
+ }
+ return 1;
}
static int match_auto_decoder(struct device *dev, void *data)
@@ -840,7 +848,6 @@ cxl_region_find_decoder(struct cxl_port *port,
struct cxl_region *cxlr)
{
struct device *dev;
- int id = 0;
if (port == cxled_to_port(cxled))
return &cxled->cxld;
@@ -849,7 +856,7 @@ cxl_region_find_decoder(struct cxl_port *port,
dev = device_find_child(&port->dev, &cxlr->params,
match_auto_decoder);
else
- dev = device_find_child(&port->dev, &id, match_free_decoder);
+ dev = device_find_child(&port->dev, NULL, match_free_decoder);
if (!dev)
return NULL;
/*
@@ -2054,13 +2061,7 @@ static int cxl_region_detach(struct cxl_endpoint_decoder *cxled)
get_device(&cxlr->dev);
if (p->state > CXL_CONFIG_ACTIVE) {
- /*
- * TODO: tear down all impacted regions if a device is
- * removed out of order
- */
- rc = cxl_region_decode_reset(cxlr, p->interleave_ways);
- if (rc)
- goto out;
+ cxl_region_decode_reset(cxlr, p->interleave_ways);
p->state = CXL_CONFIG_ACTIVE;
}
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index 8672b42ee4d1..8389a94adb1a 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -279,7 +279,7 @@ TRACE_EVENT(cxl_generic_event,
#define CXL_GMER_MEM_EVT_TYPE_ECC_ERROR 0x00
#define CXL_GMER_MEM_EVT_TYPE_INV_ADDR 0x01
#define CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR 0x02
-#define show_mem_event_type(type) __print_symbolic(type, \
+#define show_gmer_mem_event_type(type) __print_symbolic(type, \
{ CXL_GMER_MEM_EVT_TYPE_ECC_ERROR, "ECC Error" }, \
{ CXL_GMER_MEM_EVT_TYPE_INV_ADDR, "Invalid Address" }, \
{ CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, "Data Path Error" } \
@@ -373,7 +373,7 @@ TRACE_EVENT(cxl_general_media,
"hpa=%llx region=%s region_uuid=%pUb",
__entry->dpa, show_dpa_flags(__entry->dpa_flags),
show_event_desc_flags(__entry->descriptor),
- show_mem_event_type(__entry->type),
+ show_gmer_mem_event_type(__entry->type),
show_trans_type(__entry->transaction_type),
__entry->channel, __entry->rank, __entry->device,
__print_hex(__entry->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE),
@@ -391,6 +391,17 @@ TRACE_EVENT(cxl_general_media,
* DRAM Event Record defines many fields the same as the General Media Event
* Record. Reuse those definitions as appropriate.
*/
+#define CXL_DER_MEM_EVT_TYPE_ECC_ERROR 0x00
+#define CXL_DER_MEM_EVT_TYPE_SCRUB_MEDIA_ECC_ERROR 0x01
+#define CXL_DER_MEM_EVT_TYPE_INV_ADDR 0x02
+#define CXL_DER_MEM_EVT_TYPE_DATA_PATH_ERROR 0x03
+#define show_dram_mem_event_type(type) __print_symbolic(type, \
+ { CXL_DER_MEM_EVT_TYPE_ECC_ERROR, "ECC Error" }, \
+ { CXL_DER_MEM_EVT_TYPE_SCRUB_MEDIA_ECC_ERROR, "Scrub Media ECC Error" }, \
+ { CXL_DER_MEM_EVT_TYPE_INV_ADDR, "Invalid Address" }, \
+ { CXL_DER_MEM_EVT_TYPE_DATA_PATH_ERROR, "Data Path Error" } \
+)
+
#define CXL_DER_VALID_CHANNEL BIT(0)
#define CXL_DER_VALID_RANK BIT(1)
#define CXL_DER_VALID_NIBBLE BIT(2)
@@ -477,7 +488,7 @@ TRACE_EVENT(cxl_dram,
"hpa=%llx region=%s region_uuid=%pUb",
__entry->dpa, show_dpa_flags(__entry->dpa_flags),
show_event_desc_flags(__entry->descriptor),
- show_mem_event_type(__entry->type),
+ show_dram_mem_event_type(__entry->type),
show_trans_type(__entry->transaction_type),
__entry->channel, __entry->rank, __entry->nibble_mask,
__entry->bank_group, __entry->bank,
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 0d8b810a51f0..5406e3ab3d4a 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -359,7 +359,7 @@ struct cxl_decoder {
struct cxl_region *region;
unsigned long flags;
int (*commit)(struct cxl_decoder *cxld);
- int (*reset)(struct cxl_decoder *cxld);
+ void (*reset)(struct cxl_decoder *cxld);
};
/*
@@ -730,6 +730,7 @@ static inline bool is_cxl_root(struct cxl_port *port)
int cxl_num_decoders_committed(struct cxl_port *port);
bool is_cxl_port(const struct device *dev);
struct cxl_port *to_cxl_port(const struct device *dev);
+void cxl_port_commit_reap(struct cxl_decoder *cxld);
struct pci_bus;
int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev,
struct pci_bus *bus);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 861dde65768f..9dc394295e1f 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -208,7 +208,22 @@ static struct cxl_driver cxl_port_driver = {
},
};
-module_cxl_driver(cxl_port_driver);
+static int __init cxl_port_init(void)
+{
+ return cxl_driver_register(&cxl_port_driver);
+}
+/*
+ * Be ready to immediately enable ports emitted by the platform CXL root
+ * (e.g. cxl_acpi) when CONFIG_CXL_PORT=y.
+ */
+subsys_initcall(cxl_port_init);
+
+static void __exit cxl_port_exit(void)
+{
+ cxl_driver_unregister(&cxl_port_driver);
+}
+module_exit(cxl_port_exit);
+
MODULE_DESCRIPTION("CXL: Port enumeration and services");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(CXL);
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index 65a27c5a7bce..811389fc9cb8 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -601,22 +601,25 @@ static int rz_dmac_config(struct dma_chan *chan,
struct rz_dmac_chan *channel = to_rz_dmac_chan(chan);
u32 val;
- channel->src_per_address = config->src_addr;
channel->dst_per_address = config->dst_addr;
-
- val = rz_dmac_ds_to_val_mapping(config->dst_addr_width);
- if (val == CHCFG_DS_INVALID)
- return -EINVAL;
-
channel->chcfg &= ~CHCFG_FILL_DDS_MASK;
- channel->chcfg |= FIELD_PREP(CHCFG_FILL_DDS_MASK, val);
+ if (channel->dst_per_address) {
+ val = rz_dmac_ds_to_val_mapping(config->dst_addr_width);
+ if (val == CHCFG_DS_INVALID)
+ return -EINVAL;
- val = rz_dmac_ds_to_val_mapping(config->src_addr_width);
- if (val == CHCFG_DS_INVALID)
- return -EINVAL;
+ channel->chcfg |= FIELD_PREP(CHCFG_FILL_DDS_MASK, val);
+ }
+ channel->src_per_address = config->src_addr;
channel->chcfg &= ~CHCFG_FILL_SDS_MASK;
- channel->chcfg |= FIELD_PREP(CHCFG_FILL_SDS_MASK, val);
+ if (channel->src_per_address) {
+ val = rz_dmac_ds_to_val_mapping(config->src_addr_width);
+ if (val == CHCFG_DS_INVALID)
+ return -EINVAL;
+
+ channel->chcfg |= FIELD_PREP(CHCFG_FILL_SDS_MASK, val);
+ }
return 0;
}
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 406ee199c2ac..b3f27b3f9209 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -3185,27 +3185,40 @@ static int udma_configure_statictr(struct udma_chan *uc, struct udma_desc *d,
d->static_tr.elcnt = elcnt;
- /*
- * PDMA must to close the packet when the channel is in packet mode.
- * For TR mode when the channel is not cyclic we also need PDMA to close
- * the packet otherwise the transfer will stall because PDMA holds on
- * the data it has received from the peripheral.
- */
if (uc->config.pkt_mode || !uc->cyclic) {
+ /*
+ * PDMA must close the packet when the channel is in packet mode.
+ * For TR mode when the channel is not cyclic we also need PDMA
+ * to close the packet otherwise the transfer will stall because
+ * PDMA holds on the data it has received from the peripheral.
+ */
unsigned int div = dev_width * elcnt;
if (uc->cyclic)
d->static_tr.bstcnt = d->residue / d->sglen / div;
else
d->static_tr.bstcnt = d->residue / div;
+ } else if (uc->ud->match_data->type == DMA_TYPE_BCDMA &&
+ uc->config.dir == DMA_DEV_TO_MEM &&
+ uc->cyclic) {
+ /*
+ * For cyclic mode with BCDMA we have to set EOP in each TR to
+ * prevent short packet errors seen on channel teardown. So the
+ * PDMA must close the packet after every TR transfer by setting
+ * burst count equal to the number of bytes transferred.
+ */
+ struct cppi5_tr_type1_t *tr_req = d->hwdesc[0].tr_req_base;
- if (uc->config.dir == DMA_DEV_TO_MEM &&
- d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask)
- return -EINVAL;
+ d->static_tr.bstcnt =
+ (tr_req->icnt0 * tr_req->icnt1) / dev_width;
} else {
d->static_tr.bstcnt = 0;
}
+ if (uc->config.dir == DMA_DEV_TO_MEM &&
+ d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask)
+ return -EINVAL;
+
return 0;
}
@@ -3450,8 +3463,9 @@ udma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* static TR for remote PDMA */
if (udma_configure_statictr(uc, d, dev_width, burst)) {
dev_err(uc->ud->dev,
- "%s: StaticTR Z is limited to maximum 4095 (%u)\n",
- __func__, d->static_tr.bstcnt);
+ "%s: StaticTR Z is limited to maximum %u (%u)\n",
+ __func__, uc->ud->match_data->statictr_z_mask,
+ d->static_tr.bstcnt);
udma_free_hwdesc(uc, d);
kfree(d);
@@ -3476,6 +3490,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
unsigned int i;
int num_tr;
+ u32 period_csf = 0;
num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0,
&tr0_cnt1, &tr1_cnt0);
@@ -3498,6 +3513,20 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
period_addr = buf_addr |
((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT);
+ /*
+ * For BCDMA <-> PDMA transfers, the EOP flag needs to be set on the
+ * last TR of a descriptor, to mark the packet as complete.
+ * This is required for getting the teardown completion message in case
+ * of TX, and to avoid short-packet error in case of RX.
+ *
+ * As we are in cyclic mode, we do not know which period might be the
+ * last one, so set the flag for each period.
+ */
+ if (uc->config.ep_type == PSIL_EP_PDMA_XY &&
+ uc->ud->match_data->type == DMA_TYPE_BCDMA) {
+ period_csf = CPPI5_TR_CSF_EOP;
+ }
+
for (i = 0; i < periods; i++) {
int tr_idx = i * num_tr;
@@ -3525,8 +3554,10 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
}
if (!(flags & DMA_PREP_INTERRUPT))
- cppi5_tr_csf_set(&tr_req[tr_idx].flags,
- CPPI5_TR_CSF_SUPR_EVT);
+ period_csf |= CPPI5_TR_CSF_SUPR_EVT;
+
+ if (period_csf)
+ cppi5_tr_csf_set(&tr_req[tr_idx].flags, period_csf);
period_addr += period_len;
}
@@ -3655,8 +3686,9 @@ udma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
/* static TR for remote PDMA */
if (udma_configure_statictr(uc, d, dev_width, burst)) {
dev_err(uc->ud->dev,
- "%s: StaticTR Z is limited to maximum 4095 (%u)\n",
- __func__, d->static_tr.bstcnt);
+ "%s: StaticTR Z is limited to maximum %u (%u)\n",
+ __func__, uc->ud->match_data->statictr_z_mask,
+ d->static_tr.bstcnt);
udma_free_hwdesc(uc, d);
kfree(d);
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index fc0280dcddd1..c130f87147fa 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -170,6 +170,27 @@ dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll,
}
static int
+dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll,
+ struct netlink_ext_ack *extack)
+{
+ const struct dpll_device_ops *ops = dpll_device_ops(dpll);
+ DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) = { 0 };
+ enum dpll_clock_quality_level ql;
+ int ret;
+
+ if (!ops->clock_quality_level_get)
+ return 0;
+ ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack);
+ if (ret)
+ return ret;
+ for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX)
+ if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int
dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
@@ -559,6 +580,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
ret = dpll_msg_add_lock_status(msg, dpll, extack);
if (ret)
return ret;
+ ret = dpll_msg_add_clock_quality_level(msg, dpll, extack);
+ if (ret)
+ return ret;
ret = dpll_msg_add_mode(msg, dpll, extack);
if (ret)
return ret;
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c
index d3cd4cc54ace..a9a8ba067007 100644
--- a/drivers/edac/qcom_edac.c
+++ b/drivers/edac/qcom_edac.c
@@ -342,9 +342,11 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
int ecc_irq;
int rc;
- rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap);
- if (rc)
- return rc;
+ if (!llcc_driv_data->ecc_irq_configured) {
+ rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap);
+ if (rc)
+ return rc;
+ }
/* Allocate edac control info */
edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank",
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index 6adadb11962e..892b94cfd626 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -204,7 +204,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
// the node->ports array where the parent node should be. Later,
// when we handle the parent node, we fix up the reference.
++parent_count;
- node->color = i;
+ node->color = port_index;
break;
case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD:
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 96b2e5f9a8ef..157172a5f2b5 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -325,7 +325,10 @@ EXPORT_SYMBOL_GPL(scmi_driver_unregister);
static void scmi_device_release(struct device *dev)
{
- kfree(to_scmi_dev(dev));
+ struct scmi_device *scmi_dev = to_scmi_dev(dev);
+
+ kfree_const(scmi_dev->name);
+ kfree(scmi_dev);
}
static void __scmi_device_destroy(struct scmi_device *scmi_dev)
@@ -338,7 +341,6 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev)
if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM)
atomic_set(&scmi_syspower_registered, 0);
- kfree_const(scmi_dev->name);
ida_free(&scmi_bus_id, scmi_dev->id);
device_unregister(&scmi_dev->dev);
}
@@ -410,7 +412,6 @@ __scmi_device_create(struct device_node *np, struct device *parent,
return scmi_dev;
put_dev:
- kfree_const(scmi_dev->name);
put_device(&scmi_dev->dev);
ida_free(&scmi_bus_id, id);
return NULL;
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index c4b8e7ff88aa..cdec50a698a1 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -163,6 +163,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
* used to initialize this channel
* @dev: Reference to device in the SCMI hierarchy corresponding to this
* channel
+ * @is_p2a: A flag to identify a channel as P2A (RX)
* @rx_timeout_ms: The configured RX timeout in milliseconds.
* @handle: Pointer to SCMI entity handle
* @no_completion_irq: Flag to indicate that this channel has no completion
@@ -174,6 +175,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
struct scmi_chan_info {
int id;
struct device *dev;
+ bool is_p2a;
unsigned int rx_timeout_ms;
struct scmi_handle *handle;
bool no_completion_irq;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index a477b5ade38d..f8934d049d68 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1048,6 +1048,11 @@ static inline void scmi_xfer_command_release(struct scmi_info *info,
static inline void scmi_clear_channel(struct scmi_info *info,
struct scmi_chan_info *cinfo)
{
+ if (!cinfo->is_p2a) {
+ dev_warn(cinfo->dev, "Invalid clear on A2P channel !\n");
+ return;
+ }
+
if (info->desc->ops->clear_channel)
info->desc->ops->clear_channel(cinfo);
}
@@ -2638,6 +2643,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
if (!cinfo)
return -ENOMEM;
+ cinfo->is_p2a = !tx;
cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
/* Create a unique name for this transport device */
@@ -3042,10 +3048,10 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier));
- ret = of_property_read_u32(dev->of_node, "max-rx-timeout-ms",
+ ret = of_property_read_u32(dev->of_node, "arm,max-rx-timeout-ms",
&trans->desc->max_rx_timeout_ms);
if (ret && ret != -EINVAL)
- dev_err(dev, "Malformed max-rx-timeout-ms DT property.\n");
+ dev_err(dev, "Malformed arm,max-rx-timeout-ms DT property.\n");
dev_info(dev, "SCMI max-rx-timeout: %dms\n",
trans->desc->max_rx_timeout_ms);
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index 285fe7ad490d..3e8051fe8296 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -763,7 +763,7 @@ static int sdei_device_freeze(struct device *dev)
int err;
/* unregister private events */
- cpuhp_remove_state(sdei_entry_point);
+ cpuhp_remove_state(sdei_hp_state);
err = sdei_unregister_shared();
if (err)
diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c
index 9ca5ee58edbd..0f7ec8848202 100644
--- a/drivers/firmware/microchip/mpfs-auto-update.c
+++ b/drivers/firmware/microchip/mpfs-auto-update.c
@@ -76,14 +76,11 @@
#define AUTO_UPDATE_INFO_SIZE SZ_1M
#define AUTO_UPDATE_BITSTREAM_BASE (AUTO_UPDATE_DIRECTORY_SIZE + AUTO_UPDATE_INFO_SIZE)
-#define AUTO_UPDATE_TIMEOUT_MS 60000
-
struct mpfs_auto_update_priv {
struct mpfs_sys_controller *sys_controller;
struct device *dev;
struct mtd_info *flash;
struct fw_upload *fw_uploader;
- struct completion programming_complete;
size_t size_per_bitstream;
bool cancel_request;
};
@@ -156,19 +153,6 @@ static void mpfs_auto_update_cancel(struct fw_upload *fw_uploader)
static enum fw_upload_err mpfs_auto_update_poll_complete(struct fw_upload *fw_uploader)
{
- struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
- int ret;
-
- /*
- * There is no meaningful way to get the status of the programming while
- * it is in progress, so attempting anything other than waiting for it
- * to complete would be misplaced.
- */
- ret = wait_for_completion_timeout(&priv->programming_complete,
- msecs_to_jiffies(AUTO_UPDATE_TIMEOUT_MS));
- if (!ret)
- return FW_UPLOAD_ERR_TIMEOUT;
-
return FW_UPLOAD_ERR_NONE;
}
@@ -349,33 +333,23 @@ static enum fw_upload_err mpfs_auto_update_write(struct fw_upload *fw_uploader,
u32 offset, u32 size, u32 *written)
{
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
- enum fw_upload_err err = FW_UPLOAD_ERR_NONE;
int ret;
- reinit_completion(&priv->programming_complete);
-
ret = mpfs_auto_update_write_bitstream(fw_uploader, data, offset, size, written);
- if (ret) {
- err = FW_UPLOAD_ERR_RW_ERROR;
- goto out;
- }
+ if (ret)
+ return FW_UPLOAD_ERR_RW_ERROR;
- if (priv->cancel_request) {
- err = FW_UPLOAD_ERR_CANCELED;
- goto out;
- }
+ if (priv->cancel_request)
+ return FW_UPLOAD_ERR_CANCELED;
if (mpfs_auto_update_is_bitstream_info(data, size))
- goto out;
+ return FW_UPLOAD_ERR_NONE;
ret = mpfs_auto_update_verify_image(fw_uploader);
if (ret)
- err = FW_UPLOAD_ERR_FW_INVALID;
+ return FW_UPLOAD_ERR_FW_INVALID;
-out:
- complete(&priv->programming_complete);
-
- return err;
+ return FW_UPLOAD_ERR_NONE;
}
static const struct fw_upload_ops mpfs_auto_update_ops = {
@@ -461,8 +435,6 @@ static int mpfs_auto_update_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret,
"The current bitstream does not support auto-update\n");
- init_completion(&priv->programming_complete);
-
fw_uploader = firmware_upload_register(THIS_MODULE, dev, "mpfs-auto-update",
&mpfs_auto_update_ops, priv);
if (IS_ERR(fw_uploader))
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 10986cb11ec0..2e4260ba5f79 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -112,6 +112,7 @@ enum qcom_scm_qseecom_tz_cmd_info {
};
#define QSEECOM_MAX_APP_NAME_SIZE 64
+#define SHMBRIDGE_RESULT_NOTSUPP 4
/* Each bit configures cold/warm boot address for one of the 4 CPUs */
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
@@ -216,7 +217,7 @@ static DEFINE_SPINLOCK(scm_query_lock);
struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void)
{
- return __scm->mempool;
+ return __scm ? __scm->mempool : NULL;
}
static enum qcom_scm_convention __get_convention(void)
@@ -545,7 +546,7 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
} else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_DLOAD_MODE)) {
ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode);
- } else {
+ } else if (dload_mode) {
dev_err(__scm->dev,
"No available mechanism for setting download mode\n");
}
@@ -1361,6 +1362,8 @@ EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available);
int qcom_scm_shm_bridge_enable(void)
{
+ int ret;
+
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_MP,
.cmd = QCOM_SCM_MP_SHM_BRIDGE_ENABLE,
@@ -1373,7 +1376,15 @@ int qcom_scm_shm_bridge_enable(void)
QCOM_SCM_MP_SHM_BRIDGE_ENABLE))
return -EOPNOTSUPP;
- return qcom_scm_call(__scm->dev, &desc, &res) ?: res.result[0];
+ ret = qcom_scm_call(__scm->dev, &desc, &res);
+
+ if (ret)
+ return ret;
+
+ if (res.result[0] == SHMBRIDGE_RESULT_NOTSUPP)
+ return -EOPNOTSUPP;
+
+ return res.result[0];
}
EXPORT_SYMBOL_GPL(qcom_scm_shm_bridge_enable);
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index d670635914ec..a74600d9f2d7 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -16,7 +16,6 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
bool __ro_after_init smccc_trng_available = false;
-u64 __ro_after_init smccc_has_sve_hint = false;
s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
@@ -28,9 +27,6 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
smccc_conduit = conduit;
smccc_trng_available = smccc_probe_trng();
- if (IS_ENABLED(CONFIG_ARM64_SVE) &&
- smccc_version >= ARM_SMCCC_VERSION_1_3)
- smccc_has_sve_hint = true;
if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
(smccc_conduit != SMCCC_CONDUIT_NONE)) {
diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c
index 07e0d7180579..59a8f3a5c4e4 100644
--- a/drivers/gpio/gpio-sloppy-logic-analyzer.c
+++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c
@@ -234,7 +234,9 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- devm_mutex_init(dev, &priv->blob_lock);
+ ret = devm_mutex_init(dev, &priv->blob_lock);
+ if (ret)
+ return ret;
fops_buf_size_set(priv, GPIO_LA_DEFAULT_BUF_SIZE);
diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c
index 2b2dd7e92211..51d2475c05c5 100644
--- a/drivers/gpio/gpiolib-swnode.c
+++ b/drivers/gpio/gpiolib-swnode.c
@@ -64,7 +64,7 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
struct fwnode_reference_args args;
struct gpio_desc *desc;
char propname[32]; /* 32 is max size of property name */
- int ret;
+ int ret = 0;
swnode = to_software_node(fwnode);
if (!swnode)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d5952ab7752c..2b02655abb56 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -4926,6 +4926,8 @@ static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
return NULL;
s->private = priv;
+ if (*pos > 0)
+ priv->newline = true;
priv->idx = srcu_read_lock(&gpio_devices_srcu);
list_for_each_entry_srcu(gdev, &gpio_devices, list,
@@ -4969,7 +4971,7 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
gc = srcu_dereference(gdev->chip, &gdev->srcu);
if (!gc) {
- seq_printf(s, "%s%s: (dangling chip)",
+ seq_printf(s, "%s%s: (dangling chip)\n",
priv->newline ? "\n" : "",
dev_name(&gdev->dev));
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index f85ace0384d2..7dd55ed57c1d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -147,6 +147,7 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
struct acpi_buffer *params)
{
acpi_status status;
+ union acpi_object *obj;
union acpi_object atif_arg_elements[2];
struct acpi_object_list atif_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -169,16 +170,24 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
status = acpi_evaluate_object(atif->handle, NULL, &atif_arg,
&buffer);
+ obj = (union acpi_object *)buffer.pointer;
- /* Fail only if calling the method fails and ATIF is supported */
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ /* Fail if calling the method fails */
+ if (ACPI_FAILURE(status)) {
DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
acpi_format_exception(status));
- kfree(buffer.pointer);
+ kfree(obj);
return NULL;
}
- return buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ DRM_DEBUG_DRIVER("bad object returned from ATIF: %d\n",
+ obj->type);
+ kfree(obj);
+ return NULL;
+ }
+
+ return obj;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index cbef720de779..9da4414de617 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -402,7 +402,7 @@ static ssize_t amdgpu_debugfs_gprwave_read(struct file *f, char __user *buf, siz
int r;
uint32_t *data, x;
- if (size & 0x3 || *pos & 0x3)
+ if (size > 4096 || size & 0x3 || *pos & 0x3)
return -EINVAL;
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
@@ -1648,7 +1648,7 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) {
ent = debugfs_create_file(debugfs_regs_names[i],
- S_IFREG | 0444, root,
+ S_IFREG | 0400, root,
adev, debugfs_regs[i]);
if (!i && !IS_ERR_OR_NULL(ent))
i_size_write(ent->d_inode, adev->rmmio_size);
@@ -2100,11 +2100,11 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
amdgpu_securedisplay_debugfs_init(adev);
amdgpu_fw_attestation_debugfs_init(adev);
- debugfs_create_file("amdgpu_evict_vram", 0444, root, adev,
+ debugfs_create_file("amdgpu_evict_vram", 0400, root, adev,
&amdgpu_evict_vram_fops);
- debugfs_create_file("amdgpu_evict_gtt", 0444, root, adev,
+ debugfs_create_file("amdgpu_evict_gtt", 0400, root, adev,
&amdgpu_evict_gtt_fops);
- debugfs_create_file("amdgpu_test_ib", 0444, root, adev,
+ debugfs_create_file("amdgpu_test_ib", 0400, root, adev,
&amdgpu_debugfs_test_ib_fops);
debugfs_create_file("amdgpu_vm_info", 0444, root, adev,
&amdgpu_debugfs_vm_info_fops);
diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
index 5e8833e4fed2..ccfd2a4b4acc 100644
--- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
+++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c
@@ -482,7 +482,7 @@ static bool __aqua_vanjaram_is_valid_mode(struct amdgpu_xcp_mgr *xcp_mgr,
case AMDGPU_SPX_PARTITION_MODE:
return adev->gmc.num_mem_partitions == 1 && num_xcc > 0;
case AMDGPU_DPX_PARTITION_MODE:
- return adev->gmc.num_mem_partitions != 8 && (num_xcc % 4) == 0;
+ return adev->gmc.num_mem_partitions <= 2 && (num_xcc % 4) == 0;
case AMDGPU_TPX_PARTITION_MODE:
return (adev->gmc.num_mem_partitions == 1 ||
adev->gmc.num_mem_partitions == 3) &&
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index a8763496aed3..9288f37a3cc5 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -51,6 +51,12 @@ MODULE_FIRMWARE("amdgpu/sdma_7_0_1.bin");
#define SDMA0_HYP_DEC_REG_END 0x589a
#define SDMA1_HYP_DEC_REG_OFFSET 0x20
+/*define for compression field for sdma7*/
+#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_offset 0
+#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_mask 0x00000001
+#define SDMA_PKT_CONSTANT_FILL_HEADER_compress_shift 16
+#define SDMA_PKT_CONSTANT_FILL_HEADER_COMPRESS(x) (((x) & SDMA_PKT_CONSTANT_FILL_HEADER_compress_mask) << SDMA_PKT_CONSTANT_FILL_HEADER_compress_shift)
+
static const struct amdgpu_hwip_reg_entry sdma_reg_list_7_0[] = {
SOC15_REG_ENTRY_STR(GC, 0, regSDMA0_STATUS_REG),
SOC15_REG_ENTRY_STR(GC, 0, regSDMA0_STATUS1_REG),
@@ -1724,7 +1730,8 @@ static void sdma_v7_0_emit_fill_buffer(struct amdgpu_ib *ib,
uint64_t dst_offset,
uint32_t byte_count)
{
- ib->ptr[ib->length_dw++] = SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_CONST_FILL);
+ ib->ptr[ib->length_dw++] = SDMA_PKT_CONSTANT_FILL_HEADER_OP(SDMA_OP_CONST_FILL) |
+ SDMA_PKT_CONSTANT_FILL_HEADER_COMPRESS(1);
ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset);
ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset);
ib->ptr[ib->length_dw++] = src_data;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 6b5e2206e687..07e9ce99694f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8374,7 +8374,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
IP_VERSION(3, 5, 0) ||
acrtc_state->stream->link->psr_settings.psr_version <
- DC_PSR_VERSION_UNSUPPORTED) {
+ DC_PSR_VERSION_UNSUPPORTED ||
+ !(adev->flags & AMD_IS_APU)) {
timing = &acrtc_state->stream->timing;
/* at least 2 frames */
@@ -9428,6 +9429,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
bool mode_set_reset_required = false;
u32 i;
struct dc_commit_streams_params params = {dc_state->streams, dc_state->stream_count};
+ bool set_backlight_level = false;
/* Disable writeback */
for_each_old_connector_in_state(state, connector, old_con_state, i) {
@@ -9547,6 +9549,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
acrtc->hw_mode = new_crtc_state->mode;
crtc->hwmode = new_crtc_state->mode;
mode_set_reset_required = true;
+ set_backlight_level = true;
} else if (modereset_required(new_crtc_state)) {
drm_dbg_atomic(dev,
"Atomic commit: RESET. crtc id %d:[%p]\n",
@@ -9598,6 +9601,19 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
acrtc->otg_inst = status->primary_otg_inst;
}
}
+
+ /* During boot up and resume the DC layer will reset the panel brightness
+ * to fix a flicker issue.
+ * It will cause the dm->actual_brightness is not the current panel brightness
+ * level. (the dm->brightness is the correct panel level)
+ * So we set the backlight level with dm->brightness value after set mode
+ */
+ if (set_backlight_level) {
+ for (i = 0; i < dm->num_of_edps; i++) {
+ if (dm->backlight_dev[i])
+ amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
+ }
+ }
}
static void dm_set_writeback(struct amdgpu_display_manager *dm,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 069e0195e50a..eea317dcbe8c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -44,6 +44,7 @@
#include "dm_helpers.h"
#include "ddc_service_types.h"
+#include "clk_mgr.h"
static u32 edid_extract_panel_id(struct edid *edid)
{
@@ -1121,6 +1122,8 @@ bool dm_helpers_dp_handle_test_pattern_request(
struct pipe_ctx *pipe_ctx = NULL;
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_device *dev = aconnector->base.dev;
+ struct dc_state *dc_state = ctx->dc->current_state;
+ struct clk_mgr *clk_mgr = ctx->dc->clk_mgr;
int i;
for (i = 0; i < MAX_PIPES; i++) {
@@ -1221,6 +1224,16 @@ bool dm_helpers_dp_handle_test_pattern_request(
pipe_ctx->stream->test_pattern.type = test_pattern;
pipe_ctx->stream->test_pattern.color_space = test_pattern_color_space;
+ /* Temp W/A for compliance test failure */
+ dc_state->bw_ctx.bw.dcn.clk.p_state_change_support = false;
+ dc_state->bw_ctx.bw.dcn.clk.dramclk_khz = clk_mgr->dc_mode_softmax_enabled ?
+ clk_mgr->bw_params->dc_mode_softmax_memclk : clk_mgr->bw_params->max_memclk_mhz;
+ dc_state->bw_ctx.bw.dcn.clk.idle_dramclk_khz = dc_state->bw_ctx.bw.dcn.clk.dramclk_khz;
+ ctx->dc->clk_mgr->funcs->update_clocks(
+ ctx->dc->clk_mgr,
+ dc_state,
+ false);
+
dc_link_dp_set_test_pattern(
(struct dc_link *) link,
test_pattern,
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index 0d8498ab9b23..be8fbb04ad98 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -3127,7 +3127,9 @@ static enum bp_result bios_parser_get_vram_info(
struct atom_data_revision revision;
// vram info moved to umc_info for DCN4x
- if (info && DATA_TABLES(umc_info)) {
+ if (dcb->ctx->dce_version >= DCN_VERSION_4_01 &&
+ dcb->ctx->dce_version < DCN_VERSION_MAX &&
+ info && DATA_TABLES(umc_info)) {
header = GET_IMAGE(struct atom_common_table_header,
DATA_TABLES(umc_info));
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_policy.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_policy.c
index 11c904ae2958..c4c52173ef22 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_policy.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_policy.c
@@ -303,6 +303,7 @@ void build_unoptimized_policy_settings(enum dml_project_id project, struct dml_m
if (project == dml_project_dcn35 ||
project == dml_project_dcn351) {
policy->DCCProgrammingAssumesScanDirectionUnknownFinal = false;
+ policy->EnhancedPrefetchScheduleAccelerationFinal = 0;
policy->AllowForPStateChangeOrStutterInVBlankFinal = dml_prefetch_support_uclk_fclk_and_stutter_if_possible; /*new*/
policy->UseOnlyMaxPrefetchModes = 1;
}
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
index 3cd52e7a9c77..95838c7ab054 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -841,6 +841,8 @@ bool is_psr_su_specific_panel(struct dc_link *link)
isPSRSUSupported = false;
else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03)
isPSRSUSupported = false;
+ else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x01)
+ isPSRSUSupported = false;
else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1)
isPSRSUSupported = true;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 9ad9cf7a9c98..ee1bcfaae3e3 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -1234,6 +1234,14 @@ static void smu_init_xgmi_plpd_mode(struct smu_context *smu)
}
}
+static bool smu_is_workload_profile_available(struct smu_context *smu,
+ u32 profile)
+{
+ if (profile >= PP_SMC_POWER_PROFILE_COUNT)
+ return false;
+ return smu->workload_map && smu->workload_map[profile].valid_mapping;
+}
+
static int smu_sw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1251,25 +1259,33 @@ static int smu_sw_init(void *handle)
smu->watermarks_bitmap = 0;
smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ smu->user_dpm_profile.user_workload_mask = 0;
atomic_set(&smu->smu_power.power_gate.vcn_gated, 1);
atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1);
atomic_set(&smu->smu_power.power_gate.vpe_gated, 1);
atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1);
- smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
- smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
- smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
- smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4;
- smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
- smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
-
- if (smu->is_apu)
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
- else
- smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
+ smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_VIDEO] = 3;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_VR] = 4;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_COMPUTE] = 5;
+ smu->workload_priority[PP_SMC_POWER_PROFILE_CUSTOM] = 6;
+
+ if (smu->is_apu ||
+ !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) {
+ smu->driver_workload_mask =
+ 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT];
+ } else {
+ smu->driver_workload_mask =
+ 1 << smu->workload_priority[PP_SMC_POWER_PROFILE_FULLSCREEN3D];
+ smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
+ }
+ smu->workload_mask = smu->driver_workload_mask |
+ smu->user_dpm_profile.user_workload_mask;
smu->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
smu->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
smu->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING;
@@ -2339,17 +2355,20 @@ static int smu_switch_power_profile(void *handle,
return -EINVAL;
if (!en) {
- smu->workload_mask &= ~(1 << smu->workload_prority[type]);
+ smu->driver_workload_mask &= ~(1 << smu->workload_priority[type]);
index = fls(smu->workload_mask);
index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
workload[0] = smu->workload_setting[index];
} else {
- smu->workload_mask |= (1 << smu->workload_prority[type]);
+ smu->driver_workload_mask |= (1 << smu->workload_priority[type]);
index = fls(smu->workload_mask);
index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
workload[0] = smu->workload_setting[index];
}
+ smu->workload_mask = smu->driver_workload_mask |
+ smu->user_dpm_profile.user_workload_mask;
+
if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL &&
smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM)
smu_bump_power_profile_mode(smu, workload, 0);
@@ -3040,12 +3059,23 @@ static int smu_set_power_profile_mode(void *handle,
uint32_t param_size)
{
struct smu_context *smu = handle;
+ int ret;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled ||
!smu->ppt_funcs->set_power_profile_mode)
return -EOPNOTSUPP;
- return smu_bump_power_profile_mode(smu, param, param_size);
+ if (smu->user_dpm_profile.user_workload_mask &
+ (1 << smu->workload_priority[param[param_size]]))
+ return 0;
+
+ smu->user_dpm_profile.user_workload_mask =
+ (1 << smu->workload_priority[param[param_size]]);
+ smu->workload_mask = smu->user_dpm_profile.user_workload_mask |
+ smu->driver_workload_mask;
+ ret = smu_bump_power_profile_mode(smu, param, param_size);
+
+ return ret;
}
static int smu_get_fan_control_mode(void *handle, u32 *fan_mode)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index b44a185d07e8..d60d9a12a47e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -240,6 +240,7 @@ struct smu_user_dpm_profile {
/* user clock state information */
uint32_t clk_mask[SMU_CLK_COUNT];
uint32_t clk_dependency;
+ uint32_t user_workload_mask;
};
#define SMU_TABLE_INIT(tables, table_id, s, a, d) \
@@ -557,7 +558,8 @@ struct smu_context {
bool disable_uclk_switch;
uint32_t workload_mask;
- uint32_t workload_prority[WORKLOAD_POLICY_MAX];
+ uint32_t driver_workload_mask;
+ uint32_t workload_priority[WORKLOAD_POLICY_MAX];
uint32_t workload_setting[WORKLOAD_POLICY_MAX];
uint32_t power_profile_mode;
uint32_t default_power_profile_mode;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0.h
index ee457a6f0813..c2fd0a4a13e5 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0.h
@@ -25,7 +25,7 @@
#define SMU14_DRIVER_IF_V14_0_H
//Increment this version if SkuTable_t or BoardTable_t change
-#define PPTABLE_VERSION 0x18
+#define PPTABLE_VERSION 0x1B
#define NUM_GFXCLK_DPM_LEVELS 16
#define NUM_SOCCLK_DPM_LEVELS 8
@@ -145,7 +145,7 @@ typedef enum {
} FEATURE_BTC_e;
// Debug Overrides Bitmask
-#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_VCN_FCLK 0x00000001
+#define DEBUG_OVERRIDE_NOT_USE 0x00000001
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_DCN_FCLK 0x00000002
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_MP0_FCLK 0x00000004
#define DEBUG_OVERRIDE_DISABLE_VOLT_LINK_VCN_DCFCLK 0x00000008
@@ -161,6 +161,7 @@ typedef enum {
#define DEBUG_OVERRIDE_ENABLE_SOC_VF_BRINGUP_MODE 0x00002000
#define DEBUG_OVERRIDE_ENABLE_PER_WGP_RESIENCY 0x00004000
#define DEBUG_OVERRIDE_DISABLE_MEMORY_VOLTAGE_SCALING 0x00008000
+#define DEBUG_OVERRIDE_DFLL_BTC_FCW_LOG 0x00010000
// VR Mapping Bit Defines
#define VR_MAPPING_VR_SELECT_MASK 0x01
@@ -391,6 +392,21 @@ typedef struct {
EccInfo_t EccInfo[24];
} EccInfoTable_t;
+#define EPCS_HIGH_POWER 600
+#define EPCS_NORMAL_POWER 450
+#define EPCS_LOW_POWER 300
+#define EPCS_SHORTED_POWER 150
+#define EPCS_NO_BOOTUP 0
+
+typedef enum{
+ EPCS_SHORTED_LIMIT,
+ EPCS_LOW_POWER_LIMIT,
+ EPCS_NORMAL_POWER_LIMIT,
+ EPCS_HIGH_POWER_LIMIT,
+ EPCS_NOT_CONFIGURED,
+ EPCS_STATUS_COUNT,
+} EPCS_STATUS_e;
+
//D3HOT sequences
typedef enum {
BACO_SEQUENCE,
@@ -662,7 +678,7 @@ typedef enum {
} PP_GRTAVFS_FW_SEP_FUSE_e;
#define PP_NUM_RTAVFS_PWL_ZONES 5
-
+#define PP_NUM_PSM_DIDT_PWL_ZONES 3
// VBIOS or PPLIB configures telemetry slope and offset. Only slope expected to be set for SVI3
// Slope Q1.7, Offset Q1.2
@@ -746,10 +762,10 @@ typedef struct {
uint16_t Padding;
//Frequency changes
- int16_t GfxclkFmin; // MHz
- int16_t GfxclkFmax; // MHz
- uint16_t UclkFmin; // MHz
- uint16_t UclkFmax; // MHz
+ int16_t GfxclkFoffset;
+ uint16_t Padding1;
+ uint16_t UclkFmin;
+ uint16_t UclkFmax;
uint16_t FclkFmin;
uint16_t FclkFmax;
@@ -770,19 +786,23 @@ typedef struct {
uint8_t MaxOpTemp;
uint8_t AdvancedOdModeEnabled;
- uint8_t Padding1[3];
+ uint8_t Padding2[3];
uint16_t GfxVoltageFullCtrlMode;
uint16_t SocVoltageFullCtrlMode;
uint16_t GfxclkFullCtrlMode;
uint16_t UclkFullCtrlMode;
uint16_t FclkFullCtrlMode;
- uint16_t Padding2;
+ uint16_t Padding3;
int16_t GfxEdc;
int16_t GfxPccLimitControl;
- uint32_t Spare[10];
+ uint16_t GfxclkFmaxVmax;
+ uint8_t GfxclkFmaxVmaxTemperature;
+ uint8_t Padding4[1];
+
+ uint32_t Spare[9];
uint32_t MmHubPadding[8]; // SMU internal use. Adding here instead of external as a workaround
} OverDriveTable_t;
@@ -802,8 +822,8 @@ typedef struct {
uint16_t VddSocVmax;
//gfxclk
- int16_t GfxclkFmin; // MHz
- int16_t GfxclkFmax; // MHz
+ int16_t GfxclkFoffset;
+ uint16_t Padding;
//uclk
uint16_t UclkFmin; // MHz
uint16_t UclkFmax; // MHz
@@ -828,7 +848,7 @@ typedef struct {
uint8_t FanZeroRpmEnable;
//temperature
uint8_t MaxOpTemp;
- uint8_t Padding[2];
+ uint8_t Padding1[2];
//Full Ctrl
uint16_t GfxVoltageFullCtrlMode;
@@ -839,7 +859,7 @@ typedef struct {
//EDC
int16_t GfxEdc;
int16_t GfxPccLimitControl;
- int16_t Padding1;
+ int16_t Padding2;
uint32_t Spare[5];
} OverDriveLimits_t;
@@ -987,8 +1007,9 @@ typedef struct {
uint16_t BaseClockDc;
uint16_t GameClockDc;
uint16_t BoostClockDc;
-
- uint32_t Reserved[4];
+ uint16_t MaxReportedClock;
+ uint16_t Padding;
+ uint32_t Reserved[3];
} DriverReportedClocks_t;
typedef struct {
@@ -1132,7 +1153,7 @@ typedef struct {
uint32_t DcModeMaxFreq [PPCLK_COUNT ]; // In MHz
uint16_t GfxclkAibFmax;
- uint16_t GfxclkFreqCap;
+ uint16_t GfxDpmPadding;
//GFX Idle Power Settings
uint16_t GfxclkFgfxoffEntry; // Entry in RLC stage (PLL), in Mhz
@@ -1172,8 +1193,7 @@ typedef struct {
uint32_t DvoFmaxLowScaler; //Unitless float
// GFX DCS
- uint16_t DcsGfxOffVoltage; //Voltage in mV(Q2) applied to VDDGFX when entering DCS GFXOFF phase
- uint16_t PaddingDcs;
+ uint32_t PaddingDcs;
uint16_t DcsMinGfxOffTime; //Minimum amount of time PMFW shuts GFX OFF as part of GFX DCS phase
uint16_t DcsMaxGfxOffTime; //Maximum amount of time PMFW can shut GFX OFF as part of GFX DCS phase at a stretch.
@@ -1205,8 +1225,7 @@ typedef struct {
uint16_t DalDcModeMaxUclkFreq;
uint8_t PaddingsMem[2];
//FCLK Section
- uint16_t FclkDpmDisallowPstateFreq; //Frequency which FW will target when indicated that display config cannot support P-state. Set to 0 use FW calculated value
- uint16_t PaddingFclk;
+ uint32_t PaddingFclk;
// Link DPM Settings
uint8_t PcieGenSpeed[NUM_LINK_LEVELS]; ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 3:PciE-gen4 4:PciE-gen5
@@ -1215,12 +1234,19 @@ typedef struct {
// SECTION: VDD_GFX AVFS
uint8_t OverrideGfxAvfsFuses;
- uint8_t GfxAvfsPadding[3];
+ uint8_t GfxAvfsPadding[1];
+ uint16_t DroopGBStDev;
uint32_t SocHwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT]; //new added for Soc domain
uint32_t GfxL2HwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT]; //see fusedoc for encoding
//uint32_t GfxSeHwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT];
- uint32_t spare_HwRtAvfsFuses[PP_GRTAVFS_HW_FUSE_COUNT];
+
+ uint16_t PsmDidt_Vcross[PP_NUM_PSM_DIDT_PWL_ZONES-1];
+ uint32_t PsmDidt_StaticDroop_A[PP_NUM_PSM_DIDT_PWL_ZONES];
+ uint32_t PsmDidt_StaticDroop_B[PP_NUM_PSM_DIDT_PWL_ZONES];
+ uint32_t PsmDidt_DynDroop_A[PP_NUM_PSM_DIDT_PWL_ZONES];
+ uint32_t PsmDidt_DynDroop_B[PP_NUM_PSM_DIDT_PWL_ZONES];
+ uint32_t spare_HwRtAvfsFuses[19];
uint32_t SocCommonRtAvfs[PP_GRTAVFS_FW_COMMON_FUSE_COUNT];
uint32_t GfxCommonRtAvfs[PP_GRTAVFS_FW_COMMON_FUSE_COUNT];
@@ -1246,11 +1272,7 @@ typedef struct {
uint32_t dGbV_dT_vmin;
uint32_t dGbV_dT_vmax;
- //Unused: PMFW-9370
- uint32_t V2F_vmin_range_low;
- uint32_t V2F_vmin_range_high;
- uint32_t V2F_vmax_range_low;
- uint32_t V2F_vmax_range_high;
+ uint32_t PaddingV2F[4];
AvfsDcBtcParams_t DcBtcGfxParams;
QuadraticInt_t SSCurve_GFX;
@@ -1327,18 +1349,18 @@ typedef struct {
uint16_t PsmDidtReleaseTimer;
uint32_t PsmDidtStallPattern; //Will be written to both pattern 1 and didt_static_level_prog
// CAC EDC
- uint32_t Leakage_C0; // in IEEE float
- uint32_t Leakage_C1; // in IEEE float
- uint32_t Leakage_C2; // in IEEE float
- uint32_t Leakage_C3; // in IEEE float
- uint32_t Leakage_C4; // in IEEE float
- uint32_t Leakage_C5; // in IEEE float
- uint32_t GFX_CLK_SCALAR; // in IEEE float
- uint32_t GFX_CLK_INTERCEPT; // in IEEE float
- uint32_t GFX_CAC_M; // in IEEE float
- uint32_t GFX_CAC_B; // in IEEE float
- uint32_t VDD_GFX_CurrentLimitGuardband; // in IEEE float
- uint32_t DynToTotalCacScalar; // in IEEE
+ uint32_t CacEdcCacLeakageC0;
+ uint32_t CacEdcCacLeakageC1;
+ uint32_t CacEdcCacLeakageC2;
+ uint32_t CacEdcCacLeakageC3;
+ uint32_t CacEdcCacLeakageC4;
+ uint32_t CacEdcCacLeakageC5;
+ uint32_t CacEdcGfxClkScalar;
+ uint32_t CacEdcGfxClkIntercept;
+ uint32_t CacEdcCac_m;
+ uint32_t CacEdcCac_b;
+ uint32_t CacEdcCurrLimitGuardband;
+ uint32_t CacEdcDynToTotalCacRatio;
// GFX EDC XVMIN
uint32_t XVmin_Gfx_EdcThreshScalar;
uint32_t XVmin_Gfx_EdcEnableFreq;
@@ -1467,7 +1489,7 @@ typedef struct {
uint8_t VddqOffEnabled;
uint8_t PaddingUmcFlags[2];
- uint32_t PostVoltageSetBacoDelay; // in microseconds. Amount of time FW will wait after power good is established or PSI0 command is issued
+ uint32_t Paddign1;
uint32_t BacoEntryDelay; // in milliseconds. Amount of time FW will wait to trigger BACO entry after receiving entry notification from OS
uint8_t FuseWritePowerMuxPresent;
@@ -1530,7 +1552,7 @@ typedef struct {
int16_t FuzzyFan_ErrorSetDelta;
int16_t FuzzyFan_ErrorRateSetDelta;
int16_t FuzzyFan_PwmSetDelta;
- uint16_t FuzzyFan_Reserved;
+ uint16_t FanPadding2;
uint16_t FwCtfLimit[TEMP_COUNT];
@@ -1547,9 +1569,10 @@ typedef struct {
uint16_t FanSpare[1];
uint8_t FanIntakeSensorSupport;
uint8_t FanIntakePadding;
- uint32_t FanAmbientPerfBoostThreshold;
uint32_t FanSpare2[12];
+ uint32_t ODFeatureCtrlMask;
+
uint16_t TemperatureLimit_Hynix; // In degrees Celsius. Memory temperature limit associated with Hynix
uint16_t TemperatureLimit_Micron; // In degrees Celsius. Memory temperature limit associated with Micron
uint16_t TemperatureFwCtfLimit_Hynix;
@@ -1637,7 +1660,7 @@ typedef struct {
uint16_t AverageDclk0Frequency ;
uint16_t AverageVclk1Frequency ;
uint16_t AverageDclk1Frequency ;
- uint16_t PCIeBusy ;
+ uint16_t AveragePCIeBusy ;
uint16_t dGPU_W_MAX ;
uint16_t padding ;
@@ -1665,12 +1688,12 @@ typedef struct {
uint16_t AverageGfxActivity ;
uint16_t AverageUclkActivity ;
- uint16_t Vcn0ActivityPercentage ;
+ uint16_t AverageVcn0ActivityPercentage;
uint16_t Vcn1ActivityPercentage ;
uint32_t EnergyAccumulator;
uint16_t AverageSocketPower;
- uint16_t MovingAverageTotalBoardPower;
+ uint16_t AverageTotalBoardPower;
uint16_t AvgTemperature[TEMP_COUNT];
uint16_t AvgTemperatureFanIntake;
@@ -1684,7 +1707,8 @@ typedef struct {
uint8_t ThrottlingPercentage[THROTTLER_COUNT];
- uint8_t padding1[3];
+ uint8_t VmaxThrottlingPercentage;
+ uint8_t padding1[2];
//metrics for D3hot entry/exit and driver ARM msgs
uint32_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT];
@@ -1693,7 +1717,7 @@ typedef struct {
uint16_t ApuSTAPMSmartShiftLimit;
uint16_t ApuSTAPMLimit;
- uint16_t MovingAvgApuSocketPower;
+ uint16_t AvgApuSocketPower;
uint16_t AverageUclkActivity_MAX;
@@ -1823,6 +1847,17 @@ typedef struct {
#define TABLE_TRANSFER_FAILED 0xFF
#define TABLE_TRANSFER_PENDING 0xAB
+#define TABLE_PPT_FAILED 0x100
+#define TABLE_TDC_FAILED 0x200
+#define TABLE_TEMP_FAILED 0x400
+#define TABLE_FAN_TARGET_TEMP_FAILED 0x800
+#define TABLE_FAN_STOP_TEMP_FAILED 0x1000
+#define TABLE_FAN_START_TEMP_FAILED 0x2000
+#define TABLE_FAN_PWM_MIN_FAILED 0x4000
+#define TABLE_ACOUSTIC_TARGET_RPM_FAILED 0x8000
+#define TABLE_ACOUSTIC_LIMIT_RPM_FAILED 0x10000
+#define TABLE_MGPU_ACOUSTIC_TARGET_RPM_FAILED 0x20000
+
// Table types
#define TABLE_PPTABLE 0
#define TABLE_COMBO_PPTABLE 1
@@ -1849,5 +1884,6 @@ typedef struct {
#define IH_INTERRUPT_CONTEXT_ID_THERMAL_THROTTLING 0x7
#define IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8
#define IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9
+#define IH_INTERRUPT_CONTEXT_ID_DYNAMIC_TABLE 0xA
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
index 46b456590a08..727d5b405435 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
@@ -28,7 +28,7 @@
#define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7
#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_1 0x6
-#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x26
+#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x2E
#define FEATURE_MASK(feature) (1ULL << feature)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index c0f6b59369b7..31fe512028f4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -1455,7 +1455,6 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -EINVAL;
}
-
if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) &&
(smu->smc_fw_version >= 0x360d00)) {
if (size != 10)
@@ -1523,14 +1522,14 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
+ smu->workload_mask,
NULL);
if (ret) {
dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
return ret;
}
- smu->power_profile_mode = profile_mode;
+ smu_cmn_assign_power_profile(smu);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 16af1a329621..12223f507977 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -2081,10 +2081,13 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
smu->power_profile_mode);
if (workload_type < 0)
return -EINVAL;
+
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ else
+ smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index 9c3c48297cba..3b7b2ec8319a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -1786,10 +1786,13 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *
smu->power_profile_mode);
if (workload_type < 0)
return -EINVAL;
+
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
+ else
+ smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index 22737b11b1bf..952ee22cbc90 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -242,7 +242,9 @@ static int vangogh_tables_init(struct smu_context *smu)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->gpu_metrics_table_size = max(sizeof(struct gpu_metrics_v2_3), sizeof(struct gpu_metrics_v2_2));
+ smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v2_2);
+ smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_3));
+ smu_table->gpu_metrics_table_size = max(smu_table->gpu_metrics_table_size, sizeof(struct gpu_metrics_v2_4));
smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
if (!smu_table->gpu_metrics_table)
goto err1_out;
@@ -1077,7 +1079,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
}
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
+ smu->workload_mask,
NULL);
if (ret) {
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n",
@@ -1085,7 +1087,7 @@ static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input,
return ret;
}
- smu->power_profile_mode = profile_mode;
+ smu_cmn_assign_power_profile(smu);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index cc0504b063fa..62316a6707ef 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -890,14 +890,14 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u
}
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify,
- 1 << workload_type,
+ smu->workload_mask,
NULL);
if (ret) {
dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type);
return ret;
}
- smu->power_profile_mode = profile_mode;
+ smu_cmn_assign_power_profile(smu);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index cb923e33fd6f..5dd7ceca64fe 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2567,12 +2567,22 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
workload_mask |= 1 << workload_type;
}
+ smu->workload_mask |= workload_mask;
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetWorkloadMask,
- workload_mask,
+ smu->workload_mask,
NULL);
- if (!ret)
- smu->workload_mask = workload_mask;
+ if (!ret) {
+ smu_cmn_assign_power_profile(smu);
+ if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) {
+ workload_type = smu_cmn_to_asic_specific_index(smu,
+ CMN2ASIC_MAPPING_WORKLOAD,
+ PP_SMC_POWER_PROFILE_FULLSCREEN3D);
+ smu->power_profile_mode = smu->workload_mask & (1 << workload_type)
+ ? PP_SMC_POWER_PROFILE_FULLSCREEN3D
+ : PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT;
+ }
+ }
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index b891a5e0a396..9d0b19419de0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2499,13 +2499,14 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *inp
smu->power_profile_mode);
if (workload_type < 0)
return -EINVAL;
+
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
- 1 << workload_type, NULL);
+ smu->workload_mask, NULL);
if (ret)
dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__);
else
- smu->workload_mask = (1 << workload_type);
+ smu_cmn_assign_power_profile(smu);
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 5899d01fa73d..1aa13d32ceb2 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -367,54 +367,6 @@ static int smu_v14_0_2_store_powerplay_table(struct smu_context *smu)
return 0;
}
-#ifndef atom_smc_dpm_info_table_14_0_0
-struct atom_smc_dpm_info_table_14_0_0 {
- struct atom_common_table_header table_header;
- BoardTable_t BoardTable;
-};
-#endif
-
-static int smu_v14_0_2_append_powerplay_table(struct smu_context *smu)
-{
- struct smu_table_context *table_context = &smu->smu_table;
- PPTable_t *smc_pptable = table_context->driver_pptable;
- struct atom_smc_dpm_info_table_14_0_0 *smc_dpm_table;
- BoardTable_t *BoardTable = &smc_pptable->BoardTable;
- int index, ret;
-
- index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
- smc_dpm_info);
-
- ret = amdgpu_atombios_get_data_table(smu->adev, index, NULL, NULL, NULL,
- (uint8_t **)&smc_dpm_table);
- if (ret)
- return ret;
-
- memcpy(BoardTable, &smc_dpm_table->BoardTable, sizeof(BoardTable_t));
-
- return 0;
-}
-
-#if 0
-static int smu_v14_0_2_get_pptable_from_pmfw(struct smu_context *smu,
- void **table,
- uint32_t *size)
-{
- struct smu_table_context *smu_table = &smu->smu_table;
- void *combo_pptable = smu_table->combo_pptable;
- int ret = 0;
-
- ret = smu_cmn_get_combo_pptable(smu);
- if (ret)
- return ret;
-
- *table = combo_pptable;
- *size = sizeof(struct smu_14_0_powerplay_table);
-
- return 0;
-}
-#endif
-
static int smu_v14_0_2_get_pptable_from_pmfw(struct smu_context *smu,
void **table,
uint32_t *size)
@@ -436,16 +388,12 @@ static int smu_v14_0_2_get_pptable_from_pmfw(struct smu_context *smu,
static int smu_v14_0_2_setup_pptable(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
- struct amdgpu_device *adev = smu->adev;
int ret = 0;
if (amdgpu_sriov_vf(smu->adev))
return 0;
- if (!adev->scpm_enabled)
- ret = smu_v14_0_setup_pptable(smu);
- else
- ret = smu_v14_0_2_get_pptable_from_pmfw(smu,
+ ret = smu_v14_0_2_get_pptable_from_pmfw(smu,
&smu_table->power_play_table,
&smu_table->power_play_table_size);
if (ret)
@@ -455,16 +403,6 @@ static int smu_v14_0_2_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- /*
- * With SCPM enabled, the operation below will be handled
- * by PSP. Driver involvment is unnecessary and useless.
- */
- if (!adev->scpm_enabled) {
- ret = smu_v14_0_2_append_powerplay_table(smu);
- if (ret)
- return ret;
- }
-
ret = smu_v14_0_2_check_powerplay_table(smu);
if (ret)
return ret;
@@ -1077,12 +1015,9 @@ static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
switch (od_feature_bit) {
case PP_OD_FEATURE_GFXCLK_FMIN:
- od_min_setting = overdrive_lowerlimits->GfxclkFmin;
- od_max_setting = overdrive_upperlimits->GfxclkFmin;
- break;
case PP_OD_FEATURE_GFXCLK_FMAX:
- od_min_setting = overdrive_lowerlimits->GfxclkFmax;
- od_max_setting = overdrive_upperlimits->GfxclkFmax;
+ od_min_setting = overdrive_lowerlimits->GfxclkFoffset;
+ od_max_setting = overdrive_upperlimits->GfxclkFoffset;
break;
case PP_OD_FEATURE_UCLK_FMIN:
od_min_setting = overdrive_lowerlimits->UclkFmin;
@@ -1269,10 +1204,16 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
PP_OD_FEATURE_GFXCLK_BIT))
break;
- size += sysfs_emit_at(buf, size, "OD_SCLK:\n");
- size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
- od_table->OverDriveTable.GfxclkFmin,
- od_table->OverDriveTable.GfxclkFmax);
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ const OverDriveLimits_t * const overdrive_upperlimits =
+ &pptable->SkuTable.OverDriveLimitsBasicMax;
+ const OverDriveLimits_t * const overdrive_lowerlimits =
+ &pptable->SkuTable.OverDriveLimitsBasicMin;
+
+ size += sysfs_emit_at(buf, size, "OD_SCLK_OFFSET:\n");
+ size += sysfs_emit_at(buf, size, "0: %dMhz\n1: %uMhz\n",
+ overdrive_lowerlimits->GfxclkFoffset,
+ overdrive_upperlimits->GfxclkFoffset);
break;
case SMU_OD_MCLK:
@@ -1414,7 +1355,7 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
PP_OD_FEATURE_GFXCLK_FMAX,
NULL,
&max_value);
- size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
+ size += sysfs_emit_at(buf, size, "SCLK_OFFSET: %7dMhz %10uMhz\n",
min_value, max_value);
}
@@ -1796,7 +1737,7 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
DpmActivityMonitorCoeffInt_t *activity_monitor =
&(activity_monitor_external.DpmActivityMonitorCoeffInt);
int workload_type, ret = 0;
-
+ uint32_t current_profile_mode = smu->power_profile_mode;
smu->power_profile_mode = input[size];
if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
@@ -1854,6 +1795,11 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
}
}
+ if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ smu_v14_0_deep_sleep_control(smu, false);
+ else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE)
+ smu_v14_0_deep_sleep_control(smu, true);
+
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
@@ -1861,12 +1807,11 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
if (workload_type < 0)
return -EINVAL;
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetWorkloadMask,
- 1 << workload_type,
- NULL);
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
+ smu->workload_mask, NULL);
+
if (!ret)
- smu->workload_mask = 1 << workload_type;
+ smu_cmn_assign_power_profile(smu);
return ret;
}
@@ -2158,7 +2103,7 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
- gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
+ gpu_metrics->average_mm_activity = max(metrics->AverageVcn0ActivityPercentage,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
@@ -2217,8 +2162,7 @@ static void smu_v14_0_2_dump_od_table(struct smu_context *smu,
{
struct amdgpu_device *adev = smu->adev;
- dev_dbg(adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->OverDriveTable.GfxclkFmin,
- od_table->OverDriveTable.GfxclkFmax);
+ dev_dbg(adev->dev, "OD: Gfxclk offset: (%d)\n", od_table->OverDriveTable.GfxclkFoffset);
dev_dbg(adev->dev, "OD: Uclk: (%d, %d)\n", od_table->OverDriveTable.UclkFmin,
od_table->OverDriveTable.UclkFmax);
}
@@ -2309,10 +2253,8 @@ static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
memcpy(user_od_table,
boot_od_table,
sizeof(OverDriveTableExternal_t));
- user_od_table->OverDriveTable.GfxclkFmin =
- user_od_table_bak.OverDriveTable.GfxclkFmin;
- user_od_table->OverDriveTable.GfxclkFmax =
- user_od_table_bak.OverDriveTable.GfxclkFmax;
+ user_od_table->OverDriveTable.GfxclkFoffset =
+ user_od_table_bak.OverDriveTable.GfxclkFoffset;
user_od_table->OverDriveTable.UclkFmin =
user_od_table_bak.OverDriveTable.UclkFmin;
user_od_table->OverDriveTable.UclkFmax =
@@ -2441,22 +2383,6 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
}
switch (input[i]) {
- case 0:
- smu_v14_0_2_get_od_setting_limits(smu,
- PP_OD_FEATURE_GFXCLK_FMIN,
- &minimum,
- &maximum);
- if (input[i + 1] < minimum ||
- input[i + 1] > maximum) {
- dev_info(adev->dev, "GfxclkFmin (%ld) must be within [%u, %u]!\n",
- input[i + 1], minimum, maximum);
- return -EINVAL;
- }
-
- od_table->OverDriveTable.GfxclkFmin = input[i + 1];
- od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
- break;
-
case 1:
smu_v14_0_2_get_od_setting_limits(smu,
PP_OD_FEATURE_GFXCLK_FMAX,
@@ -2469,7 +2395,7 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
return -EINVAL;
}
- od_table->OverDriveTable.GfxclkFmax = input[i + 1];
+ od_table->OverDriveTable.GfxclkFoffset = input[i + 1];
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
break;
@@ -2480,13 +2406,6 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
}
}
- if (od_table->OverDriveTable.GfxclkFmin > od_table->OverDriveTable.GfxclkFmax) {
- dev_err(adev->dev,
- "Invalid setting: GfxclkFmin(%u) is bigger than GfxclkFmax(%u)\n",
- (uint32_t)od_table->OverDriveTable.GfxclkFmin,
- (uint32_t)od_table->OverDriveTable.GfxclkFmax);
- return -EINVAL;
- }
break;
case PP_OD_EDIT_MCLK_VDDC_TABLE:
@@ -2817,7 +2736,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.check_fw_status = smu_v14_0_check_fw_status,
.setup_pptable = smu_v14_0_2_setup_pptable,
.check_fw_version = smu_v14_0_check_fw_version,
- .write_pptable = smu_cmn_write_pptable,
.set_driver_table_location = smu_v14_0_set_driver_table_location,
.system_features_control = smu_v14_0_system_features_control,
.set_allowed_mask = smu_v14_0_set_allowed_mask,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 91ad434bcdae..bdfc5e617333 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1138,6 +1138,14 @@ int smu_cmn_set_mp1_state(struct smu_context *smu,
return ret;
}
+void smu_cmn_assign_power_profile(struct smu_context *smu)
+{
+ uint32_t index;
+ index = fls(smu->workload_mask);
+ index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0;
+ smu->power_profile_mode = smu->workload_setting[index];
+}
+
bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev)
{
struct pci_dev *p = NULL;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 1de685defe85..8a801e389659 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -130,6 +130,8 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
+void smu_cmn_assign_power_profile(struct smu_context *smu);
+
/*
* Helper function to make sysfs_emit_at() happy. Align buf to
* the current page boundary and record the offset.
diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index b29980f95379..295e9d031e2d 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -58,9 +58,10 @@ int drm_aux_bridge_register(struct device *parent)
adev->id = ret;
adev->name = "aux_bridge";
adev->dev.parent = parent;
- adev->dev.of_node = of_node_get(parent->of_node);
adev->dev.release = drm_aux_bridge_release;
+ device_set_of_node_from_dev(&adev->dev, parent);
+
ret = auxiliary_device_init(adev);
if (ret) {
ida_free(&drm_aux_bridge_ida, adev->id);
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 290e2532fab1..f3afdab55c11 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -2391,6 +2391,7 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc)
if (tc->pre_emphasis[0] < 0 || tc->pre_emphasis[0] > 2 ||
tc->pre_emphasis[1] < 0 || tc->pre_emphasis[1] > 2) {
dev_err(dev, "Incorrect Pre-Emphasis setting, use either 0=0dB 1=3.5dB 2=6dB\n");
+ of_node_put(node);
return -EINVAL;
}
}
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index 0830cae9a4d0..2d84d7ea1ab7 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -403,7 +403,6 @@ static const struct dmi_system_id orientation_data[] = {
}, { /* Lenovo Yoga Tab 3 X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
.driver_data = (void *)&lcd1600x2560_rightside_up,
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index faa253b27664..14ac351fd76d 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -123,9 +123,8 @@ config DRM_I915_USERPTR
config DRM_I915_GVT_KVMGT
tristate "Enable KVM host support Intel GVT-g graphics virtualization"
depends on DRM_I915
- depends on X86
+ depends on KVM_X86
depends on 64BIT
- depends on KVM
depends on VFIO
select DRM_I915_GVT
select KVM_EXTERNAL_WRITE_TRACKING
diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c
index eded5e955cc0..4cb3494c0bb2 100644
--- a/drivers/gpu/drm/imagination/pvr_context.c
+++ b/drivers/gpu/drm/imagination/pvr_context.c
@@ -17,10 +17,14 @@
#include <drm/drm_auth.h>
#include <drm/drm_managed.h>
+
+#include <linux/bug.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/xarray.h>
@@ -354,6 +358,10 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co
return err;
}
+ spin_lock(&pvr_dev->ctx_list_lock);
+ list_add_tail(&ctx->file_link, &pvr_file->contexts);
+ spin_unlock(&pvr_dev->ctx_list_lock);
+
return 0;
err_destroy_fw_obj:
@@ -380,6 +388,11 @@ pvr_context_release(struct kref *ref_count)
container_of(ref_count, struct pvr_context, ref_count);
struct pvr_device *pvr_dev = ctx->pvr_dev;
+ WARN_ON(in_interrupt());
+ spin_lock(&pvr_dev->ctx_list_lock);
+ list_del(&ctx->file_link);
+ spin_unlock(&pvr_dev->ctx_list_lock);
+
xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id);
pvr_context_destroy_queues(ctx);
pvr_fw_object_destroy(ctx->fw_obj);
@@ -437,11 +450,30 @@ pvr_context_destroy(struct pvr_file *pvr_file, u32 handle)
*/
void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file)
{
+ struct pvr_device *pvr_dev = pvr_file->pvr_dev;
struct pvr_context *ctx;
unsigned long handle;
xa_for_each(&pvr_file->ctx_handles, handle, ctx)
pvr_context_destroy(pvr_file, handle);
+
+ spin_lock(&pvr_dev->ctx_list_lock);
+ ctx = list_first_entry(&pvr_file->contexts, struct pvr_context, file_link);
+
+ while (!list_entry_is_head(ctx, &pvr_file->contexts, file_link)) {
+ list_del_init(&ctx->file_link);
+
+ if (pvr_context_get_if_referenced(ctx)) {
+ spin_unlock(&pvr_dev->ctx_list_lock);
+
+ pvr_vm_unmap_all(ctx->vm_ctx);
+
+ pvr_context_put(ctx);
+ spin_lock(&pvr_dev->ctx_list_lock);
+ }
+ ctx = list_first_entry(&pvr_file->contexts, struct pvr_context, file_link);
+ }
+ spin_unlock(&pvr_dev->ctx_list_lock);
}
/**
@@ -451,6 +483,7 @@ void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file)
void pvr_context_device_init(struct pvr_device *pvr_dev)
{
xa_init_flags(&pvr_dev->ctx_ids, XA_FLAGS_ALLOC1);
+ spin_lock_init(&pvr_dev->ctx_list_lock);
}
/**
diff --git a/drivers/gpu/drm/imagination/pvr_context.h b/drivers/gpu/drm/imagination/pvr_context.h
index 0c7b97dfa6ba..07afa179cdf4 100644
--- a/drivers/gpu/drm/imagination/pvr_context.h
+++ b/drivers/gpu/drm/imagination/pvr_context.h
@@ -85,6 +85,9 @@ struct pvr_context {
/** @compute: Transfer queue. */
struct pvr_queue *transfer;
} queues;
+
+ /** @file_link: pvr_file PVR context list link. */
+ struct list_head file_link;
};
static __always_inline struct pvr_queue *
@@ -124,6 +127,24 @@ pvr_context_get(struct pvr_context *ctx)
}
/**
+ * pvr_context_get_if_referenced() - Take an additional reference on a still
+ * referenced context.
+ * @ctx: Context pointer.
+ *
+ * Call pvr_context_put() to release.
+ *
+ * Returns:
+ * * True on success, or
+ * * false if no context pointer passed, or the context wasn't still
+ * * referenced.
+ */
+static __always_inline bool
+pvr_context_get_if_referenced(struct pvr_context *ctx)
+{
+ return ctx != NULL && kref_get_unless_zero(&ctx->ref_count) != 0;
+}
+
+/**
* pvr_context_lookup() - Lookup context pointer from handle and file.
* @pvr_file: Pointer to pvr_file structure.
* @handle: Context handle.
diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h
index b574e23d484b..6d0dfacb677b 100644
--- a/drivers/gpu/drm/imagination/pvr_device.h
+++ b/drivers/gpu/drm/imagination/pvr_device.h
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/wait.h>
@@ -293,6 +294,12 @@ struct pvr_device {
/** @sched_wq: Workqueue for schedulers. */
struct workqueue_struct *sched_wq;
+
+ /**
+ * @ctx_list_lock: Lock to be held when accessing the context list in
+ * struct pvr_file.
+ */
+ spinlock_t ctx_list_lock;
};
/**
@@ -344,6 +351,9 @@ struct pvr_file {
* This array is used to allocate handles returned to userspace.
*/
struct xarray vm_ctx_handles;
+
+ /** @contexts: PVR context list. */
+ struct list_head contexts;
};
/**
diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c
index 1a0cb7aa9cea..fb17196e05f4 100644
--- a/drivers/gpu/drm/imagination/pvr_drv.c
+++ b/drivers/gpu/drm/imagination/pvr_drv.c
@@ -28,6 +28,7 @@
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -1326,6 +1327,8 @@ pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file)
*/
pvr_file->pvr_dev = pvr_dev;
+ INIT_LIST_HEAD(&pvr_file->contexts);
+
xa_init_flags(&pvr_file->ctx_handles, XA_FLAGS_ALLOC1);
xa_init_flags(&pvr_file->free_list_handles, XA_FLAGS_ALLOC1);
xa_init_flags(&pvr_file->hwrt_handles, XA_FLAGS_ALLOC1);
diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c
index 97c0f772ed65..7bd6ba4c6e8a 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.c
+++ b/drivers/gpu/drm/imagination/pvr_vm.c
@@ -14,6 +14,7 @@
#include <drm/drm_gem.h>
#include <drm/drm_gpuvm.h>
+#include <linux/bug.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -597,12 +598,26 @@ err_free:
}
/**
- * pvr_vm_context_release() - Teardown a VM context.
- * @ref_count: Pointer to reference counter of the VM context.
+ * pvr_vm_unmap_all() - Unmap all mappings associated with a VM context.
+ * @vm_ctx: Target VM context.
*
* This function ensures that no mappings are left dangling by unmapping them
* all in order of ascending device-virtual address.
*/
+void
+pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx)
+{
+ WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start,
+ vm_ctx->gpuvm_mgr.mm_range));
+}
+
+/**
+ * pvr_vm_context_release() - Teardown a VM context.
+ * @ref_count: Pointer to reference counter of the VM context.
+ *
+ * This function also ensures that no mappings are left dangling by calling
+ * pvr_vm_unmap_all.
+ */
static void
pvr_vm_context_release(struct kref *ref_count)
{
@@ -612,8 +627,7 @@ pvr_vm_context_release(struct kref *ref_count)
if (vm_ctx->fw_mem_ctx_obj)
pvr_fw_object_destroy(vm_ctx->fw_mem_ctx_obj);
- WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start,
- vm_ctx->gpuvm_mgr.mm_range));
+ pvr_vm_unmap_all(vm_ctx);
pvr_mmu_context_destroy(vm_ctx->mmu_ctx);
drm_gem_private_object_fini(&vm_ctx->dummy_gem);
diff --git a/drivers/gpu/drm/imagination/pvr_vm.h b/drivers/gpu/drm/imagination/pvr_vm.h
index f2a6463f2b05..79406243617c 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.h
+++ b/drivers/gpu/drm/imagination/pvr_vm.h
@@ -39,6 +39,7 @@ int pvr_vm_map(struct pvr_vm_context *vm_ctx,
struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset,
u64 device_addr, u64 size);
int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size);
+void pvr_vm_unmap_all(struct pvr_vm_context *vm_ctx);
dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx);
struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx);
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 175b00e5a253..eb0e1233ad04 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -127,9 +127,8 @@ static void mtk_crtc_destroy(struct drm_crtc *crtc)
mtk_mutex_put(mtk_crtc->mutex);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
- cmdq_pkt_destroy(&mtk_crtc->cmdq_client, &mtk_crtc->cmdq_handle);
-
if (mtk_crtc->cmdq_client.chan) {
+ cmdq_pkt_destroy(&mtk_crtc->cmdq_client, &mtk_crtc->cmdq_handle);
mbox_free_channel(mtk_crtc->cmdq_client.chan);
mtk_crtc->cmdq_client.chan = NULL;
}
@@ -913,6 +912,7 @@ static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev,
BIT(pipe),
mtk_crtc_plane_type(mtk_crtc->layer_nr, num_planes),
mtk_ddp_comp_supported_rotations(comp),
+ mtk_ddp_comp_get_blend_modes(comp),
mtk_ddp_comp_get_formats(comp),
mtk_ddp_comp_get_num_formats(comp), i);
if (ret)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index be66d94be361..edc6417639e6 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -363,6 +363,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
.layer_config = mtk_ovl_layer_config,
.bgclr_in_on = mtk_ovl_bgclr_in_on,
.bgclr_in_off = mtk_ovl_bgclr_in_off,
+ .get_blend_modes = mtk_ovl_get_blend_modes,
.get_formats = mtk_ovl_get_formats,
.get_num_formats = mtk_ovl_get_num_formats,
};
@@ -416,6 +417,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
.disconnect = mtk_ovl_adaptor_disconnect,
.add = mtk_ovl_adaptor_add_comp,
.remove = mtk_ovl_adaptor_remove_comp,
+ .get_blend_modes = mtk_ovl_adaptor_get_blend_modes,
.get_formats = mtk_ovl_adaptor_get_formats,
.get_num_formats = mtk_ovl_adaptor_get_num_formats,
.mode_valid = mtk_ovl_adaptor_mode_valid,
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index ecf6dc283cd7..39720b27f4e9 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -80,6 +80,7 @@ struct mtk_ddp_comp_funcs {
void (*ctm_set)(struct device *dev,
struct drm_crtc_state *state);
struct device * (*dma_dev_get)(struct device *dev);
+ u32 (*get_blend_modes)(struct device *dev);
const u32 *(*get_formats)(struct device *dev);
size_t (*get_num_formats)(struct device *dev);
void (*connect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
@@ -267,6 +268,15 @@ static inline struct device *mtk_ddp_comp_dma_dev_get(struct mtk_ddp_comp *comp)
}
static inline
+u32 mtk_ddp_comp_get_blend_modes(struct mtk_ddp_comp *comp)
+{
+ if (comp->funcs && comp->funcs->get_blend_modes)
+ return comp->funcs->get_blend_modes(comp->dev);
+
+ return 0;
+}
+
+static inline
const u32 *mtk_ddp_comp_get_formats(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->get_formats)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 082ac18fe04a..04154db9085c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -103,6 +103,7 @@ void mtk_ovl_register_vblank_cb(struct device *dev,
void mtk_ovl_unregister_vblank_cb(struct device *dev);
void mtk_ovl_enable_vblank(struct device *dev);
void mtk_ovl_disable_vblank(struct device *dev);
+u32 mtk_ovl_get_blend_modes(struct device *dev);
const u32 *mtk_ovl_get_formats(struct device *dev);
size_t mtk_ovl_get_num_formats(struct device *dev);
@@ -131,6 +132,7 @@ void mtk_ovl_adaptor_start(struct device *dev);
void mtk_ovl_adaptor_stop(struct device *dev);
unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev);
struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev);
+u32 mtk_ovl_adaptor_get_blend_modes(struct device *dev);
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev);
size_t mtk_ovl_adaptor_get_num_formats(struct device *dev);
enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 89b439dcf3a6..e0c0bb01f65a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -65,8 +65,8 @@
#define OVL_CON_CLRFMT_RGB (1 << 12)
#define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
#define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
-#define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP)
-#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
+#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP)
#define OVL_CON_CLRFMT_UYVY (4 << 12)
#define OVL_CON_CLRFMT_YUYV (5 << 12)
#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
@@ -146,6 +146,7 @@ struct mtk_disp_ovl_data {
bool fmt_rgb565_is_0;
bool smi_id_en;
bool supports_afbc;
+ const u32 blend_modes;
const u32 *formats;
size_t num_formats;
bool supports_clrfmt_ext;
@@ -214,6 +215,13 @@ void mtk_ovl_disable_vblank(struct device *dev)
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
}
+u32 mtk_ovl_get_blend_modes(struct device *dev)
+{
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ return ovl->data->blend_modes;
+}
+
const u32 *mtk_ovl_get_formats(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
@@ -386,14 +394,27 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
DISP_REG_OVL_RDMA_CTRL(idx));
}
-static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt,
- unsigned int blend_mode)
+static unsigned int mtk_ovl_fmt_convert(struct mtk_disp_ovl *ovl,
+ struct mtk_plane_state *state)
{
- /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
- * is defined in mediatek HW data sheet.
- * The alphabet order in XXX is no relation to data
- * arrangement in memory.
+ unsigned int fmt = state->pending.format;
+ unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
+
+ /*
+ * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet
+ * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888.
+ *
+ * Check blend_modes in the driver data to see if premultiplied mode is supported.
+ * If not, use coverage mode instead to set it to the supported color formats.
+ *
+ * Current DRM assumption is that alpha is default premultiplied, so the bitmask of
+ * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init()
+ * will get an error return from drm_plane_create_blend_mode_property() and
+ * state->base.pixel_blend_mode should not be used.
*/
+ if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
+ blend_mode = state->base.pixel_blend_mode;
+
switch (fmt) {
default:
case DRM_FORMAT_RGB565:
@@ -471,20 +492,26 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
return;
}
- con = ovl_fmt_convert(ovl, fmt, blend_mode);
+ con = mtk_ovl_fmt_convert(ovl, state);
if (state->base.fb) {
- con |= OVL_CON_AEN;
con |= state->base.alpha & OVL_CON_ALPHA;
- }
- /* CONST_BLD must be enabled for XRGB formats although the alpha channel
- * can be ignored, or OVL will still read the value from memory.
- * For RGB888 related formats, whether CONST_BLD is enabled or not won't
- * affect the result. Therefore we use !has_alpha as the condition.
- */
- if ((state->base.fb && !state->base.fb->format->has_alpha) ||
- blend_mode == DRM_MODE_BLEND_PIXEL_NONE)
- ignore_pixel_alpha = OVL_CONST_BLEND;
+ /*
+ * For blend_modes supported SoCs, always enable alpha blending.
+ * For blend_modes unsupported SoCs, enable alpha blending when has_alpha is set.
+ */
+ if (blend_mode || state->base.fb->format->has_alpha)
+ con |= OVL_CON_AEN;
+
+ /*
+ * Although the alpha channel can be ignored, CONST_BLD must be enabled
+ * for XRGB format, otherwise OVL will still read the value from memory.
+ * For RGB888 related formats, whether CONST_BLD is enabled or not won't
+ * affect the result. Therefore we use !has_alpha as the condition.
+ */
+ if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state->base.fb->format->has_alpha)
+ ignore_pixel_alpha = OVL_CONST_BLEND;
+ }
if (pending->rotation & DRM_MODE_REFLECT_Y) {
con |= OVL_CON_VIRT_FLIP;
@@ -663,6 +690,9 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_formats,
.num_formats = ARRAY_SIZE(mt8173_formats),
};
@@ -673,6 +703,9 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_formats,
.num_formats = ARRAY_SIZE(mt8173_formats),
};
@@ -684,6 +717,9 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
.supports_afbc = true,
+ .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8195_formats,
.num_formats = ARRAY_SIZE(mt8195_formats),
.supports_clrfmt_ext = true,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index c6768210b08b..bf2546c4681a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -400,6 +400,13 @@ void mtk_ovl_adaptor_disable_vblank(struct device *dev)
mtk_ethdr_disable_vblank(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
}
+u32 mtk_ovl_adaptor_get_blend_modes(struct device *dev)
+{
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+
+ return mtk_ethdr_get_blend_modes(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
+}
+
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev)
{
struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index d8796a904eca..f2bee617f063 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -145,6 +145,89 @@ struct mtk_dp_data {
u16 audio_m_div2_bit;
};
+static const struct mtk_dp_efuse_fmt mt8188_dp_efuse_fmt[MTK_DP_CAL_MAX] = {
+ [MTK_DP_CAL_GLB_BIAS_TRIM] = {
+ .idx = 0,
+ .shift = 10,
+ .mask = 0x1f,
+ .min_val = 1,
+ .max_val = 0x1e,
+ .default_val = 0xf,
+ },
+ [MTK_DP_CAL_CLKTX_IMPSE] = {
+ .idx = 0,
+ .shift = 15,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] = {
+ .idx = 1,
+ .shift = 0,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] = {
+ .idx = 1,
+ .shift = 8,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] = {
+ .idx = 1,
+ .shift = 16,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] = {
+ .idx = 1,
+ .shift = 24,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] = {
+ .idx = 1,
+ .shift = 4,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] = {
+ .idx = 1,
+ .shift = 12,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] = {
+ .idx = 1,
+ .shift = 20,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+ [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] = {
+ .idx = 1,
+ .shift = 28,
+ .mask = 0xf,
+ .min_val = 1,
+ .max_val = 0xe,
+ .default_val = 0x8,
+ },
+};
+
static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = {
[MTK_DP_CAL_GLB_BIAS_TRIM] = {
.idx = 3,
@@ -2771,7 +2854,7 @@ static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend, mtk_dp_resume);
static const struct mtk_dp_data mt8188_dp_data = {
.bridge_type = DRM_MODE_CONNECTOR_DisplayPort,
.smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE,
- .efuse_fmt = mt8195_dp_efuse_fmt,
+ .efuse_fmt = mt8188_dp_efuse_fmt,
.audio_supported = true,
.audio_pkt_in_hblank_area = true,
.audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c
index d1d9cf8b10e1..0f22e7d337cb 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.c
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c
@@ -145,6 +145,13 @@ static irqreturn_t mtk_ethdr_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+u32 mtk_ethdr_get_blend_modes(struct device *dev)
+{
+ return BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE) |
+ BIT(DRM_MODE_BLEND_PIXEL_NONE);
+}
+
void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.h b/drivers/gpu/drm/mediatek/mtk_ethdr.h
index 81af9edea3f7..a72aeee46829 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.h
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.h
@@ -13,6 +13,7 @@ void mtk_ethdr_clk_disable(struct device *dev);
void mtk_ethdr_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+u32 mtk_ethdr_get_blend_modes(struct device *dev);
void mtk_ethdr_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 7d2cb4e0fafa..8a48b3b0a956 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -320,8 +320,8 @@ static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs, enum drm_plane_type type,
- unsigned int supported_rotations, const u32 *formats,
- size_t num_formats, unsigned int plane_idx)
+ unsigned int supported_rotations, const u32 blend_modes,
+ const u32 *formats, size_t num_formats, unsigned int plane_idx)
{
int err;
@@ -366,12 +366,11 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
if (err)
DRM_ERROR("failed to create property: alpha\n");
- err = drm_plane_create_blend_mode_property(plane,
- BIT(DRM_MODE_BLEND_PREMULTI) |
- BIT(DRM_MODE_BLEND_COVERAGE) |
- BIT(DRM_MODE_BLEND_PIXEL_NONE));
- if (err)
- DRM_ERROR("failed to create property: blend_mode\n");
+ if (blend_modes) {
+ err = drm_plane_create_blend_mode_property(plane, blend_modes);
+ if (err)
+ DRM_ERROR("failed to create property: blend_mode\n");
+ }
drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.h b/drivers/gpu/drm/mediatek/mtk_plane.h
index 5b177eac67b7..3b13b89989c7 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_plane.h
@@ -48,6 +48,6 @@ to_mtk_plane_state(struct drm_plane_state *state)
int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs, enum drm_plane_type type,
- unsigned int supported_rotations, const u32 *formats,
- size_t num_formats, unsigned int plane_idx);
+ unsigned int supported_rotations, const u32 blend_modes,
+ const u32 *formats, size_t num_formats, unsigned int plane_idx);
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 4082c8f2951d..6fbff516c1c1 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -390,11 +390,15 @@ int panthor_device_mmap_io(struct panthor_device *ptdev, struct vm_area_struct *
{
u64 offset = (u64)vma->vm_pgoff << PAGE_SHIFT;
+ if ((vma->vm_flags & VM_SHARED) == 0)
+ return -EINVAL;
+
switch (offset) {
case DRM_PANTHOR_USER_FLUSH_ID_MMIO_OFFSET:
if (vma->vm_end - vma->vm_start != PAGE_SIZE ||
(vma->vm_flags & (VM_WRITE | VM_EXEC)))
return -EINVAL;
+ vm_flags_clear(vma, VM_MAYWRITE);
break;
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index ef232c0c2049..4e2d3a02ea06 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -487,6 +487,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
struct panthor_fw_binary_iter *iter,
u32 ehdr)
{
+ ssize_t vm_pgsz = panthor_vm_page_size(ptdev->fw->vm);
struct panthor_fw_binary_section_entry_hdr hdr;
struct panthor_fw_section *section;
u32 section_size;
@@ -515,8 +516,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
return -EINVAL;
}
- if ((hdr.va.start & ~PAGE_MASK) != 0 ||
- (hdr.va.end & ~PAGE_MASK) != 0) {
+ if (!IS_ALIGNED(hdr.va.start, vm_pgsz) || !IS_ALIGNED(hdr.va.end, vm_pgsz)) {
drm_err(&ptdev->base, "Firmware corrupted, virtual addresses not page aligned: 0x%x-0x%x\n",
hdr.va.start, hdr.va.end);
return -EINVAL;
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index 38f560864879..be97d56bc011 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -44,8 +44,7 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo)
to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm)))
goto out_free_bo;
- ret = panthor_vm_unmap_range(vm, bo->va_node.start,
- panthor_kernel_bo_size(bo));
+ ret = panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size);
if (ret)
goto out_free_bo;
@@ -95,10 +94,16 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
}
bo = to_panthor_bo(&obj->base);
- size = obj->base.size;
kbo->obj = &obj->base;
bo->flags = bo_flags;
+ /* The system and GPU MMU page size might differ, which becomes a
+ * problem for FW sections that need to be mapped at explicit address
+ * since our PAGE_SIZE alignment might cover a VA range that's
+ * expected to be used for another section.
+ * Make sure we never map more than we need.
+ */
+ size = ALIGN(size, panthor_vm_page_size(vm));
ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node);
if (ret)
goto err_put_obj;
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c
index 3cd2bce59edc..7db2edb3374c 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.c
+++ b/drivers/gpu/drm/panthor/panthor_mmu.c
@@ -826,6 +826,14 @@ void panthor_vm_idle(struct panthor_vm *vm)
mutex_unlock(&ptdev->mmu->as.slots_lock);
}
+u32 panthor_vm_page_size(struct panthor_vm *vm)
+{
+ const struct io_pgtable *pgt = io_pgtable_ops_to_pgtable(vm->pgtbl_ops);
+ u32 pg_shift = ffs(pgt->cfg.pgsize_bitmap) - 1;
+
+ return 1u << pg_shift;
+}
+
static void panthor_vm_stop(struct panthor_vm *vm)
{
drm_sched_stop(&vm->sched, NULL);
@@ -1025,12 +1033,13 @@ int
panthor_vm_alloc_va(struct panthor_vm *vm, u64 va, u64 size,
struct drm_mm_node *va_node)
{
+ ssize_t vm_pgsz = panthor_vm_page_size(vm);
int ret;
- if (!size || (size & ~PAGE_MASK))
+ if (!size || !IS_ALIGNED(size, vm_pgsz))
return -EINVAL;
- if (va != PANTHOR_VM_KERNEL_AUTO_VA && (va & ~PAGE_MASK))
+ if (va != PANTHOR_VM_KERNEL_AUTO_VA && !IS_ALIGNED(va, vm_pgsz))
return -EINVAL;
mutex_lock(&vm->mm_lock);
@@ -1571,7 +1580,9 @@ panthor_vm_pool_get_vm(struct panthor_vm_pool *pool, u32 handle)
{
struct panthor_vm *vm;
+ xa_lock(&pool->xa);
vm = panthor_vm_get(xa_load(&pool->xa, handle));
+ xa_unlock(&pool->xa);
return vm;
}
@@ -2366,11 +2377,12 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file,
const struct drm_panthor_vm_bind_op *op,
struct panthor_vm_op_ctx *op_ctx)
{
+ ssize_t vm_pgsz = panthor_vm_page_size(vm);
struct drm_gem_object *gem;
int ret;
/* Aligned on page size. */
- if ((op->va | op->size) & ~PAGE_MASK)
+ if (!IS_ALIGNED(op->va | op->size, vm_pgsz))
return -EINVAL;
switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {
diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/panthor/panthor_mmu.h
index 6788771071e3..8d21e83d8aba 100644
--- a/drivers/gpu/drm/panthor/panthor_mmu.h
+++ b/drivers/gpu/drm/panthor/panthor_mmu.h
@@ -30,6 +30,7 @@ panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset);
int panthor_vm_active(struct panthor_vm *vm);
void panthor_vm_idle(struct panthor_vm *vm);
+u32 panthor_vm_page_size(struct panthor_vm *vm);
int panthor_vm_as(struct panthor_vm *vm);
int panthor_vm_flush_all(struct panthor_vm *vm);
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index aee362abb710..9929e22f4d8d 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -589,10 +589,11 @@ struct panthor_group {
* @timedout: True when a timeout occurred on any of the queues owned by
* this group.
*
- * Timeouts can be reported by drm_sched or by the FW. In any case, any
- * timeout situation is unrecoverable, and the group becomes useless.
- * We simply wait for all references to be dropped so we can release the
- * group object.
+ * Timeouts can be reported by drm_sched or by the FW. If a reset is required,
+ * and the group can't be suspended, this also leads to a timeout. In any case,
+ * any timeout situation is unrecoverable, and the group becomes useless. We
+ * simply wait for all references to be dropped so we can release the group
+ * object.
*/
bool timedout;
@@ -2640,6 +2641,12 @@ void panthor_sched_suspend(struct panthor_device *ptdev)
csgs_upd_ctx_init(&upd_ctx);
while (slot_mask) {
u32 csg_id = ffs(slot_mask) - 1;
+ struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id];
+
+ /* We consider group suspension failures as fatal and flag the
+ * group as unusable by setting timedout=true.
+ */
+ csg_slot->group->timedout = true;
csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id,
CSG_STATE_TERMINATE,
@@ -3409,6 +3416,11 @@ panthor_job_create(struct panthor_file *pfile,
goto err_put_job;
}
+ if (!group_can_run(job->group)) {
+ ret = -EINVAL;
+ goto err_put_job;
+ }
+
if (job->queue_idx >= job->group->queue_count ||
!job->group->queues[job->queue_idx]) {
ret = -EINVAL;
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index eaef20f41786..e97c6c60bc96 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -1276,10 +1276,11 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
sched->own_submit_wq = false;
} else {
#ifdef CONFIG_LOCKDEP
- sched->submit_wq = alloc_ordered_workqueue_lockdep_map(name, 0,
+ sched->submit_wq = alloc_ordered_workqueue_lockdep_map(name,
+ WQ_MEM_RECLAIM,
&drm_sched_lockdep_map);
#else
- sched->submit_wq = alloc_ordered_workqueue(name, 0);
+ sched->submit_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
#endif
if (!sched->submit_wq)
return -ENOMEM;
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index c9eb329665ec..34d22ba210b0 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1153,8 +1153,8 @@ static int host1x_drm_probe(struct host1x_device *dev)
if (host1x_drm_wants_iommu(dev) && device_iommu_mapped(dma_dev)) {
tegra->domain = iommu_paging_domain_alloc(dma_dev);
- if (!tegra->domain) {
- err = -ENOMEM;
+ if (IS_ERR(tegra->domain)) {
+ err = PTR_ERR(tegra->domain);
goto free;
}
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 15e36a8db685..6bba97d0be88 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -996,7 +996,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb(struct kunit *test)
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1017,7 +1017,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc(struct kunit *test)
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1038,7 +1038,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1(struct kunit *t
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
rate = drm_hdmi_compute_mode_clock(mode, 10, HDMI_COLORSPACE_RGB);
@@ -1056,7 +1056,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc(struct kunit *test)
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1077,7 +1077,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1(struct kunit *t
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
rate = drm_hdmi_compute_mode_clock(mode, 12, HDMI_COLORSPACE_RGB);
@@ -1095,7 +1095,7 @@ static void drm_test_drm_hdmi_compute_mode_clock_rgb_double(struct kunit *test)
unsigned long long rate;
struct drm_device *drm = &priv->drm;
- mode = drm_display_mode_from_cea_vic(drm, 6);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 6);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_TRUE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1118,7 +1118,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_valid(struct kunit
unsigned long long rate;
unsigned int vic = *(unsigned int *)test->param_value;
- mode = drm_display_mode_from_cea_vic(drm, vic);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1155,7 +1155,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc(struct kuni
drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0];
unsigned long long rate;
- mode = drm_display_mode_from_cea_vic(drm, vic);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1180,7 +1180,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc(struct kuni
drm_hdmi_compute_mode_clock_yuv420_vic_valid_tests[0];
unsigned long long rate;
- mode = drm_display_mode_from_cea_vic(drm, vic);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, vic);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1203,7 +1203,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc(struct kunit
struct drm_device *drm = &priv->drm;
unsigned long long rate;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1225,7 +1225,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc(struct kuni
struct drm_device *drm = &priv->drm;
unsigned long long rate;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
@@ -1247,7 +1247,7 @@ static void drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc(struct kuni
struct drm_device *drm = &priv->drm;
unsigned long long rate;
- mode = drm_display_mode_from_cea_vic(drm, 16);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
KUNIT_ASSERT_NOT_NULL(test, mode);
KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 34ee95d41f29..294773342e71 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -441,7 +441,7 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
drm = &priv->drm;
@@ -555,7 +555,7 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
drm = &priv->drm;
@@ -671,7 +671,7 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
drm = &priv->drm;
@@ -1263,7 +1263,7 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
ctx = drm_kunit_helper_acquire_ctx_alloc(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
- mode = drm_display_mode_from_cea_vic(drm, 1);
+ mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
/*
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index aa62719dab0e..04a6b8cc62ac 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -3,6 +3,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
@@ -311,6 +312,47 @@ drm_kunit_helper_create_crtc(struct kunit *test,
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_create_crtc);
+static void kunit_action_drm_mode_destroy(void *ptr)
+{
+ struct drm_display_mode *mode = ptr;
+
+ drm_mode_destroy(NULL, mode);
+}
+
+/**
+ * drm_kunit_display_mode_from_cea_vic() - return a mode for CEA VIC
+ for a KUnit test
+ * @test: The test context object
+ * @dev: DRM device
+ * @video_code: CEA VIC of the mode
+ *
+ * Creates a new mode matching the specified CEA VIC for a KUnit test.
+ *
+ * Resources will be cleaned up automatically.
+ *
+ * Returns: A new drm_display_mode on success or NULL on failure
+ */
+struct drm_display_mode *
+drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev,
+ u8 video_code)
+{
+ struct drm_display_mode *mode;
+ int ret;
+
+ mode = drm_display_mode_from_cea_vic(dev, video_code);
+ if (!mode)
+ return NULL;
+
+ ret = kunit_add_action_or_reset(test,
+ kunit_action_drm_mode_destroy,
+ mode);
+ if (ret)
+ return NULL;
+
+ return mode;
+}
+EXPORT_SYMBOL_GPL(drm_kunit_display_mode_from_cea_vic);
+
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_DESCRIPTION("KUnit test suite helper functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c
index 75736faf2a80..c6e0c8d77a70 100644
--- a/drivers/gpu/drm/xe/display/xe_display.c
+++ b/drivers/gpu/drm/xe/display/xe_display.c
@@ -309,18 +309,7 @@ static void xe_display_flush_cleanup_work(struct xe_device *xe)
}
/* TODO: System and runtime suspend/resume sequences will be sanitized as a follow-up. */
-void xe_display_pm_runtime_suspend(struct xe_device *xe)
-{
- if (!xe->info.probe_display)
- return;
-
- if (xe->d3cold.allowed)
- xe_display_pm_suspend(xe, true);
-
- intel_hpd_poll_enable(xe);
-}
-
-void xe_display_pm_suspend(struct xe_device *xe, bool runtime)
+static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime)
{
struct intel_display *display = &xe->display;
bool s2idle = suspend_to_idle();
@@ -353,28 +342,38 @@ void xe_display_pm_suspend(struct xe_device *xe, bool runtime)
intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold);
intel_dmc_suspend(xe);
+
+ if (runtime && has_display(xe))
+ intel_hpd_poll_enable(xe);
}
-void xe_display_pm_suspend_late(struct xe_device *xe)
+void xe_display_pm_suspend(struct xe_device *xe)
+{
+ __xe_display_pm_suspend(xe, false);
+}
+
+void xe_display_pm_runtime_suspend(struct xe_device *xe)
{
- bool s2idle = suspend_to_idle();
if (!xe->info.probe_display)
return;
- intel_power_domains_suspend(xe, s2idle);
+ if (xe->d3cold.allowed) {
+ __xe_display_pm_suspend(xe, true);
+ return;
+ }
- intel_display_power_suspend_late(xe);
+ intel_hpd_poll_enable(xe);
}
-void xe_display_pm_runtime_resume(struct xe_device *xe)
+void xe_display_pm_suspend_late(struct xe_device *xe)
{
+ bool s2idle = suspend_to_idle();
if (!xe->info.probe_display)
return;
- intel_hpd_poll_disable(xe);
+ intel_power_domains_suspend(xe, s2idle);
- if (xe->d3cold.allowed)
- xe_display_pm_resume(xe, true);
+ intel_display_power_suspend_late(xe);
}
void xe_display_pm_resume_early(struct xe_device *xe)
@@ -387,7 +386,7 @@ void xe_display_pm_resume_early(struct xe_device *xe)
intel_power_domains_resume(xe);
}
-void xe_display_pm_resume(struct xe_device *xe, bool runtime)
+static void __xe_display_pm_resume(struct xe_device *xe, bool runtime)
{
struct intel_display *display = &xe->display;
@@ -411,9 +410,11 @@ void xe_display_pm_resume(struct xe_device *xe, bool runtime)
intel_display_driver_resume(xe);
drm_kms_helper_poll_enable(&xe->drm);
intel_display_driver_enable_user_access(xe);
- intel_hpd_poll_disable(xe);
}
+ if (has_display(xe))
+ intel_hpd_poll_disable(xe);
+
intel_opregion_resume(display);
intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_RUNNING, false);
@@ -421,6 +422,26 @@ void xe_display_pm_resume(struct xe_device *xe, bool runtime)
intel_power_domains_enable(xe);
}
+void xe_display_pm_resume(struct xe_device *xe)
+{
+ __xe_display_pm_resume(xe, false);
+}
+
+void xe_display_pm_runtime_resume(struct xe_device *xe)
+{
+ if (!xe->info.probe_display)
+ return;
+
+ if (xe->d3cold.allowed) {
+ __xe_display_pm_resume(xe, true);
+ return;
+ }
+
+ intel_hpd_init(xe);
+ intel_hpd_poll_disable(xe);
+}
+
+
static void display_device_remove(struct drm_device *dev, void *arg)
{
struct xe_device *xe = arg;
diff --git a/drivers/gpu/drm/xe/display/xe_display.h b/drivers/gpu/drm/xe/display/xe_display.h
index 53d727fd792b..bed55fd26f30 100644
--- a/drivers/gpu/drm/xe/display/xe_display.h
+++ b/drivers/gpu/drm/xe/display/xe_display.h
@@ -34,10 +34,10 @@ void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir);
void xe_display_irq_reset(struct xe_device *xe);
void xe_display_irq_postinstall(struct xe_device *xe, struct xe_gt *gt);
-void xe_display_pm_suspend(struct xe_device *xe, bool runtime);
+void xe_display_pm_suspend(struct xe_device *xe);
void xe_display_pm_suspend_late(struct xe_device *xe);
void xe_display_pm_resume_early(struct xe_device *xe);
-void xe_display_pm_resume(struct xe_device *xe, bool runtime);
+void xe_display_pm_resume(struct xe_device *xe);
void xe_display_pm_runtime_suspend(struct xe_device *xe);
void xe_display_pm_runtime_resume(struct xe_device *xe);
@@ -65,10 +65,10 @@ static inline void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
static inline void xe_display_irq_reset(struct xe_device *xe) {}
static inline void xe_display_irq_postinstall(struct xe_device *xe, struct xe_gt *gt) {}
-static inline void xe_display_pm_suspend(struct xe_device *xe, bool runtime) {}
+static inline void xe_display_pm_suspend(struct xe_device *xe) {}
static inline void xe_display_pm_suspend_late(struct xe_device *xe) {}
static inline void xe_display_pm_resume_early(struct xe_device *xe) {}
-static inline void xe_display_pm_resume(struct xe_device *xe, bool runtime) {}
+static inline void xe_display_pm_resume(struct xe_device *xe) {}
static inline void xe_display_pm_runtime_suspend(struct xe_device *xe) {}
static inline void xe_display_pm_runtime_resume(struct xe_device *xe) {}
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 00ad34ed73a5..bd604b9f08e4 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -517,7 +517,7 @@
* [4-6] RSVD
* [7] Disabled
*/
-#define CCS_MODE XE_REG(0x14804)
+#define CCS_MODE XE_REG(0x14804, XE_REG_OPTION_MASKED)
#define CCS_MODE_CSLICE_0_3_MASK REG_GENMASK(11, 0) /* 3 bits per cslice */
#define CCS_MODE_CSLICE_MASK 0x7 /* CCS0-3 + rsvd */
#define CCS_MODE_CSLICE_WIDTH ilog2(CCS_MODE_CSLICE_MASK + 1)
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 0a9ffc19e92f..a1987b554a8d 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -87,10 +87,6 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
mutex_init(&xef->exec_queue.lock);
xa_init_flags(&xef->exec_queue.xa, XA_FLAGS_ALLOC1);
- spin_lock(&xe->clients.lock);
- xe->clients.count++;
- spin_unlock(&xe->clients.lock);
-
file->driver_priv = xef;
kref_init(&xef->refcount);
@@ -107,17 +103,12 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file)
static void xe_file_destroy(struct kref *ref)
{
struct xe_file *xef = container_of(ref, struct xe_file, refcount);
- struct xe_device *xe = xef->xe;
xa_destroy(&xef->exec_queue.xa);
mutex_destroy(&xef->exec_queue.lock);
xa_destroy(&xef->vm.xa);
mutex_destroy(&xef->vm.lock);
- spin_lock(&xe->clients.lock);
- xe->clients.count--;
- spin_unlock(&xe->clients.lock);
-
xe_drm_client_put(xef->client);
kfree(xef->process_name);
kfree(xef);
@@ -333,7 +324,6 @@ struct xe_device *xe_device_create(struct pci_dev *pdev,
xe->info.force_execlist = xe_modparam.force_execlist;
spin_lock_init(&xe->irq.lock);
- spin_lock_init(&xe->clients.lock);
init_waitqueue_head(&xe->ufence_wq);
@@ -890,7 +880,7 @@ void xe_device_l2_flush(struct xe_device *xe)
spin_lock(&gt->global_invl_lock);
xe_mmio_write32(gt, XE2_GLOBAL_INVAL, 0x1);
- if (xe_mmio_wait32(gt, XE2_GLOBAL_INVAL, 0x1, 0x0, 150, NULL, true))
+ if (xe_mmio_wait32(gt, XE2_GLOBAL_INVAL, 0x1, 0x0, 500, NULL, true))
xe_gt_err_once(gt, "Global invalidation timeout\n");
spin_unlock(&gt->global_invl_lock);
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 894f04770454..34620ef855c0 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -178,4 +178,18 @@ void xe_device_declare_wedged(struct xe_device *xe);
struct xe_file *xe_file_get(struct xe_file *xef);
void xe_file_put(struct xe_file *xef);
+/*
+ * Occasionally it is seen that the G2H worker starts running after a delay of more than
+ * a second even after being queued and activated by the Linux workqueue subsystem. This
+ * leads to G2H timeout error. The root cause of issue lies with scheduling latency of
+ * Lunarlake Hybrid CPU. Issue disappears if we disable Lunarlake atom cores from BIOS
+ * and this is beyond xe kmd.
+ *
+ * TODO: Drop this change once workqueue scheduling delay issue is fixed on LNL Hybrid CPU.
+ */
+#define LNL_FLUSH_WORKQUEUE(wq__) \
+ flush_workqueue(wq__)
+#define LNL_FLUSH_WORK(wrk__) \
+ flush_work(wrk__)
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 09d731a9125c..687f3a9039bb 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -353,15 +353,6 @@ struct xe_device {
struct workqueue_struct *wq;
} sriov;
- /** @clients: drm clients info */
- struct {
- /** @clients.lock: Protects drm clients info */
- spinlock_t lock;
-
- /** @clients.count: number of drm clients */
- u64 count;
- } clients;
-
/** @usm: unified memory state */
struct {
/** @usm.asid: convert a ASID to VM */
diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
index f23ac1e2ed88..756b492f13b0 100644
--- a/drivers/gpu/drm/xe/xe_exec.c
+++ b/drivers/gpu/drm/xe/xe_exec.c
@@ -132,12 +132,16 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
if (XE_IOCTL_DBG(xe, !q))
return -ENOENT;
- if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_VM))
- return -EINVAL;
+ if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_VM)) {
+ err = -EINVAL;
+ goto err_exec_queue;
+ }
if (XE_IOCTL_DBG(xe, args->num_batch_buffer &&
- q->width != args->num_batch_buffer))
- return -EINVAL;
+ q->width != args->num_batch_buffer)) {
+ err = -EINVAL;
+ goto err_exec_queue;
+ }
if (XE_IOCTL_DBG(xe, q->ops->reset_status(q))) {
err = -ECANCELED;
@@ -220,6 +224,7 @@ retry:
fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm);
if (IS_ERR(fence)) {
err = PTR_ERR(fence);
+ xe_vm_unlock(vm);
goto err_unlock_list;
}
for (i = 0; i < num_syncs; i++)
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index d098d2dd1b2d..fd0f3b3c9101 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -260,8 +260,14 @@ void xe_exec_queue_fini(struct xe_exec_queue *q)
{
int i;
+ /*
+ * Before releasing our ref to lrc and xef, accumulate our run ticks
+ */
+ xe_exec_queue_update_run_ticks(q);
+
for (i = 0; i < q->width; ++i)
xe_lrc_put(q->lrc[i]);
+
__xe_exec_queue_free(q);
}
diff --git a/drivers/gpu/drm/xe/xe_force_wake.c b/drivers/gpu/drm/xe/xe_force_wake.c
index b263fff15273..7d9fc489dcb8 100644
--- a/drivers/gpu/drm/xe/xe_force_wake.c
+++ b/drivers/gpu/drm/xe/xe_force_wake.c
@@ -115,9 +115,15 @@ static int __domain_wait(struct xe_gt *gt, struct xe_force_wake_domain *domain,
XE_FORCE_WAKE_ACK_TIMEOUT_MS * USEC_PER_MSEC,
&value, true);
if (ret)
- xe_gt_notice(gt, "Force wake domain %d failed to ack %s (%pe) reg[%#x] = %#x\n",
- domain->id, str_wake_sleep(wake), ERR_PTR(ret),
- domain->reg_ack.addr, value);
+ xe_gt_err(gt, "Force wake domain %d failed to ack %s (%pe) reg[%#x] = %#x\n",
+ domain->id, str_wake_sleep(wake), ERR_PTR(ret),
+ domain->reg_ack.addr, value);
+ if (value == ~0) {
+ xe_gt_err(gt,
+ "Force wake domain %d: %s. MMIO unreliable (forcewake register returns 0xFFFFFFFF)!\n",
+ domain->id, str_wake_sleep(wake));
+ ret = -EIO;
+ }
return ret;
}
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index 2895f154654c..ff19eca5d358 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -397,6 +397,16 @@ static void ggtt_invalidate_gt_tlb(struct xe_gt *gt)
static void xe_ggtt_invalidate(struct xe_ggtt *ggtt)
{
+ struct xe_device *xe = tile_to_xe(ggtt->tile);
+
+ /*
+ * XXX: Barrier for GGTT pages. Unsure exactly why this required but
+ * without this LNL is having issues with the GuC reading scratch page
+ * vs. correct GGTT page. Not particularly a hot code path so blindly
+ * do a mmio read here which results in GuC reading correct GGTT page.
+ */
+ xe_mmio_read32(xe_root_mmio_gt(xe), VF_CAP_REG);
+
/* Each GT in a tile has its own TLB to cache GGTT lookups */
ggtt_invalidate_gt_tlb(ggtt->tile->primary_gt);
ggtt_invalidate_gt_tlb(ggtt->tile->media_gt);
diff --git a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
index d2e4dc3aaf61..ffcbd05671fc 100644
--- a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
+++ b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
@@ -68,6 +68,12 @@ static void __xe_gt_apply_ccs_mode(struct xe_gt *gt, u32 num_engines)
}
}
+ /*
+ * Mask bits need to be set for the register. Though only Xe2+
+ * platforms require setting of mask bits, it won't harm for older
+ * platforms as these bits are unused there.
+ */
+ mode |= CCS_MODE_CSLICE_0_3_MASK << 16;
xe_mmio_write32(gt, CCS_MODE, mode);
xe_gt_dbg(gt, "CCS_MODE=%x config:%08x, num_engines:%d, num_slices:%d\n",
@@ -133,9 +139,10 @@ ccs_mode_store(struct device *kdev, struct device_attribute *attr,
}
/* CCS mode can only be updated when there are no drm clients */
- spin_lock(&xe->clients.lock);
- if (xe->clients.count) {
- spin_unlock(&xe->clients.lock);
+ mutex_lock(&xe->drm.filelist_mutex);
+ if (!list_empty(&xe->drm.filelist)) {
+ mutex_unlock(&xe->drm.filelist_mutex);
+ xe_gt_dbg(gt, "Rejecting compute mode change as there are active drm clients\n");
return -EBUSY;
}
@@ -146,7 +153,7 @@ ccs_mode_store(struct device *kdev, struct device_attribute *attr,
xe_gt_reset_async(gt);
}
- spin_unlock(&xe->clients.lock);
+ mutex_unlock(&xe->drm.filelist_mutex);
return count;
}
diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
index 8250ef71e685..afdb477ecf83 100644
--- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
+++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c
@@ -387,6 +387,8 @@ static void pf_release_ggtt(struct xe_tile *tile, struct xe_ggtt_node *node)
* the xe_ggtt_clear() called by below xe_ggtt_remove_node().
*/
xe_ggtt_node_remove(node, false);
+ } else {
+ xe_ggtt_node_fini(node);
}
}
@@ -442,7 +444,7 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size)
config->ggtt_region = node;
return 0;
err:
- xe_ggtt_node_fini(node);
+ pf_release_ggtt(tile, node);
return err;
}
diff --git a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
index bbb9e411d21f..9d82ea30f4df 100644
--- a/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
+++ b/drivers/gpu/drm/xe/xe_gt_tlb_invalidation.c
@@ -72,6 +72,8 @@ static void xe_gt_tlb_fence_timeout(struct work_struct *work)
struct xe_device *xe = gt_to_xe(gt);
struct xe_gt_tlb_invalidation_fence *fence, *next;
+ LNL_FLUSH_WORK(&gt->uc.guc.ct.g2h_worker);
+
spin_lock_irq(&gt->tlb_invalidation.pending_lock);
list_for_each_entry_safe(fence, next,
&gt->tlb_invalidation.pending_fences, link) {
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index d16eb9ab49fb..9c505d3517cd 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -897,6 +897,15 @@ retry_same_fence:
ret = wait_event_timeout(ct->g2h_fence_wq, g2h_fence.done, HZ);
+ if (!ret) {
+ LNL_FLUSH_WORK(&ct->g2h_worker);
+ if (g2h_fence.done) {
+ xe_gt_warn(gt, "G2H fence %u, action %04x, done\n",
+ g2h_fence.seqno, action[0]);
+ ret = 1;
+ }
+ }
+
/*
* Ensure we serialize with completion side to prevent UAF with fence going out of scope on
* the stack, since we have no clue if it will fire after the timeout before we can erase
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 8a9254e5af6e..4f5d00aea716 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -745,8 +745,6 @@ static void guc_exec_queue_free_job(struct drm_sched_job *drm_job)
{
struct xe_sched_job *job = to_xe_sched_job(drm_job);
- xe_exec_queue_update_run_ticks(job->q);
-
trace_xe_sched_job_free(job);
xe_sched_job_put(job);
}
@@ -916,12 +914,22 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w)
static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job)
{
struct xe_gt *gt = guc_to_gt(exec_queue_to_guc(q));
- u32 ctx_timestamp = xe_lrc_ctx_timestamp(q->lrc[0]);
- u32 ctx_job_timestamp = xe_lrc_ctx_job_timestamp(q->lrc[0]);
+ u32 ctx_timestamp, ctx_job_timestamp;
u32 timeout_ms = q->sched_props.job_timeout_ms;
u32 diff;
u64 running_time_ms;
+ if (!xe_sched_job_started(job)) {
+ xe_gt_warn(gt, "Check job timeout: seqno=%u, lrc_seqno=%u, guc_id=%d, not started",
+ xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
+ q->guc->id);
+
+ return xe_sched_invalidate_job(job, 2);
+ }
+
+ ctx_timestamp = xe_lrc_ctx_timestamp(q->lrc[0]);
+ ctx_job_timestamp = xe_lrc_ctx_job_timestamp(q->lrc[0]);
+
/*
* Counter wraps at ~223s at the usual 19.2MHz, be paranoid catch
* possible overflows with a high timeout.
@@ -1049,10 +1057,6 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
exec_queue_killed_or_banned_or_wedged(q) ||
exec_queue_destroyed(q);
- /* Job hasn't started, can't be timed out */
- if (!skip_timeout_check && !xe_sched_job_started(job))
- goto rearm;
-
/*
* XXX: Sampling timeout doesn't work in wedged mode as we have to
* modify scheduling state to read timestamp. We could read the
@@ -1726,8 +1730,13 @@ void xe_guc_submit_stop(struct xe_guc *guc)
mutex_lock(&guc->submission_state.lock);
- xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
+ xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) {
+ /* Prevent redundant attempts to stop parallel queues */
+ if (q->guc->id != index)
+ continue;
+
guc_exec_queue_stop(guc, q);
+ }
mutex_unlock(&guc->submission_state.lock);
@@ -1765,8 +1774,13 @@ int xe_guc_submit_start(struct xe_guc *guc)
mutex_lock(&guc->submission_state.lock);
atomic_dec(&guc->submission_state.stopped);
- xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
+ xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) {
+ /* Prevent redundant attempts to start parallel queues */
+ if (q->guc->id != index)
+ continue;
+
guc_exec_queue_start(q);
+ }
mutex_unlock(&guc->submission_state.lock);
wake_up_all(&guc->ct.wq);
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index 7cf2160fe040..33eb039053e4 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -123,7 +123,7 @@ int xe_pm_suspend(struct xe_device *xe)
for_each_gt(gt, xe, id)
xe_gt_suspend_prepare(gt);
- xe_display_pm_suspend(xe, false);
+ xe_display_pm_suspend(xe);
/* FIXME: Super racey... */
err = xe_bo_evict_all(xe);
@@ -133,7 +133,7 @@ int xe_pm_suspend(struct xe_device *xe)
for_each_gt(gt, xe, id) {
err = xe_gt_suspend(gt);
if (err) {
- xe_display_pm_resume(xe, false);
+ xe_display_pm_resume(xe);
goto err;
}
}
@@ -187,7 +187,7 @@ int xe_pm_resume(struct xe_device *xe)
for_each_gt(gt, xe, id)
xe_gt_resume(gt);
- xe_display_pm_resume(xe, false);
+ xe_display_pm_resume(xe);
err = xe_bo_restore_user(xe);
if (err)
diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
index c6cf227ead40..2e72c06fd40d 100644
--- a/drivers/gpu/drm/xe/xe_sync.c
+++ b/drivers/gpu/drm/xe/xe_sync.c
@@ -54,8 +54,9 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr,
{
struct xe_user_fence *ufence;
u64 __user *ptr = u64_to_user_ptr(addr);
+ u64 __maybe_unused prefetch_val;
- if (!access_ok(ptr, sizeof(*ptr)))
+ if (get_user(prefetch_val, ptr))
return ERR_PTR(-EFAULT);
ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
diff --git a/drivers/gpu/drm/xe/xe_wait_user_fence.c b/drivers/gpu/drm/xe/xe_wait_user_fence.c
index f5deb81eba01..5b4264ea38bd 100644
--- a/drivers/gpu/drm/xe/xe_wait_user_fence.c
+++ b/drivers/gpu/drm/xe/xe_wait_user_fence.c
@@ -155,6 +155,13 @@ int xe_wait_user_fence_ioctl(struct drm_device *dev, void *data,
}
if (!timeout) {
+ LNL_FLUSH_WORKQUEUE(xe->ordered_wq);
+ err = do_compare(addr, args->value, args->mask,
+ args->op);
+ if (err <= 0) {
+ drm_dbg(&xe->drm, "LNL_FLUSH_WORKQUEUE resolved ufence timeout\n");
+ break;
+ }
err = -ETIME;
break;
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 612ee6ddfc8d..582fd234eec7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1875,7 +1875,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
u32 len = hid_report_len(report) + 7;
- return kmalloc(len, flags);
+ return kzalloc(len, flags);
}
EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index f31d352d98b5..9d88b4fa03e4 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -524,7 +524,7 @@ err_release_lock:
void __i2c_dw_disable(struct dw_i2c_dev *dev)
{
struct i2c_timings *t = &dev->timings;
- unsigned int raw_intr_stats;
+ unsigned int raw_intr_stats, ic_stats;
unsigned int enable;
int timeout = 100;
bool abort_needed;
@@ -532,9 +532,11 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
int ret;
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_intr_stats);
+ regmap_read(dev->map, DW_IC_STATUS, &ic_stats);
regmap_read(dev->map, DW_IC_ENABLE, &enable);
- abort_needed = raw_intr_stats & DW_IC_INTR_MST_ON_HOLD;
+ abort_needed = (raw_intr_stats & DW_IC_INTR_MST_ON_HOLD) ||
+ (ic_stats & DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY);
if (abort_needed) {
if (!(enable & DW_IC_ENABLE_ENABLE)) {
regmap_write(dev->map, DW_IC_ENABLE, DW_IC_ENABLE_ENABLE);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 8e8854ec9882..2d32896d0673 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -116,6 +116,7 @@
#define DW_IC_STATUS_RFNE BIT(3)
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
+#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
diff --git a/drivers/i2c/muxes/i2c-mux-mule.c b/drivers/i2c/muxes/i2c-mux-mule.c
index 8e942470b35f..284ff4afeeac 100644
--- a/drivers/i2c/muxes/i2c-mux-mule.c
+++ b/drivers/i2c/muxes/i2c-mux-mule.c
@@ -66,8 +66,8 @@ static int mule_i2c_mux_probe(struct platform_device *pdev)
priv = i2c_mux_priv(muxc);
priv->regmap = dev_get_regmap(mux_dev->parent, NULL);
- if (IS_ERR(priv->regmap))
- return dev_err_probe(mux_dev, PTR_ERR(priv->regmap),
+ if (!priv->regmap)
+ return dev_err_probe(mux_dev, -ENODEV,
"No parent i2c register map\n");
platform_set_drvdata(pdev, muxc);
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index a5d91933f505..b79c48d46ccc 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -637,7 +637,7 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
- if (val2 != 0) {
+ if (val2 != 0 || val == 0) {
ret = -EINVAL;
break;
}
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index e8bddfb0d07d..fb728570debe 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -75,6 +75,7 @@
#define T_CONVERT_NS 190 /* conversion time */
#define T_CONVERT_0_NS 10 /* 1st conversion start time (oversampling) */
#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
+#define T_POWERUP_US 5000 /* Power up */
struct ad7380_timing_specs {
const unsigned int t_csh_ns; /* CS minimum high time */
@@ -86,6 +87,9 @@ struct ad7380_chip_info {
unsigned int num_channels;
unsigned int num_simult_channels;
bool has_mux;
+ const char * const *supplies;
+ unsigned int num_supplies;
+ bool external_ref_only;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
const unsigned long *available_scan_masks;
@@ -243,6 +247,10 @@ DEFINE_AD7380_8_CHANNEL(ad7386_4_channels, 16, 0, u);
DEFINE_AD7380_8_CHANNEL(ad7387_4_channels, 14, 0, u);
DEFINE_AD7380_8_CHANNEL(ad7388_4_channels, 12, 0, u);
+static const char * const ad7380_supplies[] = {
+ "vcc", "vlogic",
+};
+
static const char * const ad7380_2_channel_vcm_supplies[] = {
"aina", "ainb",
};
@@ -338,6 +346,8 @@ static const struct ad7380_chip_info ad7380_chip_info = {
.channels = ad7380_channels,
.num_channels = ARRAY_SIZE(ad7380_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
@@ -347,6 +357,8 @@ static const struct ad7380_chip_info ad7381_chip_info = {
.channels = ad7381_channels,
.num_channels = ARRAY_SIZE(ad7381_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
};
@@ -356,6 +368,8 @@ static const struct ad7380_chip_info ad7383_chip_info = {
.channels = ad7383_channels,
.num_channels = ARRAY_SIZE(ad7383_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
@@ -367,6 +381,8 @@ static const struct ad7380_chip_info ad7384_chip_info = {
.channels = ad7384_channels,
.num_channels = ARRAY_SIZE(ad7384_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
.available_scan_masks = ad7380_2_channel_scan_masks,
@@ -378,6 +394,8 @@ static const struct ad7380_chip_info ad7386_chip_info = {
.channels = ad7386_channels,
.num_channels = ARRAY_SIZE(ad7386_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -388,6 +406,8 @@ static const struct ad7380_chip_info ad7387_chip_info = {
.channels = ad7387_channels,
.num_channels = ARRAY_SIZE(ad7387_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -398,6 +418,8 @@ static const struct ad7380_chip_info ad7388_chip_info = {
.channels = ad7388_channels,
.num_channels = ARRAY_SIZE(ad7388_channels),
.num_simult_channels = 2,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -408,6 +430,9 @@ static const struct ad7380_chip_info ad7380_4_chip_info = {
.channels = ad7380_4_channels,
.num_channels = ARRAY_SIZE(ad7380_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .external_ref_only = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
@@ -417,6 +442,8 @@ static const struct ad7380_chip_info ad7381_4_chip_info = {
.channels = ad7381_4_channels,
.num_channels = ARRAY_SIZE(ad7381_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
};
@@ -426,6 +453,8 @@ static const struct ad7380_chip_info ad7383_4_chip_info = {
.channels = ad7383_4_channels,
.num_channels = ARRAY_SIZE(ad7383_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
@@ -437,6 +466,8 @@ static const struct ad7380_chip_info ad7384_4_chip_info = {
.channels = ad7384_4_channels,
.num_channels = ARRAY_SIZE(ad7384_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
@@ -448,6 +479,8 @@ static const struct ad7380_chip_info ad7386_4_chip_info = {
.channels = ad7386_4_channels,
.num_channels = ARRAY_SIZE(ad7386_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -458,6 +491,8 @@ static const struct ad7380_chip_info ad7387_4_chip_info = {
.channels = ad7387_4_channels,
.num_channels = ARRAY_SIZE(ad7387_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -468,6 +503,8 @@ static const struct ad7380_chip_info ad7388_4_chip_info = {
.channels = ad7388_4_channels,
.num_channels = ARRAY_SIZE(ad7388_4_channels),
.num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -956,7 +993,7 @@ static const struct iio_info ad7380_info = {
.debugfs_reg_access = &ad7380_debugfs_reg_access,
};
-static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
+static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
{
int ret;
@@ -968,13 +1005,13 @@ static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
if (ret < 0)
return ret;
- /* select internal or external reference voltage */
- ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1,
- AD7380_CONFIG1_REFSEL,
- FIELD_PREP(AD7380_CONFIG1_REFSEL,
- vref ? 1 : 0));
- if (ret < 0)
- return ret;
+ if (external_ref_en) {
+ /* select external reference voltage */
+ ret = regmap_set_bits(st->regmap, AD7380_REG_ADDR_CONFIG1,
+ AD7380_CONFIG1_REFSEL);
+ if (ret < 0)
+ return ret;
+ }
/* This is the default value after reset. */
st->oversampling_ratio = 1;
@@ -987,16 +1024,11 @@ static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
FIELD_PREP(AD7380_CONFIG2_SDO, 1));
}
-static void ad7380_regulator_disable(void *p)
-{
- regulator_disable(p);
-}
-
static int ad7380_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad7380_state *st;
- struct regulator *vref;
+ bool external_ref_en;
int ret, i;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1009,36 +1041,38 @@ static int ad7380_probe(struct spi_device *spi)
if (!st->chip_info)
return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n");
- vref = devm_regulator_get_optional(&spi->dev, "refio");
- if (IS_ERR(vref)) {
- if (PTR_ERR(vref) != -ENODEV)
- return dev_err_probe(&spi->dev, PTR_ERR(vref),
- "Failed to get refio regulator\n");
-
- vref = NULL;
- }
+ ret = devm_regulator_bulk_get_enable(&spi->dev, st->chip_info->num_supplies,
+ st->chip_info->supplies);
- /*
- * If there is no REFIO supply, then it means that we are using
- * the internal 2.5V reference, otherwise REFIO is reference voltage.
- */
- if (vref) {
- ret = regulator_enable(vref);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev,
- ad7380_regulator_disable, vref);
- if (ret)
- return ret;
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to enable power supplies\n");
+ fsleep(T_POWERUP_US);
- ret = regulator_get_voltage(vref);
+ if (st->chip_info->external_ref_only) {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev,
+ "refin");
if (ret < 0)
- return ret;
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get refin regulator\n");
st->vref_mv = ret / 1000;
+
+ /* these chips don't have a register bit for this */
+ external_ref_en = false;
} else {
- st->vref_mv = AD7380_INTERNAL_REF_MV;
+ /*
+ * If there is no REFIO supply, then it means that we are using
+ * the internal reference, otherwise REFIO is reference voltage.
+ */
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev,
+ "refio");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get refio regulator\n");
+
+ external_ref_en = ret != -ENODEV;
+ st->vref_mv = external_ref_en ? ret / 1000 : AD7380_INTERNAL_REF_MV;
}
if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
@@ -1050,27 +1084,13 @@ static int ad7380_probe(struct spi_device *spi)
* input pin.
*/
for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
- struct regulator *vcm;
-
- vcm = devm_regulator_get(&spi->dev,
- st->chip_info->vcm_supplies[i]);
- if (IS_ERR(vcm))
- return dev_err_probe(&spi->dev, PTR_ERR(vcm),
- "Failed to get %s regulator\n",
- st->chip_info->vcm_supplies[i]);
+ const char *vcm = st->chip_info->vcm_supplies[i];
- ret = regulator_enable(vcm);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev,
- ad7380_regulator_disable, vcm);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(vcm);
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, vcm);
if (ret < 0)
- return ret;
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to get %s regulator\n",
+ vcm);
st->vcm_mv[i] = ret / 1000;
}
@@ -1135,7 +1155,7 @@ static int ad7380_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = ad7380_init(st, vref);
+ ret = ad7380_init(st, external_ref_en);
if (ret)
return ret;
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 45e337c6d256..9f5d5ebb8653 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -380,7 +380,7 @@ config LTC2632
config LTC2664
tristate "Analog Devices LTC2664 and LTC2672 DAC SPI driver"
depends on SPI
- select REGMAP
+ select REGMAP_SPI
help
Say yes here to build support for Analog Devices
LTC2664 and LTC2672 converters (DAC).
diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c
index 59d7615c0f56..5f131bc1a01e 100644
--- a/drivers/iio/industrialio-gts-helper.c
+++ b/drivers/iio/industrialio-gts-helper.c
@@ -307,13 +307,15 @@ static int iio_gts_build_avail_scale_table(struct iio_gts *gts)
if (ret)
goto err_free_out;
+ for (i = 0; i < gts->num_itime; i++)
+ kfree(per_time_gains[i]);
kfree(per_time_gains);
gts->per_time_avail_scale_tables = per_time_scales;
return 0;
err_free_out:
- for (i--; i; i--) {
+ for (i--; i >= 0; i--) {
kfree(per_time_scales[i]);
kfree(per_time_gains[i]);
}
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 9630de1c578e..621428885455 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -522,7 +522,7 @@ static int veml6030_read_raw(struct iio_dev *indio_dev,
}
if (mask == IIO_CHAN_INFO_PROCESSED) {
*val = (reg * data->cur_resolution) / 10000;
- *val2 = (reg * data->cur_resolution) % 10000;
+ *val2 = (reg * data->cur_resolution) % 10000 * 100;
return IIO_VAL_INT_PLUS_MICRO;
}
*val = reg;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 2ebcb2de962b..7ad83566ab0f 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -1532,9 +1532,11 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
u32 tbl_indx;
int rc;
+ spin_lock_bh(&rcfw->tbl_lock);
tbl_indx = map_qp_id_to_tbl_indx(qp->id, rcfw);
rcfw->qp_tbl[tbl_indx].qp_id = BNXT_QPLIB_QP_ID_INVALID;
rcfw->qp_tbl[tbl_indx].qp_handle = NULL;
+ spin_unlock_bh(&rcfw->tbl_lock);
bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req,
CMDQ_BASE_OPCODE_DESTROY_QP,
@@ -1545,8 +1547,10 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
sizeof(resp), 0);
rc = bnxt_qplib_rcfw_send_message(rcfw, &msg);
if (rc) {
+ spin_lock_bh(&rcfw->tbl_lock);
rcfw->qp_tbl[tbl_indx].qp_id = qp->id;
rcfw->qp_tbl[tbl_indx].qp_handle = qp;
+ spin_unlock_bh(&rcfw->tbl_lock);
return rc;
}
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
index 7294221b3316..e82bd37158ad 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -290,7 +290,6 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw,
struct bnxt_qplib_hwq *hwq;
u32 sw_prod, cmdq_prod;
struct pci_dev *pdev;
- unsigned long flags;
u16 cookie;
u8 *preq;
@@ -301,7 +300,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw,
/* Cmdq are in 16-byte units, each request can consume 1 or more
* cmdqe
*/
- spin_lock_irqsave(&hwq->lock, flags);
+ spin_lock_bh(&hwq->lock);
required_slots = bnxt_qplib_get_cmd_slots(msg->req);
free_slots = HWQ_FREE_SLOTS(hwq);
cookie = cmdq->seq_num & RCFW_MAX_COOKIE_VALUE;
@@ -311,7 +310,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw,
dev_info_ratelimited(&pdev->dev,
"CMDQ is full req/free %d/%d!",
required_slots, free_slots);
- spin_unlock_irqrestore(&hwq->lock, flags);
+ spin_unlock_bh(&hwq->lock);
return -EAGAIN;
}
if (msg->block)
@@ -367,7 +366,7 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw,
wmb();
writel(cmdq_prod, cmdq->cmdq_mbox.prod);
writel(RCFW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db);
- spin_unlock_irqrestore(&hwq->lock, flags);
+ spin_unlock_bh(&hwq->lock);
/* Return the CREQ response pointer */
return 0;
}
@@ -486,7 +485,6 @@ static int __bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
{
struct creq_qp_event *evnt = (struct creq_qp_event *)msg->resp;
struct bnxt_qplib_crsqe *crsqe;
- unsigned long flags;
u16 cookie;
int rc;
u8 opcode;
@@ -512,12 +510,12 @@ static int __bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
rc = __poll_for_resp(rcfw, cookie);
if (rc) {
- spin_lock_irqsave(&rcfw->cmdq.hwq.lock, flags);
+ spin_lock_bh(&rcfw->cmdq.hwq.lock);
crsqe = &rcfw->crsqe_tbl[cookie];
crsqe->is_waiter_alive = false;
if (rc == -ENODEV)
set_bit(FIRMWARE_STALL_DETECTED, &rcfw->cmdq.flags);
- spin_unlock_irqrestore(&rcfw->cmdq.hwq.lock, flags);
+ spin_unlock_bh(&rcfw->cmdq.hwq.lock);
return -ETIMEDOUT;
}
@@ -628,7 +626,6 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
u16 cookie, blocked = 0;
bool is_waiter_alive;
struct pci_dev *pdev;
- unsigned long flags;
u32 wait_cmds = 0;
int rc = 0;
@@ -637,17 +634,21 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
err_event = (struct creq_qp_error_notification *)qp_event;
qp_id = le32_to_cpu(err_event->xid);
+ spin_lock(&rcfw->tbl_lock);
tbl_indx = map_qp_id_to_tbl_indx(qp_id, rcfw);
qp = rcfw->qp_tbl[tbl_indx].qp_handle;
+ if (!qp) {
+ spin_unlock(&rcfw->tbl_lock);
+ break;
+ }
+ bnxt_qplib_mark_qp_error(qp);
+ rc = rcfw->creq.aeq_handler(rcfw, qp_event, qp);
+ spin_unlock(&rcfw->tbl_lock);
dev_dbg(&pdev->dev, "Received QP error notification\n");
dev_dbg(&pdev->dev,
"qpid 0x%x, req_err=0x%x, resp_err=0x%x\n",
qp_id, err_event->req_err_state_reason,
err_event->res_err_state_reason);
- if (!qp)
- break;
- bnxt_qplib_mark_qp_error(qp);
- rc = rcfw->creq.aeq_handler(rcfw, qp_event, qp);
break;
default:
/*
@@ -659,8 +660,7 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
*
*/
- spin_lock_irqsave_nested(&hwq->lock, flags,
- SINGLE_DEPTH_NESTING);
+ spin_lock_nested(&hwq->lock, SINGLE_DEPTH_NESTING);
cookie = le16_to_cpu(qp_event->cookie);
blocked = cookie & RCFW_CMD_IS_BLOCKING;
cookie &= RCFW_MAX_COOKIE_VALUE;
@@ -672,7 +672,7 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
dev_info(&pdev->dev,
"rcfw timedout: cookie = %#x, free_slots = %d",
cookie, crsqe->free_slots);
- spin_unlock_irqrestore(&hwq->lock, flags);
+ spin_unlock(&hwq->lock);
return rc;
}
@@ -720,7 +720,7 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
__destroy_timedout_ah(rcfw,
(struct creq_create_ah_resp *)
qp_event);
- spin_unlock_irqrestore(&hwq->lock, flags);
+ spin_unlock(&hwq->lock);
}
*num_wait += wait_cmds;
return rc;
@@ -734,12 +734,11 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
u32 type, budget = CREQ_ENTRY_POLL_BUDGET;
struct bnxt_qplib_hwq *hwq = &creq->hwq;
struct creq_base *creqe;
- unsigned long flags;
u32 num_wakeup = 0;
u32 hw_polled = 0;
/* Service the CREQ until budget is over */
- spin_lock_irqsave(&hwq->lock, flags);
+ spin_lock_bh(&hwq->lock);
while (budget > 0) {
creqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL);
if (!CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags))
@@ -782,7 +781,7 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
if (hw_polled)
bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo,
rcfw->res->cctx, true);
- spin_unlock_irqrestore(&hwq->lock, flags);
+ spin_unlock_bh(&hwq->lock);
if (num_wakeup)
wake_up_nr(&rcfw->cmdq.waitq, num_wakeup);
}
@@ -978,6 +977,7 @@ int bnxt_qplib_alloc_rcfw_channel(struct bnxt_qplib_res *res,
GFP_KERNEL);
if (!rcfw->qp_tbl)
goto fail;
+ spin_lock_init(&rcfw->tbl_lock);
rcfw->max_timeout = res->cctx->hwrm_cmd_max_timeout;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
index 45996e60a0d0..07779aeb7575 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
@@ -224,6 +224,8 @@ struct bnxt_qplib_rcfw {
struct bnxt_qplib_crsqe *crsqe_tbl;
int qp_tbl_size;
struct bnxt_qplib_qp_node *qp_tbl;
+ /* To synchronize the qp-handle hash table */
+ spinlock_t tbl_lock;
u64 oos_prev;
u32 init_oos_stats;
u32 cmdq_depth;
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index 10a4c738b59f..e059f92d90fd 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -473,6 +473,7 @@ static const struct ib_device_ops c4iw_dev_ops = {
.fill_res_cq_entry = c4iw_fill_res_cq_entry,
.fill_res_cm_id_entry = c4iw_fill_res_cm_id_entry,
.fill_res_mr_entry = c4iw_fill_res_mr_entry,
+ .fill_res_qp_entry = c4iw_fill_res_qp_entry,
.get_dev_fw_str = get_dev_fw_str,
.get_dma_mr = c4iw_get_dma_mr,
.get_hw_stats = c4iw_get_mib,
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index e39b1a101e97..10ce3b44f645 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -4268,14 +4268,14 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt);
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && attr->max_rd_atomic)
- MLX5_SET(qpc, qpc, log_sra_max, ilog2(attr->max_rd_atomic));
+ MLX5_SET(qpc, qpc, log_sra_max, fls(attr->max_rd_atomic - 1));
if (attr_mask & IB_QP_SQ_PSN)
MLX5_SET(qpc, qpc, next_send_psn, attr->sq_psn);
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && attr->max_dest_rd_atomic)
MLX5_SET(qpc, qpc, log_rra_max,
- ilog2(attr->max_dest_rd_atomic));
+ fls(attr->max_dest_rd_atomic - 1));
if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
err = set_qpc_atomic_flags(qp, attr, attr_mask, qpc);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 47fac29cf7c3..c51858f1cdc5 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -119,12 +119,12 @@ static void input_pass_values(struct input_dev *dev,
handle = rcu_dereference(dev->grab);
if (handle) {
- count = handle->handler->events(handle, vals, count);
+ count = handle->handle_events(handle, vals, count);
} else {
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open) {
- count = handle->handler->events(handle, vals,
- count);
+ count = handle->handle_events(handle, vals,
+ count);
if (!count)
break;
}
@@ -2534,57 +2534,6 @@ static int input_handler_check_methods(const struct input_handler *handler)
return 0;
}
-/*
- * An implementation of input_handler's events() method that simply
- * invokes handler->event() method for each event one by one.
- */
-static unsigned int input_handler_events_default(struct input_handle *handle,
- struct input_value *vals,
- unsigned int count)
-{
- struct input_handler *handler = handle->handler;
- struct input_value *v;
-
- for (v = vals; v != vals + count; v++)
- handler->event(handle, v->type, v->code, v->value);
-
- return count;
-}
-
-/*
- * An implementation of input_handler's events() method that invokes
- * handler->filter() method for each event one by one and removes events
- * that were filtered out from the "vals" array.
- */
-static unsigned int input_handler_events_filter(struct input_handle *handle,
- struct input_value *vals,
- unsigned int count)
-{
- struct input_handler *handler = handle->handler;
- struct input_value *end = vals;
- struct input_value *v;
-
- for (v = vals; v != vals + count; v++) {
- if (handler->filter(handle, v->type, v->code, v->value))
- continue;
- if (end != v)
- *end = *v;
- end++;
- }
-
- return end - vals;
-}
-
-/*
- * An implementation of input_handler's events() method that does nothing.
- */
-static unsigned int input_handler_events_null(struct input_handle *handle,
- struct input_value *vals,
- unsigned int count)
-{
- return count;
-}
-
/**
* input_register_handler - register a new input handler
* @handler: handler to be registered
@@ -2604,13 +2553,6 @@ int input_register_handler(struct input_handler *handler)
INIT_LIST_HEAD(&handler->h_list);
- if (handler->filter)
- handler->events = input_handler_events_filter;
- else if (handler->event)
- handler->events = input_handler_events_default;
- else if (!handler->events)
- handler->events = input_handler_events_null;
-
error = mutex_lock_interruptible(&input_mutex);
if (error)
return error;
@@ -2684,6 +2626,75 @@ int input_handler_for_each_handle(struct input_handler *handler, void *data,
}
EXPORT_SYMBOL(input_handler_for_each_handle);
+/*
+ * An implementation of input_handle's handle_events() method that simply
+ * invokes handler->event() method for each event one by one.
+ */
+static unsigned int input_handle_events_default(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++)
+ handler->event(handle, v->type, v->code, v->value);
+
+ return count;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that invokes
+ * handler->filter() method for each event one by one and removes events
+ * that were filtered out from the "vals" array.
+ */
+static unsigned int input_handle_events_filter(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *end = vals;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++) {
+ if (handler->filter(handle, v->type, v->code, v->value))
+ continue;
+ if (end != v)
+ *end = *v;
+ end++;
+ }
+
+ return end - vals;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that does nothing.
+ */
+static unsigned int input_handle_events_null(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ return count;
+}
+
+/*
+ * Sets up appropriate handle->event_handler based on the input_handler
+ * associated with the handle.
+ */
+static void input_handle_setup_event_handler(struct input_handle *handle)
+{
+ struct input_handler *handler = handle->handler;
+
+ if (handler->filter)
+ handle->handle_events = input_handle_events_filter;
+ else if (handler->event)
+ handle->handle_events = input_handle_events_default;
+ else if (handler->events)
+ handle->handle_events = handler->events;
+ else
+ handle->handle_events = input_handle_events_null;
+}
+
/**
* input_register_handle - register a new input handle
* @handle: handle to register
@@ -2701,6 +2712,7 @@ int input_register_handle(struct input_handle *handle)
struct input_dev *dev = handle->dev;
int error;
+ input_handle_setup_event_handler(handle);
/*
* We take dev->mutex here to prevent race with
* input_release_device().
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index d25d63a807f2..dc734974ce06 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -822,7 +822,8 @@ static int adp5588_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- disable_irq(client->irq);
+ if (client->irq)
+ disable_irq(client->irq);
return 0;
}
@@ -831,7 +832,8 @@ static int adp5588_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- enable_irq(client->irq);
+ if (client->irq)
+ enable_irq(client->irq);
return 0;
}
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index fda49b2fe088..85c6d8ce003f 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1121,6 +1121,14 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
}
}
+static void edt_ft5x06_exit_regmap(void *arg)
+{
+ struct edt_ft5x06_ts_data *data = arg;
+
+ if (!IS_ERR_OR_NULL(data->regmap))
+ regmap_exit(data->regmap);
+}
+
static void edt_ft5x06_disable_regulators(void *arg)
{
struct edt_ft5x06_ts_data *data = arg;
@@ -1154,6 +1162,16 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
return PTR_ERR(tsdata->regmap);
}
+ /*
+ * We are not using devm_regmap_init_i2c() and instead install a
+ * custom action because we may replace regmap with M06-specific one
+ * and we need to make sure that it will not be released too early.
+ */
+ error = devm_add_action_or_reset(&client->dev, edt_ft5x06_exit_regmap,
+ tsdata);
+ if (error)
+ return error;
+
chip_data = device_get_match_data(&client->dev);
if (!chip_data)
chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
@@ -1347,7 +1365,6 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client)
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
edt_ft5x06_ts_teardown_debugfs(tsdata);
- regmap_exit(tsdata->regmap);
}
static int edt_ft5x06_ts_suspend(struct device *dev)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index ab597e74ba08..52f625e07658 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3810,8 +3810,18 @@ static int its_vpe_set_affinity(struct irq_data *d,
* Check if we're racing against a VPE being destroyed, for
* which we don't want to allow a VMOVP.
*/
- if (!atomic_read(&vpe->vmapp_count))
- return -EINVAL;
+ if (!atomic_read(&vpe->vmapp_count)) {
+ if (gic_requires_eager_mapping())
+ return -EINVAL;
+
+ /*
+ * If we lazily map the VPEs, this isn't an error and
+ * we can exit cleanly.
+ */
+ cpu = cpumask_first(mask_val);
+ irq_data_update_effective_affinity(d, cpumask_of(cpu));
+ return IRQ_SET_MASK_OK_DONE;
+ }
/*
* Changing affinity is mega expensive, so let's be as lazy as
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index ce87205e3e82..8b6159f4cdaf 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -524,6 +524,13 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
}
gic_poke_irq(d, reg);
+
+ /*
+ * Force read-back to guarantee that the active state has taken
+ * effect, and won't race with a guest-driven deactivation.
+ */
+ if (reg == GICD_ISACTIVER)
+ gic_peek_irq(d, reg);
return 0;
}
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index e5a483fd9ad8..45ff0e198f8f 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -25,8 +25,8 @@
* Bit 8 = 0x00100 = uLaw (instead of aLaw)
* Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware
* Bit 10 = spare
- * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto)
- * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto)
+ * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwise auto)
+ * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwise auto)
* Bit 13 = spare
* Bit 14 = 0x04000 = Use external ram (128K)
* Bit 15 = 0x08000 = Use external ram (512K)
@@ -41,7 +41,7 @@
* port: (optional or required for all ports on all installed cards)
* HFC-4S/HFC-8S only bits:
* Bit 0 = 0x001 = Use master clock for this S/T interface
- * (ony once per chip).
+ * (only once per chip).
* Bit 1 = 0x002 = transmitter line setup (non capacitive mode)
* Don't use this unless you know what you are doing!
* Bit 2 = 0x004 = Disable E-channel. (No E-channel processing)
@@ -82,7 +82,7 @@
* By default (0), the PCM bus id is 100 for the card that is PCM master.
* If multiple cards are PCM master (because they are not interconnected),
* each card with PCM master will have increasing PCM id.
- * All PCM busses with the same ID are expected to be connected and have
+ * All PCM buses with the same ID are expected to be connected and have
* common time slots slots.
* Only one chip of the PCM bus must be master, the others slave.
* -1 means no support of PCM bus not even.
@@ -930,7 +930,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
if (newmaster) {
hc = newmaster;
if (debug & DEBUG_HFCMULTI_PLXSD)
- printk(KERN_DEBUG "id=%d (0x%p) = syncronized with "
+ printk(KERN_DEBUG "id=%d (0x%p) = synchronized with "
"interface.\n", hc->id, hc);
/* Enable new sync master */
plx_acc_32 = hc->plx_membase + PLX_GPIOC;
@@ -949,7 +949,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
hc = pcmmaster;
if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG
- "id=%d (0x%p) = PCM master syncronized "
+ "id=%d (0x%p) = PCM master synchronized "
"with QUARTZ\n", hc->id, hc);
if (hc->ctype == HFC_TYPE_E1) {
/* Use the crystal clock for the PCM
@@ -2001,7 +2001,7 @@ next_frame:
if (Zspace <= 0)
Zspace += hc->Zlen;
Zspace -= 4; /* keep not too full, so pointers will not overrun */
- /* fill transparent data only to maxinum transparent load (minus 4) */
+ /* fill transparent data only to maximum transparent load (minus 4) */
if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
Zspace = Zspace - hc->Zlen + hc->max_trans;
if (Zspace <= 0) /* no space of 4 bytes */
@@ -4672,7 +4672,7 @@ init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m)
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG
"%s: PORT set optical "
- "interfacs: card(%d) "
+ "interface: card(%d) "
"port(%d)\n",
__func__,
HFC_cnt + 1, 1);
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index d478aafa02c9..23e0b71b991e 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -2471,7 +2471,8 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
int r;
unsigned int num_locks;
struct dm_bufio_client *c;
- char slab_name[27];
+ char slab_name[64];
+ static atomic_t seqno = ATOMIC_INIT(0);
if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) {
DMERR("%s: block size not specified or is not multiple of 512b", __func__);
@@ -2522,7 +2523,8 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
(block_size < PAGE_SIZE || !is_power_of_2(block_size))) {
unsigned int align = min(1U << __ffs(block_size), (unsigned int)PAGE_SIZE);
- snprintf(slab_name, sizeof(slab_name), "dm_bufio_cache-%u", block_size);
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_cache-%u-%u",
+ block_size, atomic_inc_return(&seqno));
c->slab_cache = kmem_cache_create(slab_name, block_size, align,
SLAB_RECLAIM_ACCOUNT, NULL);
if (!c->slab_cache) {
@@ -2531,9 +2533,11 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
}
}
if (aux_size)
- snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer-%u", aux_size);
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer-%u-%u",
+ aux_size, atomic_inc_return(&seqno));
else
- snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer");
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer-%u",
+ atomic_inc_return(&seqno));
c->slab_buffer = kmem_cache_create(slab_name, sizeof(struct dm_buffer) + aux_size,
0, SLAB_RECLAIM_ACCOUNT, NULL);
if (!c->slab_buffer) {
diff --git a/drivers/md/dm-cache-background-tracker.c b/drivers/md/dm-cache-background-tracker.c
index 9c5308298cf1..f3051bd7d2df 100644
--- a/drivers/md/dm-cache-background-tracker.c
+++ b/drivers/md/dm-cache-background-tracker.c
@@ -11,12 +11,6 @@
#define DM_MSG_PREFIX "dm-background-tracker"
-struct bt_work {
- struct list_head list;
- struct rb_node node;
- struct policy_work work;
-};
-
struct background_tracker {
unsigned int max_work;
atomic_t pending_promotes;
@@ -26,10 +20,10 @@ struct background_tracker {
struct list_head issued;
struct list_head queued;
struct rb_root pending;
-
- struct kmem_cache *work_cache;
};
+struct kmem_cache *btracker_work_cache = NULL;
+
struct background_tracker *btracker_create(unsigned int max_work)
{
struct background_tracker *b = kmalloc(sizeof(*b), GFP_KERNEL);
@@ -48,12 +42,6 @@ struct background_tracker *btracker_create(unsigned int max_work)
INIT_LIST_HEAD(&b->queued);
b->pending = RB_ROOT;
- b->work_cache = KMEM_CACHE(bt_work, 0);
- if (!b->work_cache) {
- DMERR("couldn't create mempool for background work items");
- kfree(b);
- b = NULL;
- }
return b;
}
@@ -66,10 +54,9 @@ void btracker_destroy(struct background_tracker *b)
BUG_ON(!list_empty(&b->issued));
list_for_each_entry_safe (w, tmp, &b->queued, list) {
list_del(&w->list);
- kmem_cache_free(b->work_cache, w);
+ kmem_cache_free(btracker_work_cache, w);
}
- kmem_cache_destroy(b->work_cache);
kfree(b);
}
EXPORT_SYMBOL_GPL(btracker_destroy);
@@ -180,7 +167,7 @@ static struct bt_work *alloc_work(struct background_tracker *b)
if (max_work_reached(b))
return NULL;
- return kmem_cache_alloc(b->work_cache, GFP_NOWAIT);
+ return kmem_cache_alloc(btracker_work_cache, GFP_NOWAIT);
}
int btracker_queue(struct background_tracker *b,
@@ -203,7 +190,7 @@ int btracker_queue(struct background_tracker *b,
* There was a race, we'll just ignore this second
* bit of work for the same oblock.
*/
- kmem_cache_free(b->work_cache, w);
+ kmem_cache_free(btracker_work_cache, w);
return -EINVAL;
}
@@ -244,7 +231,7 @@ void btracker_complete(struct background_tracker *b,
update_stats(b, &w->work, -1);
rb_erase(&w->node, &b->pending);
list_del(&w->list);
- kmem_cache_free(b->work_cache, w);
+ kmem_cache_free(btracker_work_cache, w);
}
EXPORT_SYMBOL_GPL(btracker_complete);
diff --git a/drivers/md/dm-cache-background-tracker.h b/drivers/md/dm-cache-background-tracker.h
index 5b8f5c667b81..09c8fc59f7bb 100644
--- a/drivers/md/dm-cache-background-tracker.h
+++ b/drivers/md/dm-cache-background-tracker.h
@@ -26,6 +26,14 @@
* protected with a spinlock.
*/
+struct bt_work {
+ struct list_head list;
+ struct rb_node node;
+ struct policy_work work;
+};
+
+extern struct kmem_cache *btracker_work_cache;
+
struct background_work;
struct background_tracker;
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index aaeeabfab09b..849eb6333e98 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -10,6 +10,7 @@
#include "dm-bio-record.h"
#include "dm-cache-metadata.h"
#include "dm-io-tracker.h"
+#include "dm-cache-background-tracker.h"
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
@@ -1905,16 +1906,13 @@ static void check_migrations(struct work_struct *ws)
* This function gets called on the error paths of the constructor, so we
* have to cope with a partially initialised struct.
*/
-static void destroy(struct cache *cache)
+static void __destroy(struct cache *cache)
{
- unsigned int i;
-
mempool_exit(&cache->migration_pool);
if (cache->prison)
dm_bio_prison_destroy_v2(cache->prison);
- cancel_delayed_work_sync(&cache->waker);
if (cache->wq)
destroy_workqueue(cache->wq);
@@ -1942,13 +1940,22 @@ static void destroy(struct cache *cache)
if (cache->policy)
dm_cache_policy_destroy(cache->policy);
+ bioset_exit(&cache->bs);
+
+ kfree(cache);
+}
+
+static void destroy(struct cache *cache)
+{
+ unsigned int i;
+
+ cancel_delayed_work_sync(&cache->waker);
+
for (i = 0; i < cache->nr_ctr_args ; i++)
kfree(cache->ctr_args[i]);
kfree(cache->ctr_args);
- bioset_exit(&cache->bs);
-
- kfree(cache);
+ __destroy(cache);
}
static void cache_dtr(struct dm_target *ti)
@@ -2003,7 +2010,6 @@ struct cache_args {
sector_t cache_sectors;
struct dm_dev *origin_dev;
- sector_t origin_sectors;
uint32_t block_size;
@@ -2084,6 +2090,7 @@ static int parse_cache_dev(struct cache_args *ca, struct dm_arg_set *as,
static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
char **error)
{
+ sector_t origin_sectors;
int r;
if (!at_least_one_arg(as, error))
@@ -2096,8 +2103,8 @@ static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
return r;
}
- ca->origin_sectors = get_dev_size(ca->origin_dev);
- if (ca->ti->len > ca->origin_sectors) {
+ origin_sectors = get_dev_size(ca->origin_dev);
+ if (ca->ti->len > origin_sectors) {
*error = "Device size larger than cached device";
return -EINVAL;
}
@@ -2257,7 +2264,7 @@ static int parse_cache_args(struct cache_args *ca, int argc, char **argv,
/*----------------------------------------------------------------*/
-static struct kmem_cache *migration_cache;
+static struct kmem_cache *migration_cache = NULL;
#define NOT_CORE_OPTION 1
@@ -2407,7 +2414,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
ca->metadata_dev = ca->origin_dev = ca->cache_dev = NULL;
- origin_blocks = cache->origin_sectors = ca->origin_sectors;
+ origin_blocks = cache->origin_sectors = ti->len;
origin_blocks = block_div(origin_blocks, ca->block_size);
cache->origin_blocks = to_oblock(origin_blocks);
@@ -2561,7 +2568,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
*result = cache;
return 0;
bad:
- destroy(cache);
+ __destroy(cache);
return r;
}
@@ -2612,7 +2619,7 @@ static int cache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
r = copy_ctr_args(cache, argc - 3, (const char **)argv + 3);
if (r) {
- destroy(cache);
+ __destroy(cache);
goto out;
}
@@ -2895,19 +2902,19 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache)
static bool can_resize(struct cache *cache, dm_cblock_t new_size)
{
if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
- if (cache->sized) {
- DMERR("%s: unable to extend cache due to missing cache table reload",
- cache_device_name(cache));
- return false;
- }
+ DMERR("%s: unable to extend cache due to missing cache table reload",
+ cache_device_name(cache));
+ return false;
}
/*
* We can't drop a dirty block when shrinking the cache.
*/
- while (from_cblock(new_size) < from_cblock(cache->cache_size)) {
- new_size = to_cblock(from_cblock(new_size) + 1);
- if (is_dirty(cache, new_size)) {
+ if (cache->loaded_mappings) {
+ new_size = to_cblock(find_next_bit(cache->dirty_bitset,
+ from_cblock(cache->cache_size),
+ from_cblock(new_size)));
+ if (new_size != cache->cache_size) {
DMERR("%s: unable to shrink cache; cache block %llu is dirty",
cache_device_name(cache),
(unsigned long long) from_cblock(new_size));
@@ -2943,20 +2950,15 @@ static int cache_preresume(struct dm_target *ti)
/*
* Check to see if the cache has resized.
*/
- if (!cache->sized) {
- r = resize_cache_dev(cache, csize);
- if (r)
- return r;
-
- cache->sized = true;
-
- } else if (csize != cache->cache_size) {
+ if (!cache->sized || csize != cache->cache_size) {
if (!can_resize(cache, csize))
return -EINVAL;
r = resize_cache_dev(cache, csize);
if (r)
return r;
+
+ cache->sized = true;
}
if (!cache->loaded_mappings) {
@@ -3444,22 +3446,36 @@ static int __init dm_cache_init(void)
int r;
migration_cache = KMEM_CACHE(dm_cache_migration, 0);
- if (!migration_cache)
- return -ENOMEM;
+ if (!migration_cache) {
+ r = -ENOMEM;
+ goto err;
+ }
+
+ btracker_work_cache = kmem_cache_create("dm_cache_bt_work",
+ sizeof(struct bt_work), __alignof__(struct bt_work), 0, NULL);
+ if (!btracker_work_cache) {
+ r = -ENOMEM;
+ goto err;
+ }
r = dm_register_target(&cache_target);
if (r) {
- kmem_cache_destroy(migration_cache);
- return r;
+ goto err;
}
return 0;
+
+err:
+ kmem_cache_destroy(migration_cache);
+ kmem_cache_destroy(btracker_work_cache);
+ return r;
}
static void __exit dm_cache_exit(void)
{
dm_unregister_target(&cache_target);
kmem_cache_destroy(migration_cache);
+ kmem_cache_destroy(btracker_work_cache);
}
module_init(dm_cache_init);
diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c
index 48587c16c445..e8a9432057dc 100644
--- a/drivers/md/dm-unstripe.c
+++ b/drivers/md/dm-unstripe.c
@@ -85,8 +85,8 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
uc->physical_start = start;
- uc->unstripe_offset = uc->unstripe * uc->chunk_size;
- uc->unstripe_width = (uc->stripes - 1) * uc->chunk_size;
+ uc->unstripe_offset = (sector_t)uc->unstripe * uc->chunk_size;
+ uc->unstripe_width = (sector_t)(uc->stripes - 1) * uc->chunk_size;
uc->chunk_shift = is_power_of_2(uc->chunk_size) ? fls(uc->chunk_size) - 1 : 0;
tmp_len = ti->len;
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 7d4d90b4395a..c142ec5458b7 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -356,9 +356,9 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
else if (verity_handle_err(v,
DM_VERITY_BLOCK_TYPE_METADATA,
hash_block)) {
- struct bio *bio =
- dm_bio_from_per_bio_data(io,
- v->ti->per_io_data_size);
+ struct bio *bio;
+ io->had_mismatch = true;
+ bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
dm_audit_log_bio(DM_MSG_PREFIX, "verify-metadata", bio,
block, 0);
r = -EIO;
@@ -482,6 +482,7 @@ static int verity_handle_data_hash_mismatch(struct dm_verity *v,
return -EIO; /* Error correction failed; Just return error */
if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, blkno)) {
+ io->had_mismatch = true;
dm_audit_log_bio(DM_MSG_PREFIX, "verify-data", bio, blkno, 0);
return -EIO;
}
@@ -606,6 +607,7 @@ static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
if (unlikely(status != BLK_STS_OK) &&
unlikely(!(bio->bi_opf & REQ_RAHEAD)) &&
+ !io->had_mismatch &&
!verity_is_system_shutting_down()) {
if (v->error_mode == DM_VERITY_MODE_PANIC) {
panic("dm-verity device has I/O error");
@@ -779,6 +781,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
io->orig_bi_end_io = bio->bi_end_io;
io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
+ io->had_mismatch = false;
bio->bi_end_io = verity_end_io;
bio->bi_private = io;
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 6b75159bf835..c996140bda94 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -92,6 +92,7 @@ struct dm_verity_io {
sector_t block;
unsigned int n_blocks;
bool in_bh;
+ bool had_mismatch;
struct work_struct work;
struct work_struct bh_work;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index ff4a6b570b76..19230404d8c2 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2290,8 +2290,10 @@ static struct mapped_device *alloc_dev(int minor)
* override accordingly.
*/
md->disk = blk_alloc_disk(NULL, md->numa_node_id);
- if (IS_ERR(md->disk))
+ if (IS_ERR(md->disk)) {
+ md->disk = NULL;
goto bad;
+ }
md->queue = md->disk->queue;
init_waitqueue_head(&md->wait);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 179ee4afe937..67108c397c5a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -546,6 +546,26 @@ static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_n
return 0;
}
+/*
+ * The only difference from bio_chain_endio() is that the current
+ * bi_status of bio does not affect the bi_status of parent.
+ */
+static void md_end_flush(struct bio *bio)
+{
+ struct bio *parent = bio->bi_private;
+
+ /*
+ * If any flush io error before the power failure,
+ * disk data may be lost.
+ */
+ if (bio->bi_status)
+ pr_err("md: %pg flush io error %d\n", bio->bi_bdev,
+ blk_status_to_errno(bio->bi_status));
+
+ bio_put(bio);
+ bio_endio(parent);
+}
+
bool md_flush_request(struct mddev *mddev, struct bio *bio)
{
struct md_rdev *rdev;
@@ -565,7 +585,9 @@ bool md_flush_request(struct mddev *mddev, struct bio *bio)
new = bio_alloc_bioset(rdev->bdev, 0,
REQ_OP_WRITE | REQ_PREFLUSH, GFP_NOIO,
&mddev->bio_set);
- bio_chain(new, bio);
+ new->bi_private = bio;
+ new->bi_end_io = md_end_flush;
+ bio_inc_remaining(bio);
submit_bio(new);
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index f3bf1116794a..862b1fb71d86 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -4061,9 +4061,12 @@ static int raid10_run(struct mddev *mddev)
}
if (!mddev_is_dm(conf->mddev)) {
- ret = raid10_set_queue_limits(mddev);
- if (ret)
+ int err = raid10_set_queue_limits(mddev);
+
+ if (err) {
+ ret = err;
goto out_free_conf;
+ }
}
/* need to check that every block has at least one working mirror */
diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
index 8526f613a40e..cfbfc4c1b2e6 100644
--- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
+++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
@@ -348,12 +348,12 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
/* Return if not a CTA-861 extension block */
if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03)
- return -1;
+ return -ENOENT;
/* search tag */
d = edid[0x02] & 0x7f;
if (d <= 4)
- return -1;
+ return -ENOENT;
i = 0x04;
end = 0x00 + d;
@@ -371,7 +371,7 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
return offset + i;
i += len + 1;
} while (i < end);
- return -1;
+ return -ENOENT;
}
static void extron_edid_crc(u8 *edid)
diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c
index ba67587bd43e..171366fe3544 100644
--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c
+++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c
@@ -685,7 +685,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4);
if (err)
return err;
- date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+ date = ((unsigned)data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
dev_info(pulse8->dev, "Firmware build date %ptT\n", &date);
dev_dbg(pulse8->dev, "Persistent config:\n");
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 642c48e8c1f5..ded11cd8dbf7 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -1795,6 +1795,9 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
unsigned p;
unsigned x;
+ if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))
+ return;
+
switch (tpg->pattern) {
case TPG_PAT_GREEN:
contrast = TPG_COLOR_100_RED;
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 29a8d876e6c2..b0523fc23506 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -1482,18 +1482,23 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
}
vb->planes[plane].dbuf_mapped = 1;
}
+ } else {
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ dma_buf_put(planes[plane].dbuf);
+ }
- /*
- * Now that everything is in order, copy relevant information
- * provided by userspace.
- */
- for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->planes[plane].bytesused = planes[plane].bytesused;
- vb->planes[plane].length = planes[plane].length;
- vb->planes[plane].m.fd = planes[plane].m.fd;
- vb->planes[plane].data_offset = planes[plane].data_offset;
- }
+ /*
+ * Now that everything is in order, copy relevant information
+ * provided by userspace.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ vb->planes[plane].bytesused = planes[plane].bytesused;
+ vb->planes[plane].length = planes[plane].length;
+ vb->planes[plane].m.fd = planes[plane].m.fd;
+ vb->planes[plane].data_offset = planes[plane].data_offset;
+ }
+ if (reacquired) {
/*
* Call driver-specific initialization on the newly acquired buffer,
* if provided.
@@ -1503,9 +1508,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
dprintk(q, 1, "buffer initialization failed\n");
goto err_put_vb2_buf;
}
- } else {
- for (plane = 0; plane < vb->num_planes; ++plane)
- dma_buf_put(planes[plane].dbuf);
}
ret = call_vb_qop(vb, buf_prepare, vb);
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 4f78f30b3646..a05aa271a1ba 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -443,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
default:
fepriv->auto_step++;
- fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
- break;
+ fepriv->auto_sub_step = 0;
+ continue;
}
if (!ready) fepriv->auto_sub_step++;
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 192a8230c4aa..29edaaff7a5c 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -366,9 +366,15 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
{
struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, exp->index);
int ret;
- ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index],
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
+ return -EINVAL;
+ }
+
+ ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, vb2,
0, exp->flags);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index b43695bc51e7..9df7c213716a 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -86,10 +86,15 @@ static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
+ unsigned int minor = iminor(inode);
+
+ if (minor >= MAX_DVB_MINORS)
+ return -ENODEV;
mutex_lock(&dvbdev_mutex);
down_read(&minor_rwsem);
- dvbdev = dvb_minors[iminor(inode)];
+
+ dvbdev = dvb_minors[minor];
if (dvbdev && dvbdev->fops) {
int err = 0;
@@ -525,7 +530,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (!dvb_minors[minor])
break;
- if (minor == MAX_DVB_MINORS) {
+#else
+ minor = nums2minor(adap->num, type, id);
+#endif
+ if (minor >= MAX_DVB_MINORS) {
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
@@ -538,9 +546,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
-#else
- minor = nums2minor(adap->num, type, id);
-#endif
+
dvbdev->minor = minor;
dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem);
diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
index 8b978a9f74a4..f5dd3a81725a 100644
--- a/drivers/media/dvb-frontends/cx24116.c
+++ b/drivers/media/dvb-frontends/cx24116.c
@@ -741,6 +741,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
{
struct cx24116_state *state = fe->demodulator_priv;
u8 snr_reading;
+ int ret;
static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
@@ -749,7 +750,11 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
dprintk("%s()\n", __func__);
- snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
+ ret = cx24116_readreg(state, CX24116_REG_QUALITY0);
+ if (ret < 0)
+ return ret;
+
+ snr_reading = ret;
if (snr_reading >= 0xa0 /* 100% */)
*snr = 0xffff;
diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
index df89c33dac23..40537c4ccb0d 100644
--- a/drivers/media/dvb-frontends/stb0899_algo.c
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
@@ -269,7 +269,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
int index = 0;
- u8 cfr[2];
+ u8 cfr[2] = {0};
u8 reg;
internal->status = NOCARRIER;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 48230d5109f0..272945a878b3 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2519,10 +2519,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
const struct adv76xx_chip_info *info = state->info;
struct v4l2_dv_timings timings;
struct stdi_readback stdi;
- u8 reg_io_0x02 = io_read(sd, 0x02);
+ int ret;
+ u8 reg_io_0x02;
u8 edid_enabled;
u8 cable_det;
-
static const char * const csc_coeff_sel_rb[16] = {
"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
@@ -2621,13 +2621,21 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "-----Color space-----\n");
v4l2_info(sd, "RGB quantization range ctrl: %s\n",
rgb_quantization_range_txt[state->rgb_quantization_range]);
- v4l2_info(sd, "Input color space: %s\n",
- input_color_space_txt[reg_io_0x02 >> 4]);
- v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
- (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
- (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
- "(16-235)" : "(0-255)",
- (reg_io_0x02 & 0x08) ? "enabled" : "disabled");
+
+ ret = io_read(sd, 0x02);
+ if (ret < 0) {
+ v4l2_info(sd, "Can't read Input/Output color space\n");
+ } else {
+ reg_io_0x02 = ret;
+
+ v4l2_info(sd, "Input color space: %s\n",
+ input_color_space_txt[reg_io_0x02 >> 4]);
+ v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
+ (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
+ (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
+ "(16-235)" : "(0-255)",
+ (reg_io_0x02 & 0x08) ? "enabled" : "disabled");
+ }
v4l2_info(sd, "Color space conversion: %s\n",
csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]);
diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c
index fc27238dd4d3..24873149096c 100644
--- a/drivers/media/i2c/ar0521.c
+++ b/drivers/media/i2c/ar0521.c
@@ -255,10 +255,10 @@ static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult
continue; /* Minimum value */
if (new_mult > 254)
break; /* Maximum, larger pre won't work either */
- if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN *
+ if (sensor->extclk_freq * (u64)new_mult < (u64)AR0521_PLL_MIN *
new_pre)
continue;
- if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX *
+ if (sensor->extclk_freq * (u64)new_mult > (u64)AR0521_PLL_MAX *
new_pre)
break; /* Larger pre won't work either */
new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult,
diff --git a/drivers/media/pci/mgb4/mgb4_cmt.c b/drivers/media/pci/mgb4/mgb4_cmt.c
index 70dc78ef193c..a25b68403bc6 100644
--- a/drivers/media/pci/mgb4/mgb4_cmt.c
+++ b/drivers/media/pci/mgb4/mgb4_cmt.c
@@ -227,6 +227,8 @@ void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev,
u32 config;
size_t i;
+ freq_range = array_index_nospec(freq_range, ARRAY_SIZE(cmt_vals_in));
+
addr = cmt_addrs_in[vindev->config->id];
reg_set = cmt_vals_in[freq_range];
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
index d2c4a0178b3c..1db4609b3557 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
@@ -775,11 +775,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
jpeg_buffer.curr = 0;
- word = 0;
-
if (get_word_be(&jpeg_buffer, &word))
return;
- jpeg_buffer.size = (long)word - 2;
+
+ if (word < 2)
+ jpeg_buffer.size = 0;
+ else
+ jpeg_buffer.size = (long)word - 2;
+
jpeg_buffer.data += 2;
jpeg_buffer.curr = 0;
@@ -1058,6 +1061,7 @@ static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
if (byte == -1)
return -1;
*word = (unsigned int)byte | temp;
+
return 0;
}
@@ -1145,7 +1149,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
sof = jpeg_buffer.curr; /* after 0xffc0 */
sof_len = length;
@@ -1176,7 +1180,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
if (n_dqt >= S5P_JPEG_MAX_MARKER)
return false;
@@ -1189,7 +1193,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
if (n_dht >= S5P_JPEG_MAX_MARKER)
return false;
@@ -1214,6 +1218,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
+ /* No need to check underflows as skip() does it */
skip(&jpeg_buffer, length);
break;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index 00e0d08af357..4f330f4fc6be 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -910,7 +910,7 @@ static int vivid_create_queue(struct vivid_dev *dev,
* videobuf2-core.c to MAX_BUFFER_INDEX.
*/
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- q->max_num_buffers = 64;
+ q->max_num_buffers = MAX_VID_CAP_BUFFERS;
if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE)
q->max_num_buffers = 1024;
if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE)
diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h
index cc18a3bc6dc0..d2d52763b119 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -26,6 +26,8 @@
#define MAX_INPUTS 16
/* The maximum number of outputs */
#define MAX_OUTPUTS 16
+/* The maximum number of video capture buffers */
+#define MAX_VID_CAP_BUFFERS 64
/* The maximum up or down scaling factor is 4 */
#define MAX_ZOOM 4
/* The maximum image width/height are set to 4K DMT */
@@ -481,7 +483,7 @@ struct vivid_dev {
/* video capture */
struct tpg_data tpg;
unsigned ms_vid_cap;
- bool must_blank[VIDEO_MAX_FRAME];
+ bool must_blank[MAX_VID_CAP_BUFFERS];
const struct vivid_fmt *fmt_cap;
struct v4l2_fract timeperframe_vid_cap;
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index 8bb38bc7b8cc..2b5c8fbcd0a2 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -553,7 +553,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case VIVID_CID_PERCENTAGE_FILL:
tpg_s_perc_fill(&dev->tpg, ctrl->val);
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = ctrl->val < 100;
break;
case VIVID_CID_INSERT_SAV:
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 69620e0a35a0..6a790ac8cbe6 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -213,7 +213,7 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
if (dev->start_streaming_error) {
dev->start_streaming_error = false;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index e5a364efd5e6..95a2202879d8 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -753,9 +753,10 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
for (i = 0; i < master->ncontrols; i++)
cur_to_new(master->cluster[i]);
ret = call_op(master, g_volatile_ctrl);
- new_to_user(c, ctrl);
+ if (!ret)
+ ret = new_to_user(c, ctrl);
} else {
- cur_to_user(c, ctrl);
+ ret = cur_to_user(c, ctrl);
}
v4l2_ctrl_unlock(master);
return ret;
@@ -770,7 +771,10 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
if (!ctrl || !ctrl->is_int)
return -EINVAL;
ret = get_ctrl(ctrl, &c);
- control->value = c.value;
+
+ if (!ret)
+ control->value = c.value;
+
return ret;
}
EXPORT_SYMBOL(v4l2_g_ctrl);
@@ -811,10 +815,11 @@ static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
int ret;
v4l2_ctrl_lock(ctrl);
- user_to_new(c, ctrl);
- ret = set_ctrl(fh, ctrl, 0);
+ ret = user_to_new(c, ctrl);
+ if (!ret)
+ ret = set_ctrl(fh, ctrl, 0);
if (!ret)
- cur_to_user(c, ctrl);
+ ret = cur_to_user(c, ctrl);
v4l2_ctrl_unlock(ctrl);
return ret;
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 9d090fa07516..be011cef12e5 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -321,7 +321,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
return;
list_del(&cb->list);
- kfree(cb->buf.data);
+ kvfree(cb->buf.data);
kfree(cb->ext_hdr);
kfree(cb);
}
@@ -497,7 +497,7 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
if (length == 0)
return cb;
- cb->buf.data = kmalloc(roundup(length, MEI_SLOT_SIZE), GFP_KERNEL);
+ cb->buf.data = kvmalloc(roundup(length, MEI_SLOT_SIZE), GFP_KERNEL);
if (!cb->buf.data) {
mei_io_cb_free(cb);
return NULL;
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 0f81586a19df..68ce4920e01e 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -892,28 +892,40 @@ static void gl9767_disable_ssc_pll(struct pci_dev *pdev)
gl9767_vhs_read(pdev);
}
+static void gl9767_set_low_power_negotiation(struct pci_dev *pdev, bool enable)
+{
+ u32 value;
+
+ gl9767_vhs_write(pdev);
+
+ pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
+ if (enable)
+ value &= ~PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+ else
+ value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
+
+ gl9767_vhs_read(pdev);
+}
+
static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct mmc_ios *ios = &host->mmc->ios;
struct pci_dev *pdev;
- u32 value;
u16 clk;
pdev = slot->chip->pdev;
host->mmc->actual_clock = 0;
- gl9767_vhs_write(pdev);
-
- pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
- value |= PCIE_GLI_9767_CFG_LOW_PWR_OFF;
- pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
-
+ gl9767_set_low_power_negotiation(pdev, false);
gl9767_disable_ssc_pll(pdev);
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
- if (clock == 0)
+ if (clock == 0) {
+ gl9767_set_low_power_negotiation(pdev, true);
return;
+ }
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) {
@@ -922,12 +934,7 @@ static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock)
}
sdhci_enable_clk(host, clk);
-
- pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
- value &= ~PCIE_GLI_9767_CFG_LOW_PWR_OFF;
- pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
-
- gl9767_vhs_read(pdev);
+ gl9767_set_low_power_negotiation(pdev, true);
}
static void gli_set_9767(struct sdhci_host *host)
@@ -1061,6 +1068,9 @@ static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_writew(host, value, SDHCI_CLOCK_CONTROL);
}
+ pci_read_config_dword(pdev, PCIE_GLI_9767_CFG, &value);
+ value &= ~PCIE_GLI_9767_CFG_LOW_PWR_OFF;
+ pci_write_config_dword(pdev, PCIE_GLI_9767_CFG, value);
gl9767_vhs_read(pdev);
return 0;
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 0433a0f36d1b..98c6205ed19f 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -3206,15 +3206,11 @@ static int amt_newlink(struct net *net, struct net_device *dev,
goto err;
}
- if (data[IFLA_AMT_RELAY_PORT])
- amt->relay_port = nla_get_be16(data[IFLA_AMT_RELAY_PORT]);
- else
- amt->relay_port = htons(IANA_AMT_UDP_PORT);
+ amt->relay_port = nla_get_be16_default(data[IFLA_AMT_RELAY_PORT],
+ htons(IANA_AMT_UDP_PORT));
- if (data[IFLA_AMT_GATEWAY_PORT])
- amt->gw_port = nla_get_be16(data[IFLA_AMT_GATEWAY_PORT]);
- else
- amt->gw_port = htons(IANA_AMT_UDP_PORT);
+ amt->gw_port = nla_get_be16_default(data[IFLA_AMT_GATEWAY_PORT],
+ htons(IANA_AMT_UDP_PORT));
if (!amt->relay_port) {
NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP],
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5812e8eaccf1..49dd4fe195e5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1008,6 +1008,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_UP)
bond_hw_addr_flush(bond->dev, old_active->dev);
+
+ bond_slave_ns_maddrs_add(bond, old_active);
}
if (new_active) {
@@ -1024,6 +1026,8 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
dev_mc_sync(new_active->dev, bond->dev);
netif_addr_unlock_bh(bond->dev);
}
+
+ bond_slave_ns_maddrs_del(bond, new_active);
}
}
@@ -1545,6 +1549,7 @@ static void bond_compute_features(struct bonding *bond)
{
unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
IFF_XMIT_DST_RELEASE_PERM;
+ netdev_features_t gso_partial_features = NETIF_F_GSO_ESP;
netdev_features_t vlan_features = BOND_VLAN_FEATURES;
netdev_features_t enc_features = BOND_ENC_FEATURES;
#ifdef CONFIG_XFRM_OFFLOAD
@@ -1577,6 +1582,9 @@ static void bond_compute_features(struct bonding *bond)
BOND_XFRM_FEATURES);
#endif /* CONFIG_XFRM_OFFLOAD */
+ if (slave->dev->hw_enc_features & NETIF_F_GSO_PARTIAL)
+ gso_partial_features &= slave->dev->gso_partial_features;
+
mpls_features = netdev_increment_features(mpls_features,
slave->dev->mpls_features,
BOND_MPLS_FEATURES);
@@ -1590,6 +1598,11 @@ static void bond_compute_features(struct bonding *bond)
}
bond_dev->hard_header_len = max_hard_header_len;
+ if (gso_partial_features & NETIF_F_GSO_ESP)
+ bond_dev->gso_partial_features |= NETIF_F_GSO_ESP;
+ else
+ bond_dev->gso_partial_features &= ~NETIF_F_GSO_ESP;
+
done:
bond_dev->vlan_features = vlan_features;
bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
@@ -2341,6 +2354,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
bond_compute_features(bond);
bond_set_carrier(bond);
+ /* Needs to be called before bond_select_active_slave(), which will
+ * remove the maddrs if the slave is selected as active slave.
+ */
+ bond_slave_ns_maddrs_add(bond, new_slave);
+
if (bond_uses_primary(bond)) {
block_netpoll_tx();
bond_select_active_slave(bond);
@@ -2350,7 +2368,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
if (bond_mode_can_use_xmit_hash(bond))
bond_update_slave_arr(bond, NULL);
-
if (!slave_dev->netdev_ops->ndo_bpf ||
!slave_dev->netdev_ops->ndo_xdp_xmit) {
if (bond->xdp_prog) {
@@ -2548,6 +2565,12 @@ static int __bond_release_one(struct net_device *bond_dev,
if (oldcurrent == slave)
bond_change_active_slave(bond, NULL);
+ /* Must be called after bond_change_active_slave () as the slave
+ * might change from an active slave to a backup slave. Then it is
+ * necessary to clear the maddrs on the backup slave.
+ */
+ bond_slave_ns_maddrs_del(bond, slave);
+
if (bond_is_lb(bond)) {
/* Must be called only after the slave has been
* detached from the list and the curr_active_slave
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 95d59a18c022..327b6ecdc77e 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -15,6 +15,7 @@
#include <linux/sched/signal.h>
#include <net/bonding.h>
+#include <net/ndisc.h>
static int bond_option_active_slave_set(struct bonding *bond,
const struct bond_opt_value *newval);
@@ -1234,6 +1235,68 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
}
#if IS_ENABLED(CONFIG_IPV6)
+static bool slave_can_set_ns_maddr(const struct bonding *bond, struct slave *slave)
+{
+ return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
+ !bond_is_active_slave(slave) &&
+ slave->dev->flags & IFF_MULTICAST;
+}
+
+static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add)
+{
+ struct in6_addr *targets = bond->params.ns_targets;
+ char slot_maddr[MAX_ADDR_LEN];
+ int i;
+
+ if (!slave_can_set_ns_maddr(bond, slave))
+ return;
+
+ for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
+ if (ipv6_addr_any(&targets[i]))
+ break;
+
+ if (!ndisc_mc_map(&targets[i], slot_maddr, slave->dev, 0)) {
+ if (add)
+ dev_mc_add(slave->dev, slot_maddr);
+ else
+ dev_mc_del(slave->dev, slot_maddr);
+ }
+ }
+}
+
+void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave)
+{
+ if (!bond->params.arp_validate)
+ return;
+ slave_set_ns_maddrs(bond, slave, true);
+}
+
+void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave)
+{
+ if (!bond->params.arp_validate)
+ return;
+ slave_set_ns_maddrs(bond, slave, false);
+}
+
+static void slave_set_ns_maddr(struct bonding *bond, struct slave *slave,
+ struct in6_addr *target, struct in6_addr *slot)
+{
+ char target_maddr[MAX_ADDR_LEN], slot_maddr[MAX_ADDR_LEN];
+
+ if (!bond->params.arp_validate || !slave_can_set_ns_maddr(bond, slave))
+ return;
+
+ /* remove the previous maddr from slave */
+ if (!ipv6_addr_any(slot) &&
+ !ndisc_mc_map(slot, slot_maddr, slave->dev, 0))
+ dev_mc_del(slave->dev, slot_maddr);
+
+ /* add new maddr on slave if target is set */
+ if (!ipv6_addr_any(target) &&
+ !ndisc_mc_map(target, target_maddr, slave->dev, 0))
+ dev_mc_add(slave->dev, target_maddr);
+}
+
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
struct in6_addr *target,
unsigned long last_rx)
@@ -1243,8 +1306,10 @@ static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
struct slave *slave;
if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
- bond_for_each_slave(bond, slave, iter)
+ bond_for_each_slave(bond, slave, iter) {
slave->target_last_arp_rx[slot] = last_rx;
+ slave_set_ns_maddr(bond, slave, target, &targets[slot]);
+ }
targets[slot] = *target;
}
}
@@ -1296,15 +1361,30 @@ static int bond_option_ns_ip6_targets_set(struct bonding *bond,
{
return -EPERM;
}
+
+static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add) {}
+
+void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave) {}
+
+void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave) {}
#endif
static int bond_option_arp_validate_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
+ bool changed = !!bond->params.arp_validate != !!newval->value;
+ struct list_head *iter;
+ struct slave *slave;
+
netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
newval->string, newval->value);
bond->params.arp_validate = newval->value;
+ if (changed) {
+ bond_for_each_slave(bond, slave, iter)
+ slave_set_ns_maddrs(bond, slave, !!bond->params.arp_validate);
+ }
+
return 0;
}
diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
index c63f7fc1e691..511615dc3341 100644
--- a/drivers/net/can/c_can/c_can_main.c
+++ b/drivers/net/can/c_can/c_can_main.c
@@ -1011,7 +1011,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
/* common for all type of bus errors */
priv->can.can_stats.bus_error++;
- stats->rx_errors++;
/* propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(dev, &cf);
@@ -1027,26 +1026,32 @@ static int c_can_handle_bus_err(struct net_device *dev,
case LEC_STUFF_ERROR:
netdev_dbg(dev, "stuff error\n");
cf->data[2] |= CAN_ERR_PROT_STUFF;
+ stats->rx_errors++;
break;
case LEC_FORM_ERROR:
netdev_dbg(dev, "form error\n");
cf->data[2] |= CAN_ERR_PROT_FORM;
+ stats->rx_errors++;
break;
case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n");
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
+ stats->tx_errors++;
break;
case LEC_BIT1_ERROR:
netdev_dbg(dev, "bit1 error\n");
cf->data[2] |= CAN_ERR_PROT_BIT1;
+ stats->tx_errors++;
break;
case LEC_BIT0_ERROR:
netdev_dbg(dev, "bit0 error\n");
cf->data[2] |= CAN_ERR_PROT_BIT0;
+ stats->tx_errors++;
break;
case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n");
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+ stats->rx_errors++;
break;
default:
break;
diff --git a/drivers/net/can/cc770/Kconfig b/drivers/net/can/cc770/Kconfig
index 467ef19de1c1..aae25c2f849e 100644
--- a/drivers/net/can/cc770/Kconfig
+++ b/drivers/net/can/cc770/Kconfig
@@ -7,7 +7,7 @@ if CAN_CC770
config CAN_CC770_ISA
tristate "ISA Bus based legacy CC770 driver"
- depends on ISA
+ depends on HAS_IOPORT
help
This driver adds legacy support for CC770 and AN82527 chips
connected to the ISA bus using I/O port, memory mapped or
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index a978b960f1f1..16e9e7d7527d 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1765,7 +1765,8 @@ static int m_can_close(struct net_device *dev)
netif_stop_queue(dev);
m_can_stop(dev);
- free_irq(dev->irq, dev);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
m_can_clean(dev);
diff --git a/drivers/net/can/rockchip/Kconfig b/drivers/net/can/rockchip/Kconfig
index e029e2a3ca4b..d203c530551f 100644
--- a/drivers/net/can/rockchip/Kconfig
+++ b/drivers/net/can/rockchip/Kconfig
@@ -2,7 +2,8 @@
config CAN_ROCKCHIP_CANFD
tristate "Rockchip CAN-FD controller"
- depends on OF || COMPILE_TEST
+ depends on OF
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
select CAN_RX_OFFLOAD
help
Say Y here if you want to use CAN-FD controller found on
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index 01168db4c106..2f516cc6d22c 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -87,7 +87,7 @@ config CAN_PLX_PCI
config CAN_SJA1000_ISA
tristate "ISA Bus based legacy SJA1000 driver"
- depends on ISA
+ depends on HAS_IOPORT
help
This driver adds legacy support for SJA1000 chips connected to
the ISA bus using I/O port, memory mapped or indirect access.
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
index e684991fa391..7209a831f0f2 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
@@ -2,7 +2,7 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
-// Copyright (c) 2019, 2020, 2021 Pengutronix,
+// Copyright (c) 2019, 2020, 2021, 2024 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
@@ -483,9 +483,11 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
};
const struct ethtool_coalesce ec = {
.rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq,
- .rx_max_coalesced_frames_irq = priv->rx_obj_num_coalesce_irq,
+ .rx_max_coalesced_frames_irq = priv->rx_obj_num_coalesce_irq == 0 ?
+ 1 : priv->rx_obj_num_coalesce_irq,
.tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq,
- .tx_max_coalesced_frames_irq = priv->tx_obj_num_coalesce_irq,
+ .tx_max_coalesced_frames_irq = priv->tx_obj_num_coalesce_irq == 0 ?
+ 1 : priv->tx_obj_num_coalesce_irq,
};
struct can_ram_layout layout;
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
index f732556d233a..d3ac865933fd 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
@@ -16,9 +16,9 @@
#include "mcp251xfd.h"
-static inline bool mcp251xfd_tx_fifo_sta_full(u32 fifo_sta)
+static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta)
{
- return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
+ return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
}
static inline int
@@ -122,7 +122,11 @@ mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)
if (err)
return err;
- if (mcp251xfd_tx_fifo_sta_full(fifo_sta)) {
+ /* If the chip says the TX-FIFO is empty, but there are no TX
+ * buffers free in the ring, we assume all have been sent.
+ */
+ if (mcp251xfd_tx_fifo_sta_empty(fifo_sta) &&
+ mcp251xfd_get_tx_free(tx_ring) == 0) {
*len_p = tx_ring->obj_num;
return 0;
}
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
index 9e1b7d41005f..da7c72105fb6 100644
--- a/drivers/net/can/vxcan.c
+++ b/drivers/net/can/vxcan.c
@@ -188,14 +188,10 @@ static int vxcan_newlink(struct net *net, struct net_device *dev,
/* register peer device */
if (data && data[VXCAN_INFO_PEER]) {
- struct nlattr *nla_peer;
+ struct nlattr *nla_peer = data[VXCAN_INFO_PEER];
- nla_peer = data[VXCAN_INFO_PEER];
ifmp = nla_data(nla_peer);
- err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
- if (err < 0)
- return err;
-
+ rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
tbp = peer_tb;
}
@@ -208,9 +204,6 @@ static int vxcan_newlink(struct net *net, struct net_device *dev,
}
peer_net = rtnl_link_get_net(net, tbp);
- if (IS_ERR(peer_net))
- return PTR_ERR(peer_net);
-
peer = rtnl_create_link(peer_net, ifname, name_assign_type,
&vxcan_link_ops, tbp, extack);
if (IS_ERR(peer)) {
@@ -302,6 +295,7 @@ static struct rtnl_link_ops vxcan_link_ops = {
.newlink = vxcan_newlink,
.dellink = vxcan_dellink,
.policy = vxcan_policy,
+ .peer_type = VXCAN_INFO_PEER,
.maxtype = VXCAN_INFO_MAX,
.get_link_net = vxcan_get_link_net,
};
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index c39cb119e760..285785c942b0 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -989,8 +989,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
if (stringset == ETH_SS_STATS) {
for (i = 0; i < mib_size; i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- mibs[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, mibs[i].name);
} else if (stringset == ETH_SS_PHY_STATS) {
phydev = b53_get_phy_device(ds, port);
if (!phydev)
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 9201f07839ad..43bde1f583ff 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1183,8 +1183,8 @@ static void bcm_sf2_sw_get_strings(struct dsa_switch *ds, int port,
int cnt = b53_get_sset_count(ds, port, stringset);
b53_get_strings(ds, port, stringset, data);
- bcm_sf2_cfp_get_strings(ds, port, stringset,
- data + cnt * ETH_GSTRING_LEN);
+ data += cnt * ETH_GSTRING_LEN;
+ bcm_sf2_cfp_get_strings(ds, port, stringset, &data);
}
static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 4fda075a3449..be9f3b29019f 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -228,8 +228,8 @@ int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
int bcm_sf2_cfp_rst(struct bcm_sf2_priv *priv);
void bcm_sf2_cfp_exit(struct dsa_switch *ds);
int bcm_sf2_cfp_resume(struct dsa_switch *ds);
-void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port,
- u32 stringset, uint8_t *data);
+void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t **data);
void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *data);
int bcm_sf2_cfp_get_sset_count(struct dsa_switch *ds, int port, int sset);
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index c88ee3dd4299..e22362e6f0cd 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -1279,27 +1279,19 @@ static const struct bcm_sf2_cfp_stat {
},
};
-void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port,
- u32 stringset, uint8_t *data)
+void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ uint8_t **data)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
- unsigned int s = ARRAY_SIZE(bcm_sf2_cfp_stats);
- char buf[ETH_GSTRING_LEN];
- unsigned int i, j, iter;
+ unsigned int i, j;
if (stringset != ETH_SS_STATS)
return;
- for (i = 1; i < priv->num_cfp_rules; i++) {
- for (j = 0; j < s; j++) {
- snprintf(buf, sizeof(buf),
- "CFP%03d_%sCntr",
- i, bcm_sf2_cfp_stats[j].name);
- iter = (i - 1) * s + j;
- strscpy(data + iter * ETH_GSTRING_LEN,
- buf, ETH_GSTRING_LEN);
- }
- }
+ for (i = 1; i < priv->num_cfp_rules; i++)
+ for (j = 0; j < ARRAY_SIZE(bcm_sf2_cfp_stats); j++)
+ ethtool_sprintf(data, "CFP%03d_%sCntr", i,
+ bcm_sf2_cfp_stats[j].name);
}
void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index c70ed67cc188..adbab544c60f 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -121,8 +121,7 @@ static void dsa_loop_get_strings(struct dsa_switch *ds, int port,
return;
for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
- memcpy(data + i * ETH_GSTRING_LEN,
- ps->ports[port].mib[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, ps->ports[port].mib[i].name);
}
static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index d798f17cf7ea..283ec5a6e23c 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -294,12 +294,8 @@ static void hellcreek_get_strings(struct dsa_switch *ds, int port,
{
int i;
- for (i = 0; i < ARRAY_SIZE(hellcreek_counter); ++i) {
- const struct hellcreek_counter *counter = &hellcreek_counter[i];
-
- strscpy(data + i * ETH_GSTRING_LEN,
- counter->name, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(hellcreek_counter); ++i)
+ ethtool_puts(&data, hellcreek_counter[i].name);
}
static int hellcreek_get_sset_count(struct dsa_switch *ds, int port, int sset)
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index 0ba658a72d8f..d16817e0476f 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -1131,6 +1131,10 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds)
if (i == dev->cpu_port)
continue;
ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+
+ /* Power down the internal PHY if port is unused. */
+ if (dsa_is_unused_port(ds, i) && dev->info->internal_phy[i])
+ ksz_pwrite16(dev, i, 0x100, BMCR_PDOWN);
}
}
diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
index 7d7560f23a73..1c6d7fc16772 100644
--- a/drivers/net/dsa/microchip/ksz9477_i2c.c
+++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
@@ -2,7 +2,7 @@
/*
* Microchip KSZ9477 series register access through I2C
*
- * Copyright (C) 2018-2019 Microchip Technology Inc.
+ * Copyright (C) 2018-2024 Microchip Technology Inc.
*/
#include <linux/i2c.h>
@@ -16,6 +16,8 @@ KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0);
static int ksz9477_i2c_probe(struct i2c_client *i2c)
{
+ const struct ksz_chip_data *chip;
+ struct device *ddev = &i2c->dev;
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;
@@ -24,6 +26,12 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c)
if (!dev)
return -ENOMEM;
+ chip = device_get_match_data(ddev);
+ if (!chip)
+ return -EINVAL;
+
+ /* Save chip id to do special initialization when probing. */
+ dev->chip_id = chip->chip_id;
for (i = 0; i < __KSZ_NUM_REGMAPS; i++) {
rc = ksz9477_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
@@ -111,6 +119,10 @@ static const struct of_device_id ksz9477_dt_ids[] = {
.compatible = "microchip,ksz9567",
.data = &ksz_switch_chips[KSZ9567]
},
+ {
+ .compatible = "microchip,lan9646",
+ .data = &ksz_switch_chips[LAN9646]
+ },
{},
};
MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 5290f5ad98f3..920443ee8ffd 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -411,6 +411,8 @@ static const struct ksz_dev_ops lan937x_dev_ops = {
.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
.port_setup = lan937x_port_setup,
.set_ageing_time = lan937x_set_ageing_time,
+ .mdio_bus_preinit = lan937x_mdio_bus_preinit,
+ .create_phy_addr_map = lan937x_create_phy_addr_map,
.r_phy = lan937x_r_phy,
.w_phy = lan937x_w_phy,
.r_mib_cnt = ksz9477_r_mib_cnt,
@@ -1762,6 +1764,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_tx_queues = 8,
.num_ipms = 8,
.tc_cbs_supported = true,
+ .phy_side_mdio_supported = true,
.ops = &lan937x_dev_ops,
.phylink_mac_ops = &lan937x_phylink_mac_ops,
.mib_names = ksz9477_mib_names,
@@ -1790,6 +1793,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_tx_queues = 8,
.num_ipms = 8,
.tc_cbs_supported = true,
+ .phy_side_mdio_supported = true,
.ops = &lan937x_dev_ops,
.phylink_mac_ops = &lan937x_phylink_mac_ops,
.mib_names = ksz9477_mib_names,
@@ -1818,6 +1822,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_tx_queues = 8,
.num_ipms = 8,
.tc_cbs_supported = true,
+ .phy_side_mdio_supported = true,
.ops = &lan937x_dev_ops,
.phylink_mac_ops = &lan937x_phylink_mac_ops,
.mib_names = ksz9477_mib_names,
@@ -1850,6 +1855,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_tx_queues = 8,
.num_ipms = 8,
.tc_cbs_supported = true,
+ .phy_side_mdio_supported = true,
.ops = &lan937x_dev_ops,
.phylink_mac_ops = &lan937x_phylink_mac_ops,
.mib_names = ksz9477_mib_names,
@@ -1882,6 +1888,7 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.num_tx_queues = 8,
.num_ipms = 8,
.tc_cbs_supported = true,
+ .phy_side_mdio_supported = true,
.ops = &lan937x_dev_ops,
.phylink_mac_ops = &lan937x_phylink_mac_ops,
.mib_names = ksz9477_mib_names,
@@ -1901,6 +1908,41 @@ const struct ksz_chip_data ksz_switch_chips[] = {
.internal_phy = {true, true, true, true,
false, false, true, true},
},
+
+ [LAN9646] = {
+ .chip_id = LAN9646_CHIP_ID,
+ .dev_name = "LAN9646",
+ .num_vlans = 4096,
+ .num_alus = 4096,
+ .num_statics = 16,
+ .cpu_ports = 0x7F, /* can be configured as cpu port */
+ .port_cnt = 7, /* total physical port count */
+ .port_nirqs = 4,
+ .num_tx_queues = 4,
+ .num_ipms = 8,
+ .ops = &ksz9477_dev_ops,
+ .phylink_mac_ops = &ksz9477_phylink_mac_ops,
+ .phy_errata_9477 = true,
+ .mib_names = ksz9477_mib_names,
+ .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
+ .reg_mib_cnt = MIB_COUNTER_NUM,
+ .regs = ksz9477_regs,
+ .masks = ksz9477_masks,
+ .shifts = ksz9477_shifts,
+ .xmii_ctrl0 = ksz9477_xmii_ctrl0,
+ .xmii_ctrl1 = ksz9477_xmii_ctrl1,
+ .supports_mii = {false, false, false, false,
+ false, true, true},
+ .supports_rmii = {false, false, false, false,
+ false, true, true},
+ .supports_rgmii = {false, false, false, false,
+ false, true, true},
+ .internal_phy = {true, true, true, true,
+ true, false, false},
+ .gbit_capable = {true, true, true, true, true, true, true},
+ .wr_table = &ksz9477_register_set,
+ .rd_table = &ksz9477_register_set,
+ },
};
EXPORT_SYMBOL_GPL(ksz_switch_chips);
@@ -2112,10 +2154,8 @@ static void ksz_get_strings(struct dsa_switch *ds, int port,
if (stringset != ETH_SS_STATS)
return;
- for (i = 0; i < dev->info->mib_cnt; i++) {
- memcpy(buf + i * ETH_GSTRING_LEN,
- dev->info->mib_names[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < dev->info->mib_cnt; i++)
+ ethtool_puts(&buf, dev->info->mib_names[i].string);
}
/**
@@ -2238,16 +2278,100 @@ static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
return dev->dev_ops->w_phy(dev, addr, regnum, val);
}
+/**
+ * ksz_parent_mdio_read - Read data from a PHY register on the parent MDIO bus.
+ * @bus: MDIO bus structure.
+ * @addr: PHY address on the parent MDIO bus.
+ * @regnum: Register number to read.
+ *
+ * This function provides a direct read operation on the parent MDIO bus for
+ * accessing PHY registers. By bypassing SPI or I2C, it uses the parent MDIO bus
+ * to retrieve data from the PHY registers at the specified address and register
+ * number.
+ *
+ * Return: Value of the PHY register, or a negative error code on failure.
+ */
+static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+ struct ksz_device *dev = bus->priv;
+
+ return mdiobus_read_nested(dev->parent_mdio_bus, addr, regnum);
+}
+
+/**
+ * ksz_parent_mdio_write - Write data to a PHY register on the parent MDIO bus.
+ * @bus: MDIO bus structure.
+ * @addr: PHY address on the parent MDIO bus.
+ * @regnum: Register number to write to.
+ * @val: Value to write to the PHY register.
+ *
+ * This function provides a direct write operation on the parent MDIO bus for
+ * accessing PHY registers. Bypassing SPI or I2C, it uses the parent MDIO bus
+ * to modify the PHY register values at the specified address.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum,
+ u16 val)
+{
+ struct ksz_device *dev = bus->priv;
+
+ return mdiobus_write_nested(dev->parent_mdio_bus, addr, regnum, val);
+}
+
+/**
+ * ksz_phy_addr_to_port - Map a PHY address to the corresponding switch port.
+ * @dev: Pointer to device structure.
+ * @addr: PHY address to map to a port.
+ *
+ * This function finds the corresponding switch port for a given PHY address by
+ * iterating over all user ports on the device. It checks if a port's PHY
+ * address in `phy_addr_map` matches the specified address and if the port
+ * contains an internal PHY. If a match is found, the index of the port is
+ * returned.
+ *
+ * Return: Port index on success, or -EINVAL if no matching port is found.
+ */
+static int ksz_phy_addr_to_port(struct ksz_device *dev, int addr)
+{
+ struct dsa_switch *ds = dev->ds;
+ struct dsa_port *dp;
+
+ dsa_switch_for_each_user_port(dp, ds) {
+ if (dev->info->internal_phy[dp->index] &&
+ dev->phy_addr_map[dp->index] == addr)
+ return dp->index;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * ksz_irq_phy_setup - Configure IRQs for PHYs in the KSZ device.
+ * @dev: Pointer to the KSZ device structure.
+ *
+ * Sets up IRQs for each active PHY connected to the KSZ switch by mapping the
+ * appropriate IRQs for each PHY and assigning them to the `user_mii_bus` in
+ * the DSA switch structure. Each IRQ is mapped based on the port's IRQ domain.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
static int ksz_irq_phy_setup(struct ksz_device *dev)
{
struct dsa_switch *ds = dev->ds;
- int phy;
+ int phy, port;
int irq;
int ret;
- for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) {
+ for (phy = 0; phy < PHY_MAX_ADDR; phy++) {
if (BIT(phy) & ds->phys_mii_mask) {
- irq = irq_find_mapping(dev->ports[phy].pirq.domain,
+ port = ksz_phy_addr_to_port(dev, phy);
+ if (port < 0) {
+ ret = port;
+ goto out;
+ }
+
+ irq = irq_find_mapping(dev->ports[port].pirq.domain,
PORT_SRC_PHY_INT);
if (irq < 0) {
ret = irq;
@@ -2265,49 +2389,183 @@ out:
return ret;
}
+/**
+ * ksz_irq_phy_free - Release IRQ mappings for PHYs in the KSZ device.
+ * @dev: Pointer to the KSZ device structure.
+ *
+ * Releases any IRQ mappings previously assigned to active PHYs in the KSZ
+ * switch by disposing of each mapped IRQ in the `user_mii_bus` structure.
+ */
static void ksz_irq_phy_free(struct ksz_device *dev)
{
struct dsa_switch *ds = dev->ds;
int phy;
- for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++)
+ for (phy = 0; phy < PHY_MAX_ADDR; phy++)
if (BIT(phy) & ds->phys_mii_mask)
irq_dispose_mapping(ds->user_mii_bus->irq[phy]);
}
+/**
+ * ksz_parse_dt_phy_config - Parse and validate PHY configuration from DT
+ * @dev: pointer to the KSZ device structure
+ * @bus: pointer to the MII bus structure
+ * @mdio_np: pointer to the MDIO node in the device tree
+ *
+ * This function parses and validates PHY configurations for each user port
+ * defined in the device tree for a KSZ switch device. It verifies that the
+ * `phy-handle` properties are correctly set and that the internal PHYs match
+ * expected addresses and parent nodes. Sets up the PHY mask in the MII bus if
+ * all validations pass. Logs error messages for any mismatches or missing data.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus,
+ struct device_node *mdio_np)
+{
+ struct device_node *phy_node, *phy_parent_node;
+ bool phys_are_valid = true;
+ struct dsa_port *dp;
+ u32 phy_addr;
+ int ret;
+
+ dsa_switch_for_each_user_port(dp, dev->ds) {
+ if (!dev->info->internal_phy[dp->index])
+ continue;
+
+ phy_node = of_parse_phandle(dp->dn, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev->dev, "failed to parse phy-handle for port %d.\n",
+ dp->index);
+ phys_are_valid = false;
+ continue;
+ }
+
+ phy_parent_node = of_get_parent(phy_node);
+ if (!phy_parent_node) {
+ dev_err(dev->dev, "failed to get PHY-parent node for port %d\n",
+ dp->index);
+ phys_are_valid = false;
+ } else if (phy_parent_node != mdio_np) {
+ dev_err(dev->dev, "PHY-parent node mismatch for port %d, expected %pOF, got %pOF\n",
+ dp->index, mdio_np, phy_parent_node);
+ phys_are_valid = false;
+ } else {
+ ret = of_property_read_u32(phy_node, "reg", &phy_addr);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to read PHY address for port %d. Error %d\n",
+ dp->index, ret);
+ phys_are_valid = false;
+ } else if (phy_addr != dev->phy_addr_map[dp->index]) {
+ dev_err(dev->dev, "PHY address mismatch for port %d, expected 0x%x, got 0x%x\n",
+ dp->index, dev->phy_addr_map[dp->index],
+ phy_addr);
+ phys_are_valid = false;
+ } else {
+ bus->phy_mask |= BIT(phy_addr);
+ }
+ }
+
+ of_node_put(phy_node);
+ of_node_put(phy_parent_node);
+ }
+
+ if (!phys_are_valid)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * ksz_mdio_register - Register and configure the MDIO bus for the KSZ device.
+ * @dev: Pointer to the KSZ device structure.
+ *
+ * This function sets up and registers an MDIO bus for the KSZ switch device,
+ * allowing access to its internal PHYs. If the device supports side MDIO,
+ * the function will configure the external MDIO controller specified by the
+ * "mdio-parent-bus" device tree property to directly manage internal PHYs.
+ * Otherwise, SPI or I2C access is set up for PHY access.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
static int ksz_mdio_register(struct ksz_device *dev)
{
+ struct device_node *parent_bus_node;
+ struct mii_bus *parent_bus = NULL;
struct dsa_switch *ds = dev->ds;
struct device_node *mdio_np;
struct mii_bus *bus;
- int ret;
+ int ret, i;
mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio");
if (!mdio_np)
return 0;
+ parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0);
+ if (parent_bus_node && !dev->info->phy_side_mdio_supported) {
+ dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n");
+ ret = -EINVAL;
+
+ goto put_mdio_node;
+ } else if (parent_bus_node) {
+ parent_bus = of_mdio_find_bus(parent_bus_node);
+ if (!parent_bus) {
+ ret = -EPROBE_DEFER;
+
+ goto put_mdio_node;
+ }
+
+ dev->parent_mdio_bus = parent_bus;
+ }
+
bus = devm_mdiobus_alloc(ds->dev);
if (!bus) {
- of_node_put(mdio_np);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto put_mdio_node;
+ }
+
+ if (dev->dev_ops->mdio_bus_preinit) {
+ ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus);
+ if (ret)
+ goto put_mdio_node;
+ }
+
+ if (dev->dev_ops->create_phy_addr_map) {
+ ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus);
+ if (ret)
+ goto put_mdio_node;
+ } else {
+ for (i = 0; i < dev->info->port_cnt; i++)
+ dev->phy_addr_map[i] = i;
}
bus->priv = dev;
- bus->read = ksz_sw_mdio_read;
- bus->write = ksz_sw_mdio_write;
- bus->name = "ksz user smi";
- snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index);
+ if (parent_bus) {
+ bus->read = ksz_parent_mdio_read;
+ bus->write = ksz_parent_mdio_write;
+ bus->name = "KSZ side MDIO";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d",
+ ds->index);
+ } else {
+ bus->read = ksz_sw_mdio_read;
+ bus->write = ksz_sw_mdio_write;
+ bus->name = "ksz user smi";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index);
+ }
+
+ ret = ksz_parse_dt_phy_config(dev, bus, mdio_np);
+ if (ret)
+ goto put_mdio_node;
+
+ ds->phys_mii_mask = bus->phy_mask;
bus->parent = ds->dev;
- bus->phy_mask = ~ds->phys_mii_mask;
ds->user_mii_bus = bus;
if (dev->irq > 0) {
ret = ksz_irq_phy_setup(dev);
- if (ret) {
- of_node_put(mdio_np);
- return ret;
- }
+ if (ret)
+ goto put_mdio_node;
}
ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np);
@@ -2318,7 +2576,9 @@ static int ksz_mdio_register(struct ksz_device *dev)
ksz_irq_phy_free(dev);
}
+put_mdio_node:
of_node_put(mdio_np);
+ of_node_put(parent_bus_node);
return ret;
}
@@ -2745,6 +3005,7 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
case KSZ9896_CHIP_ID:
/* KSZ9896C Errata DS80000757A Module 3 */
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
/* KSZ9897R Errata DS80000758C Module 4 */
/* Energy Efficient Ethernet (EEE) feature select must be manually disabled
* The EEE feature is enabled by default, but it is not fully
@@ -3005,6 +3266,7 @@ static void ksz_port_teardown(struct dsa_switch *ds, int port)
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
if (dsa_is_user_port(ds, port))
ksz9477_port_acl_free(dev, port);
}
@@ -3061,7 +3323,8 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
dev->chip_id == KSZ9477_CHIP_ID ||
dev->chip_id == KSZ9896_CHIP_ID ||
dev->chip_id == KSZ9897_CHIP_ID ||
- dev->chip_id == KSZ9567_CHIP_ID)
+ dev->chip_id == KSZ9567_CHIP_ID ||
+ dev->chip_id == LAN9646_CHIP_ID)
proto = DSA_TAG_PROTO_KSZ9477;
if (is_lan937x(dev))
@@ -3180,6 +3443,7 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port)
case LAN9372_CHIP_ID:
case LAN9373_CHIP_ID:
case LAN9374_CHIP_ID:
+ case LAN9646_CHIP_ID:
return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
}
@@ -3202,6 +3466,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port)
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
return 0;
}
@@ -3554,7 +3819,10 @@ static int ksz_switch_detect(struct ksz_device *dev)
case LAN9372_CHIP_ID:
case LAN9373_CHIP_ID:
case LAN9374_CHIP_ID:
- dev->chip_id = id32;
+
+ /* LAN9646 does not have its own chip id. */
+ if (dev->chip_id != LAN9646_CHIP_ID)
+ dev->chip_id = id32;
break;
case KSZ9893_CHIP_ID:
ret = ksz_read8(dev, REG_CHIP_ID4,
@@ -3593,6 +3861,7 @@ static int ksz_cls_flower_add(struct dsa_switch *ds, int port,
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
return ksz9477_cls_flower_add(ds, port, cls, ingress);
}
@@ -3613,6 +3882,7 @@ static int ksz_cls_flower_del(struct dsa_switch *ds, int port,
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
return ksz9477_cls_flower_del(ds, port, cls, ingress);
}
@@ -4700,6 +4970,7 @@ static int ksz_parse_drive_strength(struct ksz_device *dev)
case KSZ9893_CHIP_ID:
case KSZ9896_CHIP_ID:
case KSZ9897_CHIP_ID:
+ case LAN9646_CHIP_ID:
return ksz9477_drive_strength_write(dev, of_props,
ARRAY_SIZE(of_props));
default:
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index bec846e20682..b3bb75ca0796 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -65,6 +65,12 @@ struct ksz_chip_data {
u8 num_tx_queues;
u8 num_ipms; /* number of Internal Priority Maps */
bool tc_cbs_supported;
+
+ /**
+ * @phy_side_mdio_supported: Indicates if the chip supports an additional
+ * side MDIO channel for accessing integrated PHYs.
+ */
+ bool phy_side_mdio_supported;
const struct ksz_dev_ops *ops;
const struct phylink_mac_ops *phylink_mac_ops;
bool phy_errata_9477;
@@ -191,6 +197,22 @@ struct ksz_device {
struct ksz_switch_macaddr *switch_macaddr;
struct net_device *hsr_dev; /* HSR */
u8 hsr_ports;
+
+ /**
+ * @phy_addr_map: Array mapping switch ports to their corresponding PHY
+ * addresses.
+ */
+ u8 phy_addr_map[KSZ_MAX_NUM_PORTS];
+
+ /**
+ * @parent_mdio_bus: Pointer to the external MDIO bus controller.
+ *
+ * This points to an external MDIO bus controller that is used to access
+ * the PHYs integrated within the switch. Unlike an integrated MDIO
+ * bus, this external controller provides a direct path for managing
+ * the switch’s internal PHYs, bypassing the main SPI interface.
+ */
+ struct mii_bus *parent_mdio_bus;
};
/* List of supported models */
@@ -214,6 +236,7 @@ enum ksz_model {
LAN9372,
LAN9373,
LAN9374,
+ LAN9646,
};
enum ksz_regs {
@@ -326,6 +349,43 @@ struct ksz_dev_ops {
void (*port_cleanup)(struct ksz_device *dev, int port);
void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port);
int (*set_ageing_time)(struct ksz_device *dev, unsigned int msecs);
+
+ /**
+ * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus
+ * for accessing PHYs.
+ * @dev: Pointer to device structure.
+ * @side_mdio: Boolean indicating if the PHYs are accessed over a side
+ * MDIO bus.
+ *
+ * This function pointer is used to configure the MDIO bus for PHY
+ * access before initiating regular PHY operations. It enables either
+ * SPI/I2C or side MDIO access modes by unlocking necessary registers
+ * and setting up access permissions for the selected mode.
+ *
+ * Return:
+ * - 0 on success.
+ * - Negative error code on failure.
+ */
+ int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio);
+
+ /**
+ * @create_phy_addr_map: Function pointer to create a port-to-PHY
+ * address map.
+ * @dev: Pointer to device structure.
+ * @side_mdio: Boolean indicating if the PHYs are accessed over a side
+ * MDIO bus.
+ *
+ * This function pointer is responsible for mapping switch ports to PHY
+ * addresses according to the configured access mode (SPI or side MDIO)
+ * and the device’s strap configuration. The mapping setup may vary
+ * depending on the chip variant and configuration. Ensures the correct
+ * address mapping for PHY communication.
+ *
+ * Return:
+ * - 0 on success.
+ * - Negative error code on failure (e.g., invalid configuration).
+ */
+ int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio);
int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr,
diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c
index 1c6652f2b9fe..108a958dc356 100644
--- a/drivers/net/dsa/microchip/ksz_spi.c
+++ b/drivers/net/dsa/microchip/ksz_spi.c
@@ -54,6 +54,8 @@ static int ksz_spi_probe(struct spi_device *spi)
if (!chip)
return -EINVAL;
+ /* Save chip id to do special initialization when probing. */
+ dev->chip_id = chip->chip_id;
if (chip->chip_id == KSZ88X3_CHIP_ID)
regmap_config = ksz8863_regmap_config;
else if (chip->chip_id == KSZ8795_CHIP_ID ||
@@ -203,6 +205,10 @@ static const struct of_device_id ksz_dt_ids[] = {
.compatible = "microchip,lan9374",
.data = &ksz_switch_chips[LAN9374]
},
+ {
+ .compatible = "microchip,lan9646",
+ .data = &ksz_switch_chips[LAN9646]
+ },
{},
};
MODULE_DEVICE_TABLE(of, ksz_dt_ids);
@@ -228,6 +234,7 @@ static const struct spi_device_id ksz_spi_ids[] = {
{ "lan9372" },
{ "lan9373" },
{ "lan9374" },
+ { "lan9646" },
{ },
};
MODULE_DEVICE_TABLE(spi, ksz_spi_ids);
diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h
index 3388d91dbc44..df13ebbd356f 100644
--- a/drivers/net/dsa/microchip/lan937x.h
+++ b/drivers/net/dsa/microchip/lan937x.h
@@ -13,6 +13,8 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port);
void lan937x_config_cpu_port(struct dsa_switch *ds);
int lan937x_switch_init(struct ksz_device *dev);
void lan937x_switch_exit(struct ksz_device *dev);
+int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio);
+int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio);
int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu);
diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
index 824d9309a3d3..b7652efd632e 100644
--- a/drivers/net/dsa/microchip/lan937x_main.c
+++ b/drivers/net/dsa/microchip/lan937x_main.c
@@ -18,6 +18,87 @@
#include "ksz9477.h"
#include "lan937x.h"
+/* marker for ports without built-in PHY */
+#define LAN937X_NO_PHY U8_MAX
+
+/*
+ * lan9370_phy_addr - Mapping of LAN9370 switch ports to PHY addresses.
+ *
+ * Each entry corresponds to a specific port on the LAN9370 switch,
+ * where ports 1-4 are connected to integrated 100BASE-T1 PHYs, and
+ * Port 5 is connected to an RGMII interface without a PHY. The values
+ * are based on the documentation (DS00003108E, section 3.3).
+ */
+static const u8 lan9370_phy_addr[] = {
+ [0] = 2, /* Port 1, T1 AFE0 */
+ [1] = 3, /* Port 2, T1 AFE1 */
+ [2] = 5, /* Port 3, T1 AFE3 */
+ [3] = 6, /* Port 4, T1 AFE4 */
+ [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */
+};
+
+/*
+ * lan9371_phy_addr - Mapping of LAN9371 switch ports to PHY addresses.
+ *
+ * The values are based on the documentation (DS00003109E, section 3.3).
+ */
+static const u8 lan9371_phy_addr[] = {
+ [0] = 2, /* Port 1, T1 AFE0 */
+ [1] = 3, /* Port 2, T1 AFE1 */
+ [2] = 5, /* Port 3, T1 AFE3 */
+ [3] = 8, /* Port 4, TX PHY */
+ [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */
+ [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */
+};
+
+/*
+ * lan9372_phy_addr - Mapping of LAN9372 switch ports to PHY addresses.
+ *
+ * The values are based on the documentation (DS00003110F, section 3.3).
+ */
+static const u8 lan9372_phy_addr[] = {
+ [0] = 2, /* Port 1, T1 AFE0 */
+ [1] = 3, /* Port 2, T1 AFE1 */
+ [2] = 5, /* Port 3, T1 AFE3 */
+ [3] = 8, /* Port 4, TX PHY */
+ [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */
+ [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */
+ [6] = 6, /* Port 7, T1 AFE4 */
+ [7] = 4, /* Port 8, T1 AFE2 */
+};
+
+/*
+ * lan9373_phy_addr - Mapping of LAN9373 switch ports to PHY addresses.
+ *
+ * The values are based on the documentation (DS00003110F, section 3.3).
+ */
+static const u8 lan9373_phy_addr[] = {
+ [0] = 2, /* Port 1, T1 AFE0 */
+ [1] = 3, /* Port 2, T1 AFE1 */
+ [2] = 5, /* Port 3, T1 AFE3 */
+ [3] = LAN937X_NO_PHY, /* Port 4, SGMII */
+ [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */
+ [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */
+ [6] = 6, /* Port 7, T1 AFE4 */
+ [7] = 4, /* Port 8, T1 AFE2 */
+};
+
+/*
+ * lan9374_phy_addr - Mapping of LAN9374 switch ports to PHY addresses.
+ *
+ * The values are based on the documentation (DS00003110F, section 3.3).
+ */
+static const u8 lan9374_phy_addr[] = {
+ [0] = 2, /* Port 1, T1 AFE0 */
+ [1] = 3, /* Port 2, T1 AFE1 */
+ [2] = 5, /* Port 3, T1 AFE3 */
+ [3] = 7, /* Port 4, T1 AFE5 */
+ [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */
+ [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */
+ [6] = 6, /* Port 7, T1 AFE4 */
+ [7] = 4, /* Port 8, T1 AFE2 */
+};
+
static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
{
return regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0);
@@ -30,24 +111,144 @@ static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset,
bits, set ? bits : 0);
}
-static int lan937x_enable_spi_indirect_access(struct ksz_device *dev)
+/**
+ * lan937x_create_phy_addr_map - Create port-to-PHY address map for MDIO bus.
+ * @dev: Pointer to device structure.
+ * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus.
+ *
+ * This function sets up the PHY address mapping for the LAN937x switches,
+ * which support two access modes for internal PHYs:
+ * 1. **SPI Access**: A straightforward one-to-one port-to-PHY address
+ * mapping is applied.
+ * 2. **MDIO Access**: The PHY address mapping varies based on chip variant
+ * and strap configuration. An offset is calculated based on strap settings
+ * to ensure correct PHY addresses are assigned. The offset calculation logic
+ * is based on Microchip's Article Number 000015828, available at:
+ * https://microchip.my.site.com/s/article/LAN9374-Virtual-PHY-PHY-Address-Mapping
+ *
+ * The function first checks if side MDIO access is disabled, in which case a
+ * simple direct mapping (port number = PHY address) is applied. If side MDIO
+ * access is enabled, it reads the strap configuration to determine the correct
+ * offset for PHY addresses.
+ *
+ * The appropriate mapping table is selected based on the chip ID, and the
+ * `phy_addr_map` is populated with the correct addresses for each port. Any
+ * port with no PHY is assigned a `LAN937X_NO_PHY` marker.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio)
+{
+ static const u8 *phy_addr_map;
+ u32 strap_val;
+ u8 offset = 0;
+ size_t size;
+ int ret, i;
+
+ if (!side_mdio) {
+ /* simple direct mapping */
+ for (i = 0; i < dev->info->port_cnt; i++)
+ dev->phy_addr_map[i] = i;
+
+ return 0;
+ }
+
+ ret = ksz_read32(dev, REG_SW_CFG_STRAP_VAL, &strap_val);
+ if (ret < 0)
+ return ret;
+
+ if (!(strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG))
+ offset = 0;
+ else if (!(strap_val & SW_CASCADE_ID_CFG) && (strap_val & SW_VPHY_ADD_CFG))
+ offset = 7;
+ else if ((strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG))
+ offset = 15;
+ else
+ offset = 22;
+
+ switch (dev->info->chip_id) {
+ case LAN9370_CHIP_ID:
+ phy_addr_map = lan9370_phy_addr;
+ size = ARRAY_SIZE(lan9370_phy_addr);
+ break;
+ case LAN9371_CHIP_ID:
+ phy_addr_map = lan9371_phy_addr;
+ size = ARRAY_SIZE(lan9371_phy_addr);
+ break;
+ case LAN9372_CHIP_ID:
+ phy_addr_map = lan9372_phy_addr;
+ size = ARRAY_SIZE(lan9372_phy_addr);
+ break;
+ case LAN9373_CHIP_ID:
+ phy_addr_map = lan9373_phy_addr;
+ size = ARRAY_SIZE(lan9373_phy_addr);
+ break;
+ case LAN9374_CHIP_ID:
+ phy_addr_map = lan9374_phy_addr;
+ size = ARRAY_SIZE(lan9374_phy_addr);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (size < dev->info->port_cnt)
+ return -EINVAL;
+
+ for (i = 0; i < dev->info->port_cnt; i++) {
+ if (phy_addr_map[i] == LAN937X_NO_PHY)
+ dev->phy_addr_map[i] = phy_addr_map[i];
+ else
+ dev->phy_addr_map[i] = phy_addr_map[i] + offset;
+ }
+
+ return 0;
+}
+
+/**
+ * lan937x_mdio_bus_preinit - Pre-initialize MDIO bus for accessing PHYs.
+ * @dev: Pointer to device structure.
+ * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus.
+ *
+ * This function configures the LAN937x switch for PHY access either through
+ * SPI or the side MDIO bus, unlocking the necessary registers for each access
+ * mode.
+ *
+ * Operation Modes:
+ * 1. **SPI Access**: Enables SPI indirect access to address clock domain
+ * crossing issues when SPI is used for PHY access.
+ * 2. **MDIO Access**: Grants access to internal PHYs over the side MDIO bus,
+ * required when using the MDIO bus for PHY management.
+ *
+ * Return: 0 on success, error code on failure.
+ */
+int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio)
{
u16 data16;
int ret;
- /* Enable Phy access through SPI */
+ /* Unlock access to the PHYs, needed for SPI and side MDIO access */
ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false);
if (ret < 0)
- return ret;
+ goto print_error;
- ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16);
- if (ret < 0)
- return ret;
+ if (side_mdio)
+ /* Allow access to internal PHYs over MDIO bus */
+ data16 = VPHY_MDIO_INTERNAL_ENABLE;
+ else
+ /* Enable SPI indirect access to address clock domain crossing
+ * issue
+ */
+ data16 = VPHY_SPI_INDIRECT_ENABLE;
- /* Allow SPI access */
- data16 |= VPHY_SPI_INDIRECT_ENABLE;
+ ret = ksz_rmw16(dev, REG_VPHY_SPECIAL_CTRL__2,
+ VPHY_SPI_INDIRECT_ENABLE | VPHY_MDIO_INTERNAL_ENABLE,
+ data16);
+
+print_error:
+ if (ret < 0)
+ dev_err(dev->dev, "failed to preinit the MDIO bus\n");
- return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16);
+ return ret;
}
static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg)
@@ -363,13 +564,6 @@ int lan937x_setup(struct dsa_switch *ds)
struct ksz_device *dev = ds->priv;
int ret;
- /* enable Indirect Access from SPI to the VPHY registers */
- ret = lan937x_enable_spi_indirect_access(dev);
- if (ret < 0) {
- dev_err(dev->dev, "failed to enable spi indirect access");
- return ret;
- }
-
/* The VLAN aware is a global setting. Mixed vlan
* filterings are not supported.
*/
diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h
index 2f22a9d01de3..4ec93e421da4 100644
--- a/drivers/net/dsa/microchip/lan937x_reg.h
+++ b/drivers/net/dsa/microchip/lan937x_reg.h
@@ -37,6 +37,10 @@
#define SW_CLK125_ENB BIT(1)
#define SW_CLK25_ENB BIT(0)
+#define REG_SW_CFG_STRAP_VAL 0x0200
+#define SW_CASCADE_ID_CFG BIT(15)
+#define SW_VPHY_ADD_CFG BIT(0)
+
/* 2 - PHY Control */
#define REG_SW_CFG_STRAP_OVR 0x0214
#define SW_VPHY_DISABLE BIT(31)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index d84ee1b419a6..086b8b3d5b40 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -21,6 +21,7 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <net/dsa.h>
+#include <net/pkt_cls.h>
#include "mt7530.h"
@@ -3146,6 +3147,53 @@ mt753x_conduit_state_change(struct dsa_switch *ds,
mt7530_rmw(priv, MT753X_MFC, MT7530_CPU_EN | MT7530_CPU_PORT_MASK, val);
}
+static int mt753x_tc_setup_qdisc_tbf(struct dsa_switch *ds, int port,
+ struct tc_tbf_qopt_offload *qopt)
+{
+ struct tc_tbf_qopt_offload_replace_params *p = &qopt->replace_params;
+ struct mt7530_priv *priv = ds->priv;
+ u32 rate = 0;
+
+ switch (qopt->command) {
+ case TC_TBF_REPLACE:
+ rate = div_u64(p->rate.rate_bytes_ps, 1000) << 3; /* kbps */
+ fallthrough;
+ case TC_TBF_DESTROY: {
+ u32 val, tick;
+
+ mt7530_rmw(priv, MT753X_GERLCR, EGR_BC_MASK,
+ EGR_BC_CRC_IPG_PREAMBLE);
+
+ /* if rate is greater than 10Mbps tick is 1/32 ms,
+ * 1ms otherwise
+ */
+ tick = rate > 10000 ? 2 : 7;
+ val = FIELD_PREP(ERLCR_CIR_MASK, (rate >> 5)) |
+ FIELD_PREP(ERLCR_EN_MASK, !!rate) |
+ FIELD_PREP(ERLCR_EXP_MASK, tick) |
+ ERLCR_TBF_MODE_MASK |
+ FIELD_PREP(ERLCR_MANT_MASK, 0xf);
+ mt7530_write(priv, MT753X_ERLCR_P(port), val);
+ break;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int mt753x_setup_tc(struct dsa_switch *ds, int port,
+ enum tc_setup_type type, void *type_data)
+{
+ switch (type) {
+ case TC_SETUP_QDISC_TBF:
+ return mt753x_tc_setup_qdisc_tbf(ds, port, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int mt7988_setup(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
@@ -3193,6 +3241,7 @@ const struct dsa_switch_ops mt7530_switch_ops = {
.get_mac_eee = mt753x_get_mac_eee,
.set_mac_eee = mt753x_set_mac_eee,
.conduit_state_change = mt753x_conduit_state_change,
+ .port_setup_tc = mt753x_setup_tc,
};
EXPORT_SYMBOL_GPL(mt7530_switch_ops);
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 6ad33a9f6b1d..448200689f49 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -248,6 +248,18 @@ enum mt7530_vlan_egress_attr {
#define AGE_UNIT_MAX 0xfff
#define AGE_UNIT(x) (AGE_UNIT_MASK & (x))
+#define MT753X_ERLCR_P(x) (0x1040 + ((x) * 0x100))
+#define ERLCR_CIR_MASK GENMASK(31, 16)
+#define ERLCR_EN_MASK BIT(15)
+#define ERLCR_EXP_MASK GENMASK(11, 8)
+#define ERLCR_TBF_MODE_MASK BIT(7)
+#define ERLCR_MANT_MASK GENMASK(6, 0)
+
+#define MT753X_GERLCR 0x10e0
+#define EGR_BC_MASK GENMASK(7, 0)
+#define EGR_BC_CRC 0x4 /* crc */
+#define EGR_BC_CRC_IPG_PREAMBLE 0x18 /* crc + ipg + preamble */
+
/* Register for port STP state control */
#define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100))
#define FID_PST(fid, state) (((state) & 0x3) << ((fid) * 2))
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index c75005b4d86e..3a792f79270d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1153,42 +1153,37 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
return value;
}
-static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
- uint8_t *data, int types)
+static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t **data, int types)
{
const struct mv88e6xxx_hw_stat *stat;
- int i, j;
+ int i;
- for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
+ for (i = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
- if (stat->type & types) {
- memcpy(data + j * ETH_GSTRING_LEN, stat->string,
- ETH_GSTRING_LEN);
- j++;
- }
+ if (stat->type & types)
+ ethtool_puts(data, stat->string);
}
-
- return j;
}
-static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
- uint8_t *data)
+static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t **data)
{
- return mv88e6xxx_stats_get_strings(chip, data,
- STATS_TYPE_BANK0 | STATS_TYPE_PORT);
+ mv88e6xxx_stats_get_strings(chip, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_PORT);
}
-static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
- uint8_t *data)
+static void mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t **data)
{
- return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
+ mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
}
-static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
- uint8_t *data)
+static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
+ uint8_t **data)
{
- return mv88e6xxx_stats_get_strings(chip, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
+ mv88e6xxx_stats_get_strings(chip, data,
+ STATS_TYPE_BANK0 | STATS_TYPE_BANK1);
}
static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
@@ -1199,21 +1194,18 @@ static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = {
"vtu_miss_violation",
};
-static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data)
+static void mv88e6xxx_atu_vtu_get_strings(uint8_t **data)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- mv88e6xxx_atu_vtu_stats_strings[i],
- ETH_GSTRING_LEN);
+ ethtool_puts(data, mv88e6xxx_atu_vtu_stats_strings[i]);
}
static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
u32 stringset, uint8_t *data)
{
struct mv88e6xxx_chip *chip = ds->priv;
- int count = 0;
if (stringset != ETH_SS_STATS)
return;
@@ -1221,15 +1213,12 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
mv88e6xxx_reg_lock(chip);
if (chip->info->ops->stats_get_strings)
- count = chip->info->ops->stats_get_strings(chip, data);
+ chip->info->ops->stats_get_strings(chip, &data);
- if (chip->info->ops->serdes_get_strings) {
- data += count * ETH_GSTRING_LEN;
- count = chip->info->ops->serdes_get_strings(chip, port, data);
- }
+ if (chip->info->ops->serdes_get_strings)
+ chip->info->ops->serdes_get_strings(chip, port, &data);
- data += count * ETH_GSTRING_LEN;
- mv88e6xxx_atu_vtu_get_strings(data);
+ mv88e6xxx_atu_vtu_get_strings(&data);
mv88e6xxx_reg_unlock(chip);
}
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 48399ab5355a..9fe8e8a7856b 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -606,7 +606,7 @@ 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);
+ void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t **data);
size_t (*stats_get_stat)(struct mv88e6xxx_chip *chip, int port,
const struct mv88e6xxx_hw_stat *stat,
uint64_t *data);
@@ -633,8 +633,8 @@ struct mv88e6xxx_ops {
/* Statistics from the SERDES interface */
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_strings)(struct mv88e6xxx_chip *chip, int port,
+ uint8_t **data);
size_t (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port,
uint64_t *data);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 01ea53940786..b3330211edbc 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -132,8 +132,8 @@ int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
-int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
- int port, uint8_t *data)
+int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
+ uint8_t **data)
{
struct mv88e6352_serdes_hw_stat *stat;
int err, i;
@@ -144,8 +144,7 @@ int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
stat = &mv88e6352_serdes_hw_stats[i];
- memcpy(data + i * ETH_GSTRING_LEN, stat->string,
- ETH_GSTRING_LEN);
+ ethtool_puts(data, stat->string);
}
return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
}
@@ -394,8 +393,8 @@ int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}
-int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
- int port, uint8_t *data)
+int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
+ uint8_t **data)
{
struct mv88e6390_serdes_hw_stat *stat;
int i;
@@ -405,8 +404,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
stat = &mv88e6390_serdes_hw_stats[i];
- memcpy(data + i * ETH_GSTRING_LEN, stat->string,
- ETH_GSTRING_LEN);
+ ethtool_puts(data, stat->string);
}
return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index ff5c3ab31e15..ad887d8601bc 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -125,13 +125,13 @@ unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int port);
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_strings(struct mv88e6xxx_chip *chip, int port,
+ uint8_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_strings(struct mv88e6xxx_chip *chip, int port,
+ uint8_t **data);
size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data);
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index f8d8c70642c4..59b4a7240b58 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -673,7 +673,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
* We therefore need to lock the MDIO bus onto which the switch is
* connected.
*/
- mutex_lock(&priv->bus->mdio_lock);
+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
/* Actually start the request:
* 1. Send mdio master packet
diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c
index 1135a32e4b7e..66974379334a 100644
--- a/drivers/net/dsa/rzn1_a5psw.c
+++ b/drivers/net/dsa/rzn1_a5psw.c
@@ -802,10 +802,8 @@ static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset,
if (stringset != ETH_SS_STATS)
return;
- for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) {
- memcpy(data + u * ETH_GSTRING_LEN, a5psw_stats[u].name,
- ETH_GSTRING_LEN);
- }
+ for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
+ ethtool_puts(&data, a5psw_stats[u].name);
}
static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c
index decc6c931dc1..2ea64b1d026d 100644
--- a/drivers/net/dsa/sja1105/sja1105_ethtool.c
+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c
@@ -586,7 +586,6 @@ void sja1105_get_strings(struct dsa_switch *ds, int port,
{
struct sja1105_private *priv = ds->priv;
enum sja1105_counter_index max_ctr, i;
- char *p = data;
if (stringset != ETH_SS_STATS)
return;
@@ -597,10 +596,8 @@ void sja1105_get_strings(struct dsa_switch *ds, int port,
else
max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER;
- for (i = 0; i < max_ctr; i++) {
- strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < max_ctr; i++)
+ ethtool_puts(&data, sja1105_port_counters[i].name);
}
int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset)
diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c
index de3b768f2ff9..4dbcc49a9e52 100644
--- a/drivers/net/dsa/xrs700x/xrs700x.c
+++ b/drivers/net/dsa/xrs700x/xrs700x.c
@@ -91,10 +91,8 @@ static void xrs700x_get_strings(struct dsa_switch *ds, int port,
if (stringset != ETH_SS_STATS)
return;
- for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++) {
- strscpy(data, xrs700x_mibs[i].name, ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++)
+ ethtool_puts(&data, xrs700x_mibs[i].name);
}
static int xrs700x_get_sset_count(struct dsa_switch *ds, int port, int sset)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index e9c5e1e11fa0..005d79975f3b 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -168,22 +168,21 @@ static int __init dummy_init_module(void)
{
int i, err = 0;
- down_write(&pernet_ops_rwsem);
- rtnl_lock();
- err = __rtnl_link_register(&dummy_link_ops);
+ err = rtnl_link_register(&dummy_link_ops);
if (err < 0)
- goto out;
+ return err;
+
+ rtnl_net_lock(&init_net);
for (i = 0; i < numdummies && !err; i++) {
err = dummy_init_one();
cond_resched();
}
- if (err < 0)
- __rtnl_link_unregister(&dummy_link_ops);
-out:
- rtnl_unlock();
- up_write(&pernet_ops_rwsem);
+ rtnl_net_unlock(&init_net);
+
+ if (err < 0)
+ rtnl_link_unregister(&dummy_link_ops);
return err;
}
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index d958cda9e58b..66445617fbfb 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -763,25 +763,16 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com
if (comp_ctx->status == ENA_CMD_COMPLETED) {
netdev_err(admin_queue->ena_dev->net_device,
- "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n",
- comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF");
- /* Check if fallback to polling is enabled */
- if (admin_queue->auto_polling)
- admin_queue->polling = true;
+ "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d)\n",
+ comp_ctx->cmd_opcode);
} else {
netdev_err(admin_queue->ena_dev->net_device,
"The ena device didn't send a completion for the admin cmd %d status %d\n",
comp_ctx->cmd_opcode, comp_ctx->status);
}
- /* Check if shifted to polling mode.
- * This will happen if there is a completion without an interrupt
- * and autopolling mode is enabled. Continuing normal execution in such case
- */
- if (!admin_queue->polling) {
- admin_queue->running_state = false;
- ret = -ETIME;
- goto err;
- }
+ admin_queue->running_state = false;
+ ret = -ETIME;
+ goto err;
}
ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status);
@@ -1650,12 +1641,6 @@ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
ena_dev->admin_queue.polling = polling;
}
-void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
- bool polling)
-{
- ena_dev->admin_queue.auto_polling = polling;
-}
-
int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
{
struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
@@ -2198,21 +2183,6 @@ int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev,
return ret;
}
-int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
- struct ena_admin_basic_stats *stats)
-{
- struct ena_com_stats_ctx ctx;
- int ret;
-
- memset(&ctx, 0x0, sizeof(ctx));
- ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC);
- if (likely(ret == 0))
- memcpy(stats, &ctx.get_resp.u.basic_stats,
- sizeof(ctx.get_resp.u.basic_stats));
-
- return ret;
-}
-
int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len)
{
struct ena_admin_aq_get_stats_cmd *get_cmd;
@@ -2289,24 +2259,6 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu)
return ret;
}
-int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
- struct ena_admin_feature_offload_desc *offload)
-{
- int ret;
- struct ena_admin_get_feat_resp resp;
-
- ret = ena_com_get_feature(ena_dev, &resp,
- ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0);
- if (unlikely(ret)) {
- netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret);
- return ret;
- }
-
- memcpy(offload, &resp.u.offload, sizeof(resp.u.offload));
-
- return 0;
-}
-
int ena_com_set_hash_function(struct ena_com_dev *ena_dev)
{
struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue;
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h
index a372c5e768a7..9414e93d107b 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.h
+++ b/drivers/net/ethernet/amazon/ena/ena_com.h
@@ -224,9 +224,6 @@ struct ena_com_admin_queue {
/* Indicate if the admin queue should poll for completion */
bool polling;
- /* Define if fallback to polling mode should occur */
- bool auto_polling;
-
u16 curr_cmd_id;
/* Indicate that the ena was initialized and can
@@ -493,17 +490,6 @@ bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev);
*/
void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling);
-/* ena_com_set_admin_auto_polling_mode - Enable autoswitch to polling mode
- * @ena_dev: ENA communication layer struct
- * @polling: Enable/Disable polling mode
- *
- * Set the autopolling mode.
- * If autopolling is on:
- * In case of missing interrupt when data is available switch to polling.
- */
-void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev,
- bool polling);
-
/* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler
* @ena_dev: ENA communication layer struct
*
@@ -591,15 +577,6 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag);
int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
struct ena_com_dev_get_features_ctx *get_feat_ctx);
-/* ena_com_get_dev_basic_stats - Get device basic statistics
- * @ena_dev: ENA communication layer struct
- * @stats: stats return value
- *
- * @return: 0 on Success and negative value otherwise.
- */
-int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev,
- struct ena_admin_basic_stats *stats);
-
/* ena_com_get_eni_stats - Get extended network interface statistics
* @ena_dev: ENA communication layer struct
* @stats: stats return value
@@ -635,15 +612,6 @@ int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32
*/
int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu);
-/* ena_com_get_offload_settings - Retrieve the device offloads capabilities
- * @ena_dev: ENA communication layer struct
- * @offlad: offload return value
- *
- * @return: 0 on Success and negative value otherwise.
- */
-int ena_com_get_offload_settings(struct ena_com_dev *ena_dev,
- struct ena_admin_feature_offload_desc *offload);
-
/* ena_com_rss_init - Init RSS
* @ena_dev: ENA communication layer struct
* @log_size: indirection log size
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index 60fb35ec4b15..a3c934c3de71 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -1129,22 +1129,18 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
return;
}
- strings_buf = devm_kcalloc(&adapter->pdev->dev,
- ETH_GSTRING_LEN, strings_num,
- GFP_ATOMIC);
+ strings_buf = kcalloc(strings_num, ETH_GSTRING_LEN, GFP_ATOMIC);
if (!strings_buf) {
netif_err(adapter, drv, netdev,
"Failed to allocate strings_buf\n");
return;
}
- data_buf = devm_kcalloc(&adapter->pdev->dev,
- strings_num, sizeof(u64),
- GFP_ATOMIC);
+ data_buf = kcalloc(strings_num, sizeof(u64), GFP_ATOMIC);
if (!data_buf) {
netif_err(adapter, drv, netdev,
"Failed to allocate data buf\n");
- devm_kfree(&adapter->pdev->dev, strings_buf);
+ kfree(strings_buf);
return;
}
@@ -1166,8 +1162,8 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf)
strings_buf + i * ETH_GSTRING_LEN,
data_buf[i]);
- devm_kfree(&adapter->pdev->dev, strings_buf);
- devm_kfree(&adapter->pdev->dev, data_buf);
+ kfree(strings_buf);
+ kfree(data_buf);
}
void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf)
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 96df20854eb9..63c8a2328142 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -1383,7 +1383,7 @@ static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
rx_ring->rx_stats.bytes,
&dim_sample);
- net_dim(&ena_napi->dim, dim_sample);
+ net_dim(&ena_napi->dim, &dim_sample);
rx_ring->per_napi_packets = 0;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index 5fc94c2f638e..4431ab1c18b3 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -195,23 +195,19 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < XGBE_STATS_COUNT; i++) {
- memcpy(data, xgbe_gstring_stats[i].stat_string,
- ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < XGBE_STATS_COUNT; i++)
+ ethtool_puts(&data, xgbe_gstring_stats[i].stat_string);
+
for (i = 0; i < pdata->tx_ring_count; i++) {
- sprintf(data, "txq_%u_packets", i);
- data += ETH_GSTRING_LEN;
- sprintf(data, "txq_%u_bytes", i);
- data += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "txq_%u_packets", i);
+ ethtool_sprintf(&data, "txq_%u_bytes", i);
}
+
for (i = 0; i < pdata->rx_ring_count; i++) {
- sprintf(data, "rxq_%u_packets", i);
- data += ETH_GSTRING_LEN;
- sprintf(data, "rxq_%u_bytes", i);
- data += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "rxq_%u_packets", i);
+ ethtool_sprintf(&data, "rxq_%u_bytes", i);
}
+
break;
}
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
index 43c71f6b314f..08630ee94251 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
@@ -162,8 +162,8 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
self->msix_entry_mask |= (1 << i);
if (pdev->msix_enabled && affinity_mask)
- irq_set_affinity_hint(pci_irq_vector(pdev, i),
- affinity_mask);
+ irq_update_affinity_hint(pci_irq_vector(pdev, i),
+ affinity_mask);
}
return err;
@@ -187,7 +187,7 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self)
continue;
if (pdev->msix_enabled)
- irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL);
+ irq_update_affinity_hint(pci_irq_vector(pdev, i), NULL);
free_irq(pci_irq_vector(pdev, i), irq_data);
self->msix_entry_mask &= ~(1U << i);
}
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 31ee477dd131..8283aeee35fb 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -111,6 +111,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
{
struct arc_emac_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
+ struct device *dev = ndev->dev.parent;
unsigned int i;
for (i = 0; i < TX_BD_NUM; i++) {
@@ -140,7 +141,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
stats->tx_bytes += skb->len;
}
- dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr),
+ dma_unmap_single(dev, dma_unmap_addr(tx_buff, addr),
dma_unmap_len(tx_buff, len), DMA_TO_DEVICE);
/* return the sk_buff to system */
@@ -174,6 +175,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
static int arc_emac_rx(struct net_device *ndev, int budget)
{
struct arc_emac_priv *priv = netdev_priv(ndev);
+ struct device *dev = ndev->dev.parent;
unsigned int work_done;
for (work_done = 0; work_done < budget; work_done++) {
@@ -223,9 +225,9 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
continue;
}
- addr = dma_map_single(&ndev->dev, (void *)skb->data,
+ addr = dma_map_single(dev, (void *)skb->data,
EMAC_BUFFER_SIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(&ndev->dev, addr)) {
+ if (dma_mapping_error(dev, addr)) {
if (net_ratelimit())
netdev_err(ndev, "cannot map dma buffer\n");
dev_kfree_skb(skb);
@@ -237,7 +239,7 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
}
/* unmap previosly mapped skb */
- dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
+ dma_unmap_single(dev, dma_unmap_addr(rx_buff, addr),
dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
pktlen = info & LEN_MASK;
@@ -423,6 +425,7 @@ static int arc_emac_open(struct net_device *ndev)
{
struct arc_emac_priv *priv = netdev_priv(ndev);
struct phy_device *phy_dev = ndev->phydev;
+ struct device *dev = ndev->dev.parent;
int i;
phy_dev->autoneg = AUTONEG_ENABLE;
@@ -445,9 +448,9 @@ static int arc_emac_open(struct net_device *ndev)
if (unlikely(!rx_buff->skb))
return -ENOMEM;
- addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data,
+ addr = dma_map_single(dev, (void *)rx_buff->skb->data,
EMAC_BUFFER_SIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(&ndev->dev, addr)) {
+ if (dma_mapping_error(dev, addr)) {
netdev_err(ndev, "cannot dma map\n");
dev_kfree_skb(rx_buff->skb);
return -ENOMEM;
@@ -548,6 +551,7 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
static void arc_free_tx_queue(struct net_device *ndev)
{
struct arc_emac_priv *priv = netdev_priv(ndev);
+ struct device *dev = ndev->dev.parent;
unsigned int i;
for (i = 0; i < TX_BD_NUM; i++) {
@@ -555,7 +559,7 @@ static void arc_free_tx_queue(struct net_device *ndev)
struct buffer_state *tx_buff = &priv->tx_buff[i];
if (tx_buff->skb) {
- dma_unmap_single(&ndev->dev,
+ dma_unmap_single(dev,
dma_unmap_addr(tx_buff, addr),
dma_unmap_len(tx_buff, len),
DMA_TO_DEVICE);
@@ -579,6 +583,7 @@ static void arc_free_tx_queue(struct net_device *ndev)
static void arc_free_rx_queue(struct net_device *ndev)
{
struct arc_emac_priv *priv = netdev_priv(ndev);
+ struct device *dev = ndev->dev.parent;
unsigned int i;
for (i = 0; i < RX_BD_NUM; i++) {
@@ -586,7 +591,7 @@ static void arc_free_rx_queue(struct net_device *ndev)
struct buffer_state *rx_buff = &priv->rx_buff[i];
if (rx_buff->skb) {
- dma_unmap_single(&ndev->dev,
+ dma_unmap_single(dev,
dma_unmap_addr(rx_buff, addr),
dma_unmap_len(rx_buff, len),
DMA_FROM_DEVICE);
@@ -679,6 +684,7 @@ static netdev_tx_t arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
unsigned int len, *txbd_curr = &priv->txbd_curr;
struct net_device_stats *stats = &ndev->stats;
__le32 *info = &priv->txbd[*txbd_curr].info;
+ struct device *dev = ndev->dev.parent;
dma_addr_t addr;
if (skb_padto(skb, ETH_ZLEN))
@@ -692,10 +698,9 @@ static netdev_tx_t arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
- addr = dma_map_single(&ndev->dev, (void *)skb->data, len,
- DMA_TO_DEVICE);
+ addr = dma_map_single(dev, (void *)skb->data, len, DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(&ndev->dev, addr))) {
+ if (unlikely(dma_mapping_error(dev, addr))) {
stats->tx_dropped++;
stats->tx_errors++;
dev_kfree_skb_any(skb);
diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c
index 87f40c2ba904..078b1a72c161 100644
--- a/drivers/net/ethernet/arc/emac_mdio.c
+++ b/drivers/net/ethernet/arc/emac_mdio.c
@@ -133,6 +133,7 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
struct arc_emac_mdio_bus_data *data = &priv->bus_data;
struct device_node *np = priv->dev->of_node;
const char *name = "Synopsys MII Bus";
+ struct device_node *mdio_node;
struct mii_bus *bus;
int error;
@@ -164,7 +165,13 @@ int arc_mdio_probe(struct arc_emac_priv *priv)
snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
- error = of_mdiobus_register(bus, priv->dev->of_node);
+ /* Backwards compatibility for EMAC nodes without MDIO subnode. */
+ mdio_node = of_get_child_by_name(np, "mdio");
+ if (!mdio_node)
+ mdio_node = of_node_get(np);
+
+ error = of_mdiobus_register(bus, mdio_node);
+ of_node_put(mdio_node);
if (error) {
mdiobus_free(bus);
return dev_err_probe(priv->dev, error,
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c
index 67928b5d8a26..9da5ae29a105 100644
--- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c
@@ -101,14 +101,14 @@ static int bcmasp_get_sset_count(struct net_device *dev, int string_set)
static void bcmasp_get_strings(struct net_device *dev, u32 stringset,
u8 *data)
{
+ const char *str;
unsigned int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < BCMASP_STATS_LEN; i++) {
- memcpy(data + i * ETH_GSTRING_LEN,
- bcmasp_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ str = bcmasp_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
break;
default:
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index e5e03aaa49f9..65e3a0656a4c 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -1339,14 +1339,14 @@ static int bcm_enet_get_sset_count(struct net_device *netdev,
static void bcm_enet_get_strings(struct net_device *netdev,
u32 stringset, u8 *data)
{
+ const char *str;
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < BCM_ENET_STATS_LEN; i++) {
- memcpy(data + i * ETH_GSTRING_LEN,
- bcm_enet_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ str = bcm_enet_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
break;
}
@@ -2503,14 +2503,14 @@ static const struct bcm_enet_stats bcm_enetsw_gstrings_stats[] = {
static void bcm_enetsw_get_strings(struct net_device *netdev,
u32 stringset, u8 *data)
{
+ const char *str;
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) {
- memcpy(data + i * ETH_GSTRING_LEN,
- bcm_enetsw_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ str = bcm_enetsw_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
break;
}
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index caff6e87a488..42672c63f108 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -346,32 +346,22 @@ static void bcm_sysport_get_strings(struct net_device *dev,
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
const struct bcm_sysport_stats *s;
- char buf[128];
- int i, j;
+ int i;
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0, j = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
+ for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) {
s = &bcm_sysport_gstrings_stats[i];
if (priv->is_lite &&
!bcm_sysport_lite_stat_valid(s->type))
continue;
- memcpy(data + j * ETH_GSTRING_LEN, s->stat_string,
- ETH_GSTRING_LEN);
- j++;
+ ethtool_puts(&data, s->stat_string);
}
for (i = 0; i < dev->num_tx_queues; i++) {
- snprintf(buf, sizeof(buf), "txq%d_packets", i);
- memcpy(data + j * ETH_GSTRING_LEN, buf,
- ETH_GSTRING_LEN);
- j++;
-
- snprintf(buf, sizeof(buf), "txq%d_bytes", i);
- memcpy(data + j * ETH_GSTRING_LEN, buf,
- ETH_GSTRING_LEN);
- j++;
+ ethtool_sprintf(&data, "txq%d_packets", i);
+ ethtool_sprintf(&data, "txq%d_bytes", i);
}
break;
default:
@@ -1029,7 +1019,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget)
if (priv->dim.use_dim) {
dim_update_sample(priv->dim.event_ctr, priv->dim.packets,
priv->dim.bytes, &dim_sample);
- net_dim(&priv->dim.dim, dim_sample);
+ net_dim(&priv->dim.dim, &dim_sample);
}
return work_done;
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 6ffdc4229407..a461ec612e95 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1367,8 +1367,7 @@ static void bgmac_get_strings(struct net_device *dev, u32 stringset,
return;
for (i = 0; i < BGMAC_STATS_LEN; i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- bgmac_get_strings_stats[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, bgmac_get_strings_stats[i].name);
}
static void bgmac_get_ethtool_stats(struct net_device *dev,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index adf7b6b94941..44199855ebfb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -39,34 +39,34 @@ static const struct {
int size;
char string[ETH_GSTRING_LEN];
} bnx2x_q_stats_arr[] = {
-/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" },
+/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" },
{ Q_STATS_OFFSET32(total_unicast_packets_received_hi),
- 8, "[%s]: rx_ucast_packets" },
+ 8, "[%d]: rx_ucast_packets" },
{ Q_STATS_OFFSET32(total_multicast_packets_received_hi),
- 8, "[%s]: rx_mcast_packets" },
+ 8, "[%d]: rx_mcast_packets" },
{ Q_STATS_OFFSET32(total_broadcast_packets_received_hi),
- 8, "[%s]: rx_bcast_packets" },
- { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" },
+ 8, "[%d]: rx_bcast_packets" },
+ { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" },
{ Q_STATS_OFFSET32(rx_err_discard_pkt),
- 4, "[%s]: rx_phy_ip_err_discards"},
+ 4, "[%d]: rx_phy_ip_err_discards"},
{ Q_STATS_OFFSET32(rx_skb_alloc_failed),
- 4, "[%s]: rx_skb_alloc_discard" },
- { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" },
- { Q_STATS_OFFSET32(driver_xoff), 4, "[%s]: tx_exhaustion_events" },
- { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" },
+ 4, "[%d]: rx_skb_alloc_discard" },
+ { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" },
+ { Q_STATS_OFFSET32(driver_xoff), 4, "[%d]: tx_exhaustion_events" },
+ { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" },
/* 10 */{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
- 8, "[%s]: tx_ucast_packets" },
+ 8, "[%d]: tx_ucast_packets" },
{ Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
- 8, "[%s]: tx_mcast_packets" },
+ 8, "[%d]: tx_mcast_packets" },
{ Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
- 8, "[%s]: tx_bcast_packets" },
+ 8, "[%d]: tx_bcast_packets" },
{ Q_STATS_OFFSET32(total_tpa_aggregations_hi),
- 8, "[%s]: tpa_aggregations" },
+ 8, "[%d]: tpa_aggregations" },
{ Q_STATS_OFFSET32(total_tpa_aggregated_frames_hi),
- 8, "[%s]: tpa_aggregated_frames"},
- { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%s]: tpa_bytes"},
+ 8, "[%d]: tpa_aggregated_frames"},
+ { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%d]: tpa_bytes"},
{ Q_STATS_OFFSET32(driver_filtered_tx_pkt),
- 4, "[%s]: driver_filtered_tx_pkt" }
+ 4, "[%d]: driver_filtered_tx_pkt" }
};
#define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr)
@@ -3184,49 +3184,43 @@ static u32 bnx2x_get_private_flags(struct net_device *dev)
static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnx2x *bp = netdev_priv(dev);
- int i, j, k, start;
- char queue_name[MAX_QUEUE_NAME_LEN+1];
+ const char *str;
+ int i, j, start;
switch (stringset) {
case ETH_SS_STATS:
- k = 0;
if (is_multi(bp)) {
for_each_eth_queue(bp, i) {
- memset(queue_name, 0, sizeof(queue_name));
- snprintf(queue_name, sizeof(queue_name),
- "%d", i);
- for (j = 0; j < BNX2X_NUM_Q_STATS; j++)
- snprintf(buf + (k + j)*ETH_GSTRING_LEN,
- ETH_GSTRING_LEN,
- bnx2x_q_stats_arr[j].string,
- queue_name);
- k += BNX2X_NUM_Q_STATS;
+ for (j = 0; j < BNX2X_NUM_Q_STATS; j++) {
+ str = bnx2x_q_stats_arr[j].string;
+ ethtool_sprintf(&buf, str, i);
+ }
}
}
- for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
+ for (i = 0; i < BNX2X_NUM_STATS; i++) {
if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i))
continue;
- strcpy(buf + (k + j)*ETH_GSTRING_LEN,
- bnx2x_stats_arr[i].string);
- j++;
+ ethtool_puts(&buf, bnx2x_stats_arr[i].string);
}
break;
case ETH_SS_TEST:
+ if (IS_VF(bp))
+ break;
/* First 4 tests cannot be done in MF mode */
if (!IS_MF(bp))
start = 0;
else
start = 4;
- memcpy(buf, bnx2x_tests_str_arr + start,
- ETH_GSTRING_LEN * BNX2X_NUM_TESTS(bp));
+ for (i = start; i < BNX2X_NUM_TESTS_SF; i++)
+ ethtool_puts(&buf, bnx2x_tests_str_arr[i]);
break;
case ETH_SS_PRIV_FLAGS:
- memcpy(buf, bnx2x_private_arr,
- ETH_GSTRING_LEN * BNX2X_PRI_FLAG_LEN);
+ for (i = 0; i < BNX2X_PRI_FLAG_LEN; i++)
+ ethtool_puts(&buf, bnx2x_private_arr[i]);
break;
}
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 6dd6541d8619..4c1302a8f72d 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -864,6 +864,11 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
bnapi->events &= ~BNXT_TX_CMP_EVENT;
}
+static bool bnxt_separate_head_pool(void)
+{
+ return PAGE_SIZE > BNXT_RX_PAGE_SIZE;
+}
+
static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
struct bnxt_rx_ring_info *rxr,
unsigned int *offset,
@@ -886,27 +891,19 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
}
static inline u8 *__bnxt_alloc_rx_frag(struct bnxt *bp, dma_addr_t *mapping,
+ struct bnxt_rx_ring_info *rxr,
gfp_t gfp)
{
- u8 *data;
- struct pci_dev *pdev = bp->pdev;
+ unsigned int offset;
+ struct page *page;
- if (gfp == GFP_ATOMIC)
- data = napi_alloc_frag(bp->rx_buf_size);
- else
- data = netdev_alloc_frag(bp->rx_buf_size);
- if (!data)
+ page = page_pool_alloc_frag(rxr->head_pool, &offset,
+ bp->rx_buf_size, gfp);
+ if (!page)
return NULL;
- *mapping = dma_map_single_attrs(&pdev->dev, data + bp->rx_dma_offset,
- bp->rx_buf_use_size, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
-
- if (dma_mapping_error(&pdev->dev, *mapping)) {
- skb_free_frag(data);
- data = NULL;
- }
- return data;
+ *mapping = page_pool_get_dma_addr(page) + bp->rx_dma_offset + offset;
+ return page_address(page) + offset;
}
int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
@@ -928,7 +925,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
rx_buf->data = page;
rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset;
} else {
- u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, gfp);
+ u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, gfp);
if (!data)
return -ENOMEM;
@@ -1179,13 +1176,14 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp,
}
skb = napi_build_skb(data, bp->rx_buf_size);
- dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
- bp->rx_dir, DMA_ATTR_WEAK_ORDERING);
+ dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
+ bp->rx_dir);
if (!skb) {
- skb_free_frag(data);
+ page_pool_free_va(rxr->head_pool, data, true);
return NULL;
}
+ skb_mark_for_recycle(skb);
skb_reserve(skb, bp->rx_offset);
skb_put(skb, offset_and_len & 0xffff);
return skb;
@@ -1840,7 +1838,8 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
u8 *new_data;
dma_addr_t new_mapping;
- new_data = __bnxt_alloc_rx_frag(bp, &new_mapping, GFP_ATOMIC);
+ new_data = __bnxt_alloc_rx_frag(bp, &new_mapping, rxr,
+ GFP_ATOMIC);
if (!new_data) {
bnxt_abort_tpa(cpr, idx, agg_bufs);
cpr->sw_stats->rx.rx_oom_discards += 1;
@@ -1852,16 +1851,16 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
tpa_info->mapping = new_mapping;
skb = napi_build_skb(data, bp->rx_buf_size);
- dma_unmap_single_attrs(&bp->pdev->dev, mapping,
- bp->rx_buf_use_size, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
+ dma_sync_single_for_cpu(&bp->pdev->dev, mapping,
+ bp->rx_buf_use_size, bp->rx_dir);
if (!skb) {
- skb_free_frag(data);
+ page_pool_free_va(rxr->head_pool, data, true);
bnxt_abort_tpa(cpr, idx, agg_bufs);
cpr->sw_stats->rx.rx_oom_discards += 1;
return NULL;
}
+ skb_mark_for_recycle(skb);
skb_reserve(skb, bp->rx_offset);
skb_put(skb, len);
}
@@ -2254,11 +2253,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) {
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
- unsigned long flags;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- ns = timecounter_cyc2time(&ptp->tc, ts);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ ns = bnxt_timecounter_cyc2time(ptp, ts);
memset(skb_hwtstamps(skb), 0,
sizeof(*skb_hwtstamps(skb)));
skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
@@ -2764,12 +2760,12 @@ static int bnxt_async_event_process(struct bnxt *bp,
if (!ptp)
goto async_event_process_exit;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
bnxt_ptp_update_current_time(bp);
ns = (((u64)BNXT_EVENT_PHC_RTC_UPDATE(data1) <<
BNXT_PHC_BITS) | ptp->current_time);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
bnxt_ptp_rtc_timecounter_init(ptp, ns);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
}
break;
}
@@ -3102,7 +3098,7 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
cpr->rx_packets,
cpr->rx_bytes,
&dim_sample);
- net_dim(&cpr->dim, dim_sample);
+ net_dim(&cpr->dim, &dim_sample);
}
return work_done;
}
@@ -3233,7 +3229,7 @@ poll_done:
cpr_rx->rx_packets,
cpr_rx->rx_bytes,
&dim_sample);
- net_dim(&cpr->dim, dim_sample);
+ net_dim(&cpr->dim, &dim_sample);
}
return work_done;
}
@@ -3311,28 +3307,22 @@ static void bnxt_free_tx_skbs(struct bnxt *bp)
static void bnxt_free_one_rx_ring(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
{
- struct pci_dev *pdev = bp->pdev;
int i, max_idx;
max_idx = bp->rx_nr_pages * RX_DESC_CNT;
for (i = 0; i < max_idx; i++) {
struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[i];
- dma_addr_t mapping = rx_buf->mapping;
void *data = rx_buf->data;
if (!data)
continue;
rx_buf->data = NULL;
- if (BNXT_RX_PAGE_MODE(bp)) {
+ if (BNXT_RX_PAGE_MODE(bp))
page_pool_recycle_direct(rxr->page_pool, data);
- } else {
- dma_unmap_single_attrs(&pdev->dev, mapping,
- bp->rx_buf_use_size, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
- skb_free_frag(data);
- }
+ else
+ page_pool_free_va(rxr->head_pool, data, true);
}
}
@@ -3359,7 +3349,6 @@ static void bnxt_free_one_rx_agg_ring(struct bnxt *bp, struct bnxt_rx_ring_info
static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr)
{
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[ring_nr];
- struct pci_dev *pdev = bp->pdev;
struct bnxt_tpa_idx_map *map;
int i;
@@ -3373,13 +3362,8 @@ static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr)
if (!data)
continue;
- dma_unmap_single_attrs(&pdev->dev, tpa_info->mapping,
- bp->rx_buf_use_size, bp->rx_dir,
- DMA_ATTR_WEAK_ORDERING);
-
tpa_info->data = NULL;
-
- skb_free_frag(data);
+ page_pool_free_va(rxr->head_pool, data, false);
}
skip_rx_tpa_free:
@@ -3595,7 +3579,9 @@ static void bnxt_free_rx_rings(struct bnxt *bp)
xdp_rxq_info_unreg(&rxr->xdp_rxq);
page_pool_destroy(rxr->page_pool);
- rxr->page_pool = NULL;
+ if (rxr->page_pool != rxr->head_pool)
+ page_pool_destroy(rxr->head_pool);
+ rxr->page_pool = rxr->head_pool = NULL;
kfree(rxr->rx_agg_bmap);
rxr->rx_agg_bmap = NULL;
@@ -3613,6 +3599,7 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
int numa_node)
{
struct page_pool_params pp = { 0 };
+ struct page_pool *pool;
pp.pool_size = bp->rx_agg_ring_size;
if (BNXT_RX_PAGE_MODE(bp))
@@ -3625,14 +3612,25 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
pp.max_len = PAGE_SIZE;
pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
- rxr->page_pool = page_pool_create(&pp);
- if (IS_ERR(rxr->page_pool)) {
- int err = PTR_ERR(rxr->page_pool);
+ pool = page_pool_create(&pp);
+ if (IS_ERR(pool))
+ return PTR_ERR(pool);
+ rxr->page_pool = pool;
- rxr->page_pool = NULL;
- return err;
+ if (bnxt_separate_head_pool()) {
+ pp.pool_size = max(bp->rx_ring_size, 1024);
+ pool = page_pool_create(&pp);
+ if (IS_ERR(pool))
+ goto err_destroy_pp;
}
+ rxr->head_pool = pool;
+
return 0;
+
+err_destroy_pp:
+ page_pool_destroy(rxr->page_pool);
+ rxr->page_pool = NULL;
+ return PTR_ERR(pool);
}
static int bnxt_alloc_rx_rings(struct bnxt *bp)
@@ -4183,7 +4181,8 @@ static int bnxt_alloc_one_rx_ring(struct bnxt *bp, int ring_nr)
u8 *data;
for (i = 0; i < bp->max_tpa; i++) {
- data = __bnxt_alloc_rx_frag(bp, &mapping, GFP_KERNEL);
+ data = __bnxt_alloc_rx_frag(bp, &mapping, rxr,
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -10885,7 +10884,7 @@ static void bnxt_free_irq(struct bnxt *bp)
irq = &bp->irq_tbl[map_idx];
if (irq->requested) {
if (irq->have_cpumask) {
- irq_set_affinity_hint(irq->vector, NULL);
+ irq_update_affinity_hint(irq->vector, NULL);
free_cpumask_var(irq->cpu_mask);
irq->have_cpumask = 0;
}
@@ -10940,10 +10939,10 @@ static int bnxt_request_irq(struct bnxt *bp)
irq->have_cpumask = 1;
cpumask_set_cpu(cpumask_local_spread(i, numa_node),
irq->cpu_mask);
- rc = irq_set_affinity_hint(irq->vector, irq->cpu_mask);
+ rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask);
if (rc) {
netdev_warn(bp->dev,
- "Set affinity failed, IRQ = %d\n",
+ "Update affinity hint failed, IRQ = %d\n",
irq->vector);
break;
}
@@ -13496,12 +13495,13 @@ static void bnxt_force_fw_reset(struct bnxt *bp)
test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
return;
+ /* we have to serialize with bnxt_refclk_read()*/
if (ptp) {
unsigned long flags;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
} else {
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
}
@@ -13565,12 +13565,13 @@ void bnxt_fw_reset(struct bnxt *bp)
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
int n = 0, tmo;
+ /* we have to serialize with bnxt_refclk_read()*/
if (ptp) {
unsigned long flags;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
} else {
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 69231e85140b..649955fa3e37 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -1105,6 +1105,7 @@ struct bnxt_rx_ring_info {
struct bnxt_ring_struct rx_agg_ring_struct;
struct xdp_rxq_info xdp_rxq;
struct page_pool *page_pool;
+ struct page_pool *head_pool;
};
struct bnxt_rx_sw_stats {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index f71cc8188b4e..cfd2c65b1c90 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -705,112 +705,105 @@ skip_ring_stats:
static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnxt *bp = netdev_priv(dev);
- static const char * const *str;
u32 i, j, num_str;
+ const char *str;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < bp->cp_nr_rings; i++) {
- if (is_rx_ring(bp, i)) {
- num_str = NUM_RING_RX_HW_STATS;
- for (j = 0; j < num_str; j++) {
- sprintf(buf, "[%d]: %s", i,
- bnxt_ring_rx_stats_str[j]);
- buf += ETH_GSTRING_LEN;
+ if (is_rx_ring(bp, i))
+ for (j = 0; j < NUM_RING_RX_HW_STATS; j++) {
+ str = bnxt_ring_rx_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i,
+ str);
}
- }
- if (is_tx_ring(bp, i)) {
- num_str = NUM_RING_TX_HW_STATS;
- for (j = 0; j < num_str; j++) {
- sprintf(buf, "[%d]: %s", i,
- bnxt_ring_tx_stats_str[j]);
- buf += ETH_GSTRING_LEN;
+ if (is_tx_ring(bp, i))
+ for (j = 0; j < NUM_RING_TX_HW_STATS; j++) {
+ str = bnxt_ring_tx_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i,
+ str);
}
- }
num_str = bnxt_get_num_tpa_ring_stats(bp);
if (!num_str || !is_rx_ring(bp, i))
goto skip_tpa_stats;
if (bp->max_tpa_v2)
- str = bnxt_ring_tpa2_stats_str;
+ for (j = 0; j < num_str; j++) {
+ str = bnxt_ring_tpa2_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i,
+ str);
+ }
else
- str = bnxt_ring_tpa_stats_str;
-
- for (j = 0; j < num_str; j++) {
- sprintf(buf, "[%d]: %s", i, str[j]);
- buf += ETH_GSTRING_LEN;
- }
-skip_tpa_stats:
- if (is_rx_ring(bp, i)) {
- num_str = NUM_RING_RX_SW_STATS;
for (j = 0; j < num_str; j++) {
- sprintf(buf, "[%d]: %s", i,
- bnxt_rx_sw_stats_str[j]);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_ring_tpa_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i,
+ str);
}
+skip_tpa_stats:
+ if (is_rx_ring(bp, i))
+ for (j = 0; j < NUM_RING_RX_SW_STATS; j++) {
+ str = bnxt_rx_sw_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i,
+ str);
+ }
+ for (j = 0; j < NUM_RING_CMN_SW_STATS; j++) {
+ str = bnxt_cmn_sw_stats_str[j];
+ ethtool_sprintf(&buf, "[%d]: %s", i, str);
}
- num_str = NUM_RING_CMN_SW_STATS;
- for (j = 0; j < num_str; j++) {
- sprintf(buf, "[%d]: %s", i,
- bnxt_cmn_sw_stats_str[j]);
- buf += ETH_GSTRING_LEN;
- }
- }
- for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) {
- strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN);
- buf += ETH_GSTRING_LEN;
}
+ for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++)
+ ethtool_puts(&buf, bnxt_ring_err_stats_arr[i]);
- if (bp->flags & BNXT_FLAG_PORT_STATS) {
+ if (bp->flags & BNXT_FLAG_PORT_STATS)
for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
- strcpy(buf, bnxt_port_stats_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_port_stats_arr[i].string;
+ ethtool_puts(&buf, str);
}
- }
+
if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
u32 len;
len = min_t(u32, bp->fw_rx_stats_ext_size,
ARRAY_SIZE(bnxt_port_stats_ext_arr));
for (i = 0; i < len; i++) {
- strcpy(buf, bnxt_port_stats_ext_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_port_stats_ext_arr[i].string;
+ ethtool_puts(&buf, str);
}
+
len = min_t(u32, bp->fw_tx_stats_ext_size,
ARRAY_SIZE(bnxt_tx_port_stats_ext_arr));
for (i = 0; i < len; i++) {
- strcpy(buf,
- bnxt_tx_port_stats_ext_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_tx_port_stats_ext_arr[i].string;
+ ethtool_puts(&buf, str);
}
+
if (bp->pri2cos_valid) {
for (i = 0; i < 8; i++) {
- strcpy(buf,
- bnxt_rx_bytes_pri_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_rx_bytes_pri_arr[i].string;
+ ethtool_puts(&buf, str);
}
+
for (i = 0; i < 8; i++) {
- strcpy(buf,
- bnxt_rx_pkts_pri_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_rx_pkts_pri_arr[i].string;
+ ethtool_puts(&buf, str);
}
+
for (i = 0; i < 8; i++) {
- strcpy(buf,
- bnxt_tx_bytes_pri_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_tx_bytes_pri_arr[i].string;
+ ethtool_puts(&buf, str);
}
+
for (i = 0; i < 8; i++) {
- strcpy(buf,
- bnxt_tx_pkts_pri_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ str = bnxt_tx_pkts_pri_arr[i].string;
+ ethtool_puts(&buf, str);
}
}
}
break;
case ETH_SS_TEST:
if (bp->num_tests)
- memcpy(buf, bp->test_info->string,
- bp->num_tests * ETH_GSTRING_LEN);
+ for (i = 0; i < bp->num_tests; i++)
+ ethtool_puts(&buf, bp->test_info->string[i]);
break;
default:
netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
@@ -1131,14 +1124,15 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
fkeys = &fltr->fkeys;
fmasks = &fltr->fmasks;
if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
- if (fkeys->basic.ip_proto == IPPROTO_ICMP ||
- fkeys->basic.ip_proto == IPPROTO_RAW) {
+ if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) {
fs->flow_type = IP_USER_FLOW;
fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
- if (fkeys->basic.ip_proto == IPPROTO_ICMP)
- fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP;
- else
- fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW;
+ fs->h_u.usr_ip4_spec.proto = BNXT_IP_PROTO_WILDCARD;
+ fs->m_u.usr_ip4_spec.proto = 0;
+ } else if (fkeys->basic.ip_proto == IPPROTO_ICMP) {
+ fs->flow_type = IP_USER_FLOW;
+ fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+ fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP;
fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK;
} else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
fs->flow_type = TCP_V4_FLOW;
@@ -1160,13 +1154,13 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst;
}
} else {
- if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 ||
- fkeys->basic.ip_proto == IPPROTO_RAW) {
+ if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) {
fs->flow_type = IPV6_USER_FLOW;
- if (fkeys->basic.ip_proto == IPPROTO_ICMPV6)
- fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6;
- else
- fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW;
+ fs->h_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_WILDCARD;
+ fs->m_u.usr_ip6_spec.l4_proto = 0;
+ } else if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) {
+ fs->flow_type = IPV6_USER_FLOW;
+ fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6;
fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK;
} else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
fs->flow_type = TCP_V6_FLOW;
@@ -1289,10 +1283,12 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp,
static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec,
struct ethtool_usrip4_spec *ip_mask)
{
+ u8 mproto = ip_mask->proto;
+ u8 sproto = ip_spec->proto;
+
if (ip_mask->l4_4_bytes || ip_mask->tos ||
ip_spec->ip_ver != ETH_RX_NFC_IP4 ||
- ip_mask->proto != BNXT_IP_PROTO_FULL_MASK ||
- (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP))
+ (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMP)))
return false;
return true;
}
@@ -1300,10 +1296,11 @@ static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec,
static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec,
struct ethtool_usrip6_spec *ip_mask)
{
+ u8 mproto = ip_mask->l4_proto;
+ u8 sproto = ip_spec->l4_proto;
+
if (ip_mask->l4_4_bytes || ip_mask->tclass ||
- ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK ||
- (ip_spec->l4_proto != IPPROTO_RAW &&
- ip_spec->l4_proto != IPPROTO_ICMPV6))
+ (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMPV6)))
return false;
return true;
}
@@ -1357,7 +1354,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec;
struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec;
- fkeys->basic.ip_proto = ip_spec->proto;
+ fkeys->basic.ip_proto = ip_mask->proto ? ip_spec->proto
+ : BNXT_IP_PROTO_WILDCARD;
fkeys->basic.n_proto = htons(ETH_P_IP);
fkeys->addrs.v4addrs.src = ip_spec->ip4src;
fmasks->addrs.v4addrs.src = ip_mask->ip4src;
@@ -1388,7 +1386,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec;
struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec;
- fkeys->basic.ip_proto = ip_spec->l4_proto;
+ fkeys->basic.ip_proto = ip_mask->l4_proto ? ip_spec->l4_proto
+ : BNXT_IP_PROTO_WILDCARD;
fkeys->basic.n_proto = htons(ETH_P_IPV6);
fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src;
fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src;
@@ -2781,7 +2780,7 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
static void bnxt_get_default_speeds(struct ethtool_link_ksettings *lk_ksettings,
struct bnxt_link_info *link_info)
{
- struct ethtool_link_settings *base = &lk_ksettings->base;
+ struct ethtool_link_settings_hdr *base = &lk_ksettings->base;
if (link_info->link_state == BNXT_LINK_STATE_UP) {
base->speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
@@ -2800,7 +2799,7 @@ static void bnxt_get_default_speeds(struct ethtool_link_ksettings *lk_ksettings,
static int bnxt_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *lk_ksettings)
{
- struct ethtool_link_settings *base = &lk_ksettings->base;
+ struct ethtool_link_settings_hdr *base = &lk_ksettings->base;
enum ethtool_link_mode_bit_indices link_mode;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info;
@@ -3023,9 +3022,9 @@ u16 bnxt_get_fw_auto_link_speeds(const unsigned long *mode)
static int bnxt_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *lk_ksettings)
{
+ const struct ethtool_link_settings_hdr *base = &lk_ksettings->base;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
- const struct ethtool_link_settings *base = &lk_ksettings->base;
bool set_pause = false;
u32 speed, lanes = 0;
int rc = 0;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
index e2ee030237d4..33b86ede1ce5 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h
@@ -44,6 +44,7 @@ struct bnxt_led_cfg {
#define BNXT_PXP_REG_LEN 0x3110
#define BNXT_IP_PROTO_FULL_MASK 0xFF
+#define BNXT_IP_PROTO_WILDCARD 0x0
extern const struct ethtool_ops bnxt_ethtool_ops;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
index fa514be87650..075ccd589845 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
@@ -67,15 +67,15 @@ static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
if (BNXT_PTP_USE_RTC(ptp->bp))
return bnxt_ptp_cfg_settime(ptp->bp, ns);
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
timecounter_init(&ptp->tc, &ptp->cc, ns);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
return 0;
}
/* Caller holds ptp_lock */
-static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
- u64 *ns)
+static int __bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
+ u64 *ns)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
u32 high_before, high_now, low;
@@ -98,17 +98,50 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
return 0;
}
-static void bnxt_ptp_get_current_time(struct bnxt *bp)
+static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
+ u64 *ns)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
unsigned long flags;
+ int rc;
+
+ /* We have to serialize reg access and FW reset */
+ read_seqlock_excl_irqsave(&ptp->ptp_lock, flags);
+ rc = __bnxt_refclk_read(bp, sts, ns);
+ read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags);
+ return rc;
+}
+
+static int bnxt_refclk_read_low(struct bnxt *bp, struct ptp_system_timestamp *sts,
+ u32 *low)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ unsigned long flags;
+
+ /* We have to serialize reg access and FW reset */
+ read_seqlock_excl_irqsave(&ptp->ptp_lock, flags);
+
+ if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
+ read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags);
+ return -EIO;
+ }
+
+ ptp_read_system_prets(sts);
+ *low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+ ptp_read_system_postts(sts);
+
+ read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags);
+ return 0;
+}
+
+static void bnxt_ptp_get_current_time(struct bnxt *bp)
+{
+ struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
if (!ptp)
return;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- WRITE_ONCE(ptp->old_time, ptp->current_time);
+ WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT);
bnxt_refclk_read(bp, NULL, &ptp->current_time);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
}
static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts,
@@ -151,36 +184,32 @@ static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
{
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
ptp_info);
- unsigned long flags;
u64 ns, cycles;
+ u32 low;
int rc;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- rc = bnxt_refclk_read(ptp->bp, sts, &cycles);
- if (rc) {
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ rc = bnxt_refclk_read_low(ptp->bp, sts, &low);
+ if (rc)
return rc;
- }
- ns = timecounter_cyc2time(&ptp->tc, cycles);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+
+ cycles = bnxt_extend_cycles_32b_to_48b(ptp, low);
+ ns = bnxt_timecounter_cyc2time(ptp, cycles);
*ts = ns_to_timespec64(ns);
return 0;
}
-/* Caller holds ptp_lock */
void bnxt_ptp_update_current_time(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
bnxt_refclk_read(ptp->bp, NULL, &ptp->current_time);
- WRITE_ONCE(ptp->old_time, ptp->current_time);
+ WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT);
}
static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
{
struct hwrm_port_mac_cfg_input *req;
- unsigned long flags;
int rc;
rc = hwrm_req_init(ptp->bp, req, HWRM_PORT_MAC_CFG);
@@ -194,9 +223,7 @@ static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
if (rc) {
netdev_err(ptp->bp->dev, "ptp adjphc failed. rc = %x\n", rc);
} else {
- spin_lock_irqsave(&ptp->ptp_lock, flags);
bnxt_ptp_update_current_time(ptp->bp);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
}
return rc;
@@ -211,9 +238,9 @@ static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
if (BNXT_PTP_USE_RTC(ptp->bp))
return bnxt_ptp_adjphc(ptp, delta);
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
timecounter_adjtime(&ptp->tc, delta);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
return 0;
}
@@ -246,10 +273,10 @@ static int bnxt_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
if (!BNXT_MH(bp))
return bnxt_ptp_adjfine_rtc(bp, scaled_ppm);
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
timecounter_read(&ptp->tc);
ptp->cc.mult = adjust_by_scaled_ppm(ptp->cmult, scaled_ppm);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
return 0;
}
@@ -257,13 +284,10 @@ void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct ptp_clock_event event;
- unsigned long flags;
u64 ns, pps_ts;
pps_ts = EVENT_PPS_TS(data2, data1);
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- ns = timecounter_cyc2time(&ptp->tc, pps_ts);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ ns = bnxt_timecounter_cyc2time(ptp, pps_ts);
switch (EVENT_DATA2_PPS_EVENT_TYPE(data2)) {
case ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_INTERNAL:
@@ -400,17 +424,13 @@ static int bnxt_get_target_cycles(struct bnxt_ptp_cfg *ptp, u64 target_ns,
{
u64 cycles_now;
u64 nsec_now, nsec_delta;
- unsigned long flags;
int rc;
- spin_lock_irqsave(&ptp->ptp_lock, flags);
rc = bnxt_refclk_read(ptp->bp, NULL, &cycles_now);
- if (rc) {
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ if (rc)
return rc;
- }
- nsec_now = timecounter_cyc2time(&ptp->tc, cycles_now);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+
+ nsec_now = bnxt_timecounter_cyc2time(ptp, cycles_now);
nsec_delta = target_ns - nsec_now;
*cycles_delta = div64_u64(nsec_delta << ptp->cc.shift, ptp->cc.mult);
@@ -687,7 +707,7 @@ static u64 bnxt_cc_read(const struct cyclecounter *cc)
struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc);
u64 ns = 0;
- bnxt_refclk_read(ptp->bp, NULL, &ns);
+ __bnxt_refclk_read(ptp->bp, NULL, &ns);
return ns;
}
@@ -697,7 +717,6 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot)
struct skb_shared_hwtstamps timestamp;
struct bnxt_ptp_tx_req *txts_req;
unsigned long now = jiffies;
- unsigned long flags;
u64 ts = 0, ns = 0;
u32 tmo = 0;
int rc;
@@ -711,9 +730,7 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot)
tmo, slot);
if (!rc) {
memset(&timestamp, 0, sizeof(timestamp));
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- ns = timecounter_cyc2time(&ptp->tc, ts);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ ns = bnxt_timecounter_cyc2time(ptp, ts);
timestamp.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(txts_req->tx_skb, &timestamp);
ptp->stats.ts_pkts++;
@@ -767,9 +784,9 @@ next_slot:
bnxt_ptp_get_current_time(bp);
ptp->next_period = now + HZ;
if (time_after_eq(now, ptp->next_overflow_check)) {
- spin_lock_irqsave(&ptp->ptp_lock, flags);
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
timecounter_read(&ptp->tc);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD;
}
if (rc == -EAGAIN)
@@ -808,15 +825,11 @@ void bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb, u16 prod)
int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
- u64 time;
if (!ptp)
return -ENODEV;
- BNXT_READ_TIME64(ptp, time, ptp->old_time);
- *ts = (time & BNXT_HI_TIMER_MASK) | pkt_ts;
- if (pkt_ts < (time & BNXT_LO_TIMER_MASK))
- *ts += BNXT_LO_TIMER_MASK + 1;
+ *ts = bnxt_extend_cycles_32b_to_48b(ptp, pkt_ts);
return 0;
}
@@ -829,7 +842,6 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi,
u32 opaque = tscmp->tx_ts_cmp_opaque;
struct bnxt_tx_ring_info *txr;
struct bnxt_sw_tx_bd *tx_buf;
- unsigned long flags;
u64 ts, ns;
u16 cons;
@@ -844,9 +856,7 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi,
le32_to_cpu(tscmp->tx_ts_cmp_flags_type),
le32_to_cpu(tscmp->tx_ts_cmp_errors_v));
} else {
- spin_lock_irqsave(&ptp->ptp_lock, flags);
- ns = timecounter_cyc2time(&ptp->tc, ts);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ ns = bnxt_timecounter_cyc2time(ptp, ts);
timestamp.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(tx_buf->skb, &timestamp);
}
@@ -955,6 +965,7 @@ static bool bnxt_pps_config_ok(struct bnxt *bp)
static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+ unsigned long flags;
if (!ptp->ptp_clock) {
memset(&ptp->cc, 0, sizeof(ptp->cc));
@@ -971,8 +982,11 @@ static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc)
}
ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
}
- if (init_tc)
+ if (init_tc) {
+ write_seqlock_irqsave(&ptp->ptp_lock, flags);
timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
+ write_sequnlock_irqrestore(&ptp->ptp_lock, flags);
+ }
}
/* Caller holds ptp_lock */
@@ -1005,9 +1019,9 @@ int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg)
if (rc)
return rc;
}
- spin_lock_irqsave(&bp->ptp_cfg->ptp_lock, flags);
+ write_seqlock_irqsave(&bp->ptp_cfg->ptp_lock, flags);
bnxt_ptp_rtc_timecounter_init(bp->ptp_cfg, ns);
- spin_unlock_irqrestore(&bp->ptp_cfg->ptp_lock, flags);
+ write_sequnlock_irqrestore(&bp->ptp_cfg->ptp_lock, flags);
return 0;
}
@@ -1042,7 +1056,7 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
bnxt_ptp_free(bp);
WRITE_ONCE(ptp->tx_avail, BNXT_MAX_TX_TS);
- spin_lock_init(&ptp->ptp_lock);
+ seqlock_init(&ptp->ptp_lock);
spin_lock_init(&ptp->ptp_tx_lock);
if (BNXT_PTP_USE_RTC(bp)) {
@@ -1075,12 +1089,8 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
atomic64_set(&ptp->stats.ts_err, 0);
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
- unsigned long flags;
-
- spin_lock_irqsave(&ptp->ptp_lock, flags);
bnxt_refclk_read(bp, NULL, &ptp->current_time);
- WRITE_ONCE(ptp->old_time, ptp->current_time);
- spin_unlock_irqrestore(&ptp->ptp_lock, flags);
+ WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT);
ptp_schedule_worker(ptp->ptp_clock, 0);
}
ptp->txts_tmo = BNXT_PTP_DFLT_TX_TMO;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
index f322466ecad3..c7851f8c971c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
@@ -21,6 +21,7 @@
#define BNXT_DEVCLK_FREQ 1000000
#define BNXT_LO_TIMER_MASK 0x0000ffffffffUL
#define BNXT_HI_TIMER_MASK 0xffff00000000UL
+#define BNXT_HI_TIMER_SHIFT 24
#define BNXT_PTP_DFLT_TX_TMO 1000 /* ms */
#define BNXT_PTP_QTS_TIMEOUT 1000
@@ -102,14 +103,15 @@ struct bnxt_ptp_cfg {
struct timecounter tc;
struct bnxt_pps pps_info;
/* serialize timecounter access */
- spinlock_t ptp_lock;
+ seqlock_t ptp_lock;
/* serialize ts tx request queuing */
spinlock_t ptp_tx_lock;
u64 current_time;
- u64 old_time;
unsigned long next_period;
unsigned long next_overflow_check;
u32 cmult;
+ /* cache of upper 24 bits of cyclecoutner. 8 bits are used to check for roll-over */
+ u32 old_time;
/* a 23b shift cyclecounter will overflow in ~36 mins. Check overflow every 18 mins. */
#define BNXT_PHC_OVERFLOW_PERIOD (18 * 60 * HZ)
@@ -145,20 +147,6 @@ struct bnxt_ptp_cfg {
struct bnxt_ptp_stats stats;
};
-#if BITS_PER_LONG == 32
-#define BNXT_READ_TIME64(ptp, dst, src) \
-do { \
- unsigned long flags; \
- \
- spin_lock_irqsave(&(ptp)->ptp_lock, flags); \
- (dst) = (src); \
- spin_unlock_irqrestore(&(ptp)->ptp_lock, flags); \
-} while (0)
-#else
-#define BNXT_READ_TIME64(ptp, dst, src) \
- ((dst) = READ_ONCE(src))
-#endif
-
#define BNXT_PTP_INC_TX_AVAIL(ptp) \
do { \
spin_lock_bh(&(ptp)->ptp_tx_lock); \
@@ -182,4 +170,27 @@ void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns);
int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg);
int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg);
void bnxt_ptp_clear(struct bnxt *bp);
+static inline u64 bnxt_timecounter_cyc2time(struct bnxt_ptp_cfg *ptp, u64 ts)
+{
+ unsigned int seq;
+ u64 ns;
+
+ do {
+ seq = read_seqbegin(&ptp->ptp_lock);
+ ns = timecounter_cyc2time(&ptp->tc, ts);
+ } while (read_seqretry(&ptp->ptp_lock, seq));
+
+ return ns;
+}
+
+static inline u64 bnxt_extend_cycles_32b_to_48b(struct bnxt_ptp_cfg *ptp, u32 ts)
+{
+ u64 time, cycles;
+
+ time = (u64)READ_ONCE(ptp->old_time) << BNXT_HI_TIMER_SHIFT;
+ cycles = (time & BNXT_HI_TIMER_MASK) | ts;
+ if (ts < (time & BNXT_LO_TIMER_MASK))
+ cycles += BNXT_LO_TIMER_MASK + 1;
+ return cycles;
+}
#endif
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 10966ab15373..3e93f957430b 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1144,14 +1144,14 @@ static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
static void bcmgenet_get_strings(struct net_device *dev, u32 stringset,
u8 *data)
{
+ const char *str;
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < BCMGENET_STATS_LEN; i++) {
- memcpy(data + i * ETH_GSTRING_LEN,
- bcmgenet_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
+ str = bcmgenet_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
break;
}
@@ -2405,7 +2405,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget)
if (ring->dim.use_dim) {
dim_update_sample(ring->dim.event_ctr, ring->dim.packets,
ring->dim.bytes, &dim_sample);
- net_dim(&ring->dim.dim, dim_sample);
+ net_dim(&ring->dim.dim, &dim_sample);
}
return work_done;
diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index 10b1e534030e..4396997c59d0 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -351,7 +351,6 @@ struct bnad {
/* debugfs specific data */
char *regdata;
u32 reglen;
- struct dentry *bnad_dentry_files[5];
struct dentry *port_debugfs_root;
};
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
index 97291bfbeea5..8f0972e6737c 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -500,11 +500,6 @@ bnad_debugfs_init(struct bnad *bnad)
if (!bna_debugfs_root) {
bna_debugfs_root = debugfs_create_dir("bna", NULL);
atomic_set(&bna_debugfs_port_count, 0);
- if (!bna_debugfs_root) {
- netdev_warn(bnad->netdev,
- "debugfs root dir creation failed\n");
- return;
- }
}
/* Setup the pci_dev debugfs directory for the port */
@@ -517,18 +512,11 @@ bnad_debugfs_init(struct bnad *bnad)
for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
file = &bnad_debugfs_files[i];
- bnad->bnad_dentry_files[i] =
- debugfs_create_file(file->name,
- file->mode,
- bnad->port_debugfs_root,
- bnad,
- file->fops);
- if (!bnad->bnad_dentry_files[i]) {
- netdev_warn(bnad->netdev,
- "create %s entry failed\n",
- file->name);
- return;
- }
+ debugfs_create_file(file->name,
+ file->mode,
+ bnad->port_debugfs_root,
+ bnad,
+ file->fops);
}
}
}
@@ -537,15 +525,6 @@ bnad_debugfs_init(struct bnad *bnad)
void
bnad_debugfs_uninit(struct bnad *bnad)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) {
- if (bnad->bnad_dentry_files[i]) {
- debugfs_remove(bnad->bnad_dentry_files[i]);
- bnad->bnad_dentry_files[i] = NULL;
- }
- }
-
/* Remove the pci_dev debugfs directory for the port */
if (bnad->port_debugfs_root) {
debugfs_remove(bnad->port_debugfs_root);
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index ebe886b98891..daa416fb1724 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -915,20 +915,15 @@ static int macb_mii_probe(struct net_device *dev)
return 0;
}
-static int macb_mdiobus_register(struct macb *bp)
+static int macb_mdiobus_register(struct macb *bp, struct device_node *mdio_np)
{
struct device_node *child, *np = bp->pdev->dev.of_node;
/* If we have a child named mdio, probe it instead of looking for PHYs
* directly under the MAC node
*/
- child = of_get_child_by_name(np, "mdio");
- if (child) {
- int ret = of_mdiobus_register(bp->mii_bus, child);
-
- of_node_put(child);
- return ret;
- }
+ if (mdio_np)
+ return of_mdiobus_register(bp->mii_bus, mdio_np);
/* Only create the PHY from the device tree if at least one PHY is
* described. Otherwise scan the entire MDIO bus. We do this to support
@@ -950,17 +945,15 @@ static int macb_mdiobus_register(struct macb *bp)
static int macb_mii_init(struct macb *bp)
{
- struct device_node *child, *np = bp->pdev->dev.of_node;
+ struct device_node *mdio_np, *np = bp->pdev->dev.of_node;
int err = -ENXIO;
/* With fixed-link, we don't need to register the MDIO bus,
* except if we have a child named "mdio" in the device tree.
* In that case, some devices may be attached to the MACB's MDIO bus.
*/
- child = of_get_child_by_name(np, "mdio");
- if (child)
- of_node_put(child);
- else if (of_phy_is_fixed_link(np))
+ mdio_np = of_get_child_by_name(np, "mdio");
+ if (!mdio_np && of_phy_is_fixed_link(np))
return macb_mii_probe(bp->dev);
/* Enable management port */
@@ -984,7 +977,7 @@ static int macb_mii_init(struct macb *bp)
dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
- err = macb_mdiobus_register(bp);
+ err = macb_mdiobus_register(bp, mdio_np);
if (err)
goto err_out_free_mdiobus;
@@ -999,6 +992,8 @@ err_out_unregister_bus:
err_out_free_mdiobus:
mdiobus_free(bp->mii_bus);
err_out:
+ of_node_put(mdio_np);
+
return err;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
index 7f3f5afa864f..45d28a65347e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
@@ -662,8 +662,8 @@ static unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask)
static int get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *link_ksettings)
{
+ struct ethtool_link_settings_hdr *base = &link_ksettings->base;
struct port_info *pi = netdev_priv(dev);
- struct ethtool_link_settings *base = &link_ksettings->base;
/* For the nonce, the Firmware doesn't send up Port State changes
* when the Virtual Interface attached to the Port is down. So
@@ -717,9 +717,9 @@ static int get_link_ksettings(struct net_device *dev,
static int set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *link_ksettings)
{
+ const struct ethtool_link_settings_hdr *base = &link_ksettings->base;
struct port_info *pi = netdev_priv(dev);
struct link_config *lc = &pi->link_cfg;
- const struct ethtool_link_settings *base = &link_ksettings->base;
struct link_config old_lc;
unsigned int fw_caps;
int ret = 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 2fbe0f059a0b..61d08547e3f9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -1436,8 +1436,8 @@ static void fw_caps_to_lmm(enum fw_port_type port_type,
static int cxgb4vf_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *link_ksettings)
{
+ struct ethtool_link_settings_hdr *base = &link_ksettings->base;
struct port_info *pi = netdev_priv(dev);
- struct ethtool_link_settings *base = &link_ksettings->base;
/* For the nonce, the Firmware doesn't send up Port State changes
* when the Virtual Interface attached to the Port is down. So
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 0cc3644ee855..10b7e02ba4d0 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -23,10 +23,8 @@
#define ENIC_BARS_MAX 6
-#define ENIC_WQ_MAX 8
-#define ENIC_RQ_MAX 8
-#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX)
-#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2)
+#define ENIC_WQ_MAX 256
+#define ENIC_RQ_MAX 256
#define ENIC_WQ_NAPI_BUDGET 256
@@ -162,6 +160,17 @@ struct enic_rq_stats {
u64 desc_skip; /* Rx pkt went into later buffer */
};
+struct enic_wq {
+ spinlock_t lock; /* spinlock for wq */
+ struct vnic_wq vwq;
+ struct enic_wq_stats stats;
+} ____cacheline_aligned;
+
+struct enic_rq {
+ struct vnic_rq vrq;
+ struct enic_rq_stats stats;
+} ____cacheline_aligned;
+
/* Per-instance private data structure */
struct enic {
struct net_device *netdev;
@@ -173,8 +182,8 @@ struct enic {
struct work_struct reset;
struct work_struct tx_hang_reset;
struct work_struct change_mtu_work;
- struct msix_entry msix_entry[ENIC_INTR_MAX];
- struct enic_msix_entry msix[ENIC_INTR_MAX];
+ struct msix_entry *msix_entry;
+ struct enic_msix_entry *msix;
u32 msg_enable;
spinlock_t devcmd_lock;
u8 mac_addr[ETH_ALEN];
@@ -193,28 +202,25 @@ struct enic {
bool enic_api_busy;
struct enic_port_profile *pp;
- /* work queue cache line section */
- ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
- spinlock_t wq_lock[ENIC_WQ_MAX];
- struct enic_wq_stats wq_stats[ENIC_WQ_MAX];
+ struct enic_wq *wq;
+ unsigned int wq_avail;
unsigned int wq_count;
u16 loop_enable;
u16 loop_tag;
- /* receive queue cache line section */
- ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
- struct enic_rq_stats rq_stats[ENIC_RQ_MAX];
+ struct enic_rq *rq;
+ unsigned int rq_avail;
unsigned int rq_count;
struct vxlan_offload vxlan;
- struct napi_struct napi[ENIC_RQ_MAX + ENIC_WQ_MAX];
+ struct napi_struct *napi;
- /* interrupt resource cache line section */
- ____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX];
+ struct vnic_intr *intr;
+ unsigned int intr_avail;
unsigned int intr_count;
u32 __iomem *legacy_pba; /* memory-mapped */
- /* completion queue cache line section */
- ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
+ struct vnic_cq *cq;
+ unsigned int cq_avail;
unsigned int cq_count;
struct enic_rfs_flw_tbl rfs_h;
u32 rx_copybreak;
@@ -272,18 +278,28 @@ static inline unsigned int enic_msix_wq_intr(struct enic *enic,
return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
}
-static inline unsigned int enic_msix_err_intr(struct enic *enic)
-{
- return enic->rq_count + enic->wq_count;
-}
+/* MSIX interrupts are organized as the error interrupt, then the notify
+ * interrupt followed by all the I/O interrupts. The error interrupt needs
+ * to fit in 7 bits due to hardware constraints
+ */
+#define ENIC_MSIX_RESERVED_INTR 2
+#define ENIC_MSIX_ERR_INTR 0
+#define ENIC_MSIX_NOTIFY_INTR 1
+#define ENIC_MSIX_IO_INTR_BASE ENIC_MSIX_RESERVED_INTR
+#define ENIC_MSIX_MIN_INTR (ENIC_MSIX_RESERVED_INTR + 2)
#define ENIC_LEGACY_IO_INTR 0
#define ENIC_LEGACY_ERR_INTR 1
#define ENIC_LEGACY_NOTIFY_INTR 2
+static inline unsigned int enic_msix_err_intr(struct enic *enic)
+{
+ return ENIC_MSIX_ERR_INTR;
+}
+
static inline unsigned int enic_msix_notify_intr(struct enic *enic)
{
- return enic->rq_count + enic->wq_count + 1;
+ return ENIC_MSIX_NOTIFY_INTR;
}
static inline bool enic_is_err_intr(struct enic *enic, int intr)
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index f7986f2b6a17..95b071153fed 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -129,8 +129,8 @@ static void enic_intr_coal_set_rx(struct enic *enic, u32 timer)
static int enic_get_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *ecmd)
{
+ struct ethtool_link_settings_hdr *base = &ecmd->base;
struct enic *enic = netdev_priv(netdev);
- struct ethtool_link_settings *base = &ecmd->base;
ethtool_link_ksettings_add_link_mode(ecmd, supported,
10000baseT_Full);
@@ -337,7 +337,7 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
for (i = 0; i < NUM_ENIC_GEN_STATS; i++)
*(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index];
for (i = 0; i < enic->rq_count; i++) {
- struct enic_rq_stats *rqstats = &enic->rq_stats[i];
+ struct enic_rq_stats *rqstats = &enic->rq[i].stats;
int index;
for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) {
@@ -346,7 +346,7 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
}
}
for (i = 0; i < enic->wq_count; i++) {
- struct enic_wq_stats *wqstats = &enic->wq_stats[i];
+ struct enic_wq_stats *wqstats = &enic->wq[i].stats;
int index;
for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) {
@@ -695,8 +695,8 @@ static void enic_get_channels(struct net_device *netdev,
switch (vnic_dev_get_intr_mode(enic->vdev)) {
case VNIC_DEV_INTR_MODE_MSIX:
- channels->max_rx = ENIC_RQ_MAX;
- channels->max_tx = ENIC_WQ_MAX;
+ channels->max_rx = min(enic->rq_avail, ENIC_RQ_MAX);
+ channels->max_tx = min(enic->wq_avail, ENIC_WQ_MAX);
channels->rx_count = enic->rq_count;
channels->tx_count = enic->wq_count;
break;
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index ffed14b63d41..9913952ccb42 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -342,8 +342,8 @@ static void enic_wq_free_buf(struct vnic_wq *wq,
{
struct enic *enic = vnic_dev_priv(wq->vdev);
- enic->wq_stats[wq->index].cq_work++;
- enic->wq_stats[wq->index].cq_bytes += buf->len;
+ enic->wq[wq->index].stats.cq_work++;
+ enic->wq[wq->index].stats.cq_bytes += buf->len;
enic_free_wq_buf(wq, buf);
}
@@ -352,20 +352,20 @@ static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
{
struct enic *enic = vnic_dev_priv(vdev);
- spin_lock(&enic->wq_lock[q_number]);
+ spin_lock(&enic->wq[q_number].lock);
- vnic_wq_service(&enic->wq[q_number], cq_desc,
+ vnic_wq_service(&enic->wq[q_number].vwq, cq_desc,
completed_index, enic_wq_free_buf,
opaque);
if (netif_tx_queue_stopped(netdev_get_tx_queue(enic->netdev, q_number)) &&
- vnic_wq_desc_avail(&enic->wq[q_number]) >=
+ vnic_wq_desc_avail(&enic->wq[q_number].vwq) >=
(MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)) {
netif_wake_subqueue(enic->netdev, q_number);
- enic->wq_stats[q_number].wake++;
+ enic->wq[q_number].stats.wake++;
}
- spin_unlock(&enic->wq_lock[q_number]);
+ spin_unlock(&enic->wq[q_number].lock);
return 0;
}
@@ -377,7 +377,7 @@ static bool enic_log_q_error(struct enic *enic)
bool err = false;
for (i = 0; i < enic->wq_count; i++) {
- error_status = vnic_wq_error_status(&enic->wq[i]);
+ error_status = vnic_wq_error_status(&enic->wq[i].vwq);
err |= error_status;
if (error_status)
netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
@@ -385,7 +385,7 @@ static bool enic_log_q_error(struct enic *enic)
}
for (i = 0; i < enic->rq_count; i++) {
- error_status = vnic_rq_error_status(&enic->rq[i]);
+ error_status = vnic_rq_error_status(&enic->rq[i].vrq);
err |= error_status;
if (error_status)
netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
@@ -598,9 +598,9 @@ static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq,
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
/* The enic_queue_wq_desc() above does not do HW checksum */
- enic->wq_stats[wq->index].csum_none++;
- enic->wq_stats[wq->index].packets++;
- enic->wq_stats[wq->index].bytes += skb->len;
+ enic->wq[wq->index].stats.csum_none++;
+ enic->wq[wq->index].stats.packets++;
+ enic->wq[wq->index].stats.bytes += skb->len;
return err;
}
@@ -634,9 +634,9 @@ static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
if (!eop)
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
- enic->wq_stats[wq->index].csum_partial++;
- enic->wq_stats[wq->index].packets++;
- enic->wq_stats[wq->index].bytes += skb->len;
+ enic->wq[wq->index].stats.csum_partial++;
+ enic->wq[wq->index].stats.packets++;
+ enic->wq[wq->index].stats.bytes += skb->len;
return err;
}
@@ -699,11 +699,11 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
if (skb->encapsulation) {
hdr_len = skb_inner_tcp_all_headers(skb);
enic_preload_tcp_csum_encap(skb);
- enic->wq_stats[wq->index].encap_tso++;
+ enic->wq[wq->index].stats.encap_tso++;
} else {
hdr_len = skb_tcp_all_headers(skb);
enic_preload_tcp_csum(skb);
- enic->wq_stats[wq->index].tso++;
+ enic->wq[wq->index].stats.tso++;
}
/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
@@ -757,8 +757,8 @@ tso_out_stats:
pkts = len / mss;
if ((len % mss) > 0)
pkts++;
- enic->wq_stats[wq->index].packets += pkts;
- enic->wq_stats[wq->index].bytes += (len + (pkts * hdr_len));
+ enic->wq[wq->index].stats.packets += pkts;
+ enic->wq[wq->index].stats.bytes += (len + (pkts * hdr_len));
return 0;
}
@@ -792,9 +792,9 @@ static inline int enic_queue_wq_skb_encap(struct enic *enic, struct vnic_wq *wq,
if (!eop)
err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
- enic->wq_stats[wq->index].encap_csum++;
- enic->wq_stats[wq->index].packets++;
- enic->wq_stats[wq->index].bytes += skb->len;
+ enic->wq[wq->index].stats.encap_csum++;
+ enic->wq[wq->index].stats.packets++;
+ enic->wq[wq->index].stats.bytes += skb->len;
return err;
}
@@ -812,7 +812,7 @@ static inline int enic_queue_wq_skb(struct enic *enic,
/* VLAN tag from trunking driver */
vlan_tag_insert = 1;
vlan_tag = skb_vlan_tag_get(skb);
- enic->wq_stats[wq->index].add_vlan++;
+ enic->wq[wq->index].stats.add_vlan++;
} else if (enic->loop_enable) {
vlan_tag = enic->loop_tag;
loopback = 1;
@@ -859,11 +859,11 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
txq_map = skb_get_queue_mapping(skb) % enic->wq_count;
- wq = &enic->wq[txq_map];
+ wq = &enic->wq[txq_map].vwq;
if (skb->len <= 0) {
dev_kfree_skb_any(skb);
- enic->wq_stats[wq->index].null_pkt++;
+ enic->wq[wq->index].stats.null_pkt++;
return NETDEV_TX_OK;
}
@@ -878,19 +878,19 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC &&
skb_linearize(skb)) {
dev_kfree_skb_any(skb);
- enic->wq_stats[wq->index].skb_linear_fail++;
+ enic->wq[wq->index].stats.skb_linear_fail++;
return NETDEV_TX_OK;
}
- spin_lock(&enic->wq_lock[txq_map]);
+ spin_lock(&enic->wq[txq_map].lock);
if (vnic_wq_desc_avail(wq) <
skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) {
netif_tx_stop_queue(txq);
/* This is a hard error, log it */
netdev_err(netdev, "BUG! Tx ring full when queue awake!\n");
- spin_unlock(&enic->wq_lock[txq_map]);
- enic->wq_stats[wq->index].desc_full_awake++;
+ spin_unlock(&enic->wq[txq_map].lock);
+ enic->wq[wq->index].stats.desc_full_awake++;
return NETDEV_TX_BUSY;
}
@@ -899,14 +899,14 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS) {
netif_tx_stop_queue(txq);
- enic->wq_stats[wq->index].stopped++;
+ enic->wq[wq->index].stats.stopped++;
}
skb_tx_timestamp(skb);
if (!netdev_xmit_more() || netif_xmit_stopped(txq))
vnic_wq_doorbell(wq);
error:
- spin_unlock(&enic->wq_lock[txq_map]);
+ spin_unlock(&enic->wq[txq_map].lock);
return NETDEV_TX_OK;
}
@@ -940,10 +940,10 @@ static void enic_get_stats(struct net_device *netdev,
net_stats->rx_errors = stats->rx.rx_errors;
net_stats->multicast = stats->rx.rx_multicast_frames_ok;
- for (i = 0; i < ENIC_RQ_MAX; i++) {
- struct enic_rq_stats *rqs = &enic->rq_stats[i];
+ for (i = 0; i < enic->rq_count; i++) {
+ struct enic_rq_stats *rqs = &enic->rq[i].stats;
- if (!enic->rq->ctrl)
+ if (!enic->rq[i].vrq.ctrl)
break;
pkt_truncated += rqs->pkt_truncated;
bad_fcs += rqs->bad_fcs;
@@ -1313,7 +1313,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
}
skb = netdev_alloc_skb_ip_align(netdev, len);
if (!skb) {
- enic->rq_stats[rq->index].no_skb++;
+ enic->rq[rq->index].stats.no_skb++;
return -ENOMEM;
}
@@ -1366,7 +1366,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
struct net_device *netdev = enic->netdev;
struct sk_buff *skb;
struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
- struct enic_rq_stats *rqstats = &enic->rq_stats[rq->index];
+ struct enic_rq_stats *rqstats = &enic->rq[rq->index].stats;
u8 type, color, eop, sop, ingress_port, vlan_stripped;
u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
@@ -1512,7 +1512,7 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
{
struct enic *enic = vnic_dev_priv(vdev);
- vnic_rq_service(&enic->rq[q_number], cq_desc,
+ vnic_rq_service(&enic->rq[q_number].vrq, cq_desc,
completed_index, VNIC_RQ_RETURN_DESC,
enic_rq_indicate_buf, opaque);
@@ -1609,7 +1609,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
- err = vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
+ err = vnic_rq_fill(&enic->rq[0].vrq, enic_rq_alloc_buf);
/* Buffer allocation failed. Stay in polling
* mode so we can try to fill the ring again.
@@ -1621,7 +1621,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
/* Call the function which refreshes the intr coalescing timer
* value based on the traffic.
*/
- enic_calc_int_moderation(enic, &enic->rq[0]);
+ enic_calc_int_moderation(enic, &enic->rq[0].vrq);
if ((rq_work_done < budget) && napi_complete_done(napi, rq_work_done)) {
@@ -1630,11 +1630,11 @@ static int enic_poll(struct napi_struct *napi, int budget)
*/
if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
- enic_set_int_moderation(enic, &enic->rq[0]);
+ enic_set_int_moderation(enic, &enic->rq[0].vrq);
vnic_intr_unmask(&enic->intr[intr]);
- enic->rq_stats[0].napi_complete++;
+ enic->rq[0].stats.napi_complete++;
} else {
- enic->rq_stats[0].napi_repoll++;
+ enic->rq[0].stats.napi_repoll++;
}
return rq_work_done;
@@ -1683,7 +1683,7 @@ static int enic_poll_msix_wq(struct napi_struct *napi, int budget)
struct net_device *netdev = napi->dev;
struct enic *enic = netdev_priv(netdev);
unsigned int wq_index = (napi - &enic->napi[0]) - enic->rq_count;
- struct vnic_wq *wq = &enic->wq[wq_index];
+ struct vnic_wq *wq = &enic->wq[wq_index].vwq;
unsigned int cq;
unsigned int intr;
unsigned int wq_work_to_do = ENIC_WQ_NAPI_BUDGET;
@@ -1737,7 +1737,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
0 /* don't unmask intr */,
0 /* don't reset intr timer */);
- err = vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf);
+ err = vnic_rq_fill(&enic->rq[rq].vrq, enic_rq_alloc_buf);
/* Buffer allocation failed. Stay in polling mode
* so we can try to fill the ring again.
@@ -1749,7 +1749,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
/* Call the function which refreshes the intr coalescing timer
* value based on the traffic.
*/
- enic_calc_int_moderation(enic, &enic->rq[rq]);
+ enic_calc_int_moderation(enic, &enic->rq[rq].vrq);
if ((work_done < budget) && napi_complete_done(napi, work_done)) {
@@ -1758,11 +1758,11 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
*/
if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
- enic_set_int_moderation(enic, &enic->rq[rq]);
+ enic_set_int_moderation(enic, &enic->rq[rq].vrq);
vnic_intr_unmask(&enic->intr[intr]);
- enic->rq_stats[rq].napi_complete++;
+ enic->rq[rq].stats.napi_complete++;
} else {
- enic->rq_stats[rq].napi_repoll++;
+ enic->rq[rq].stats.napi_repoll++;
}
return work_done;
@@ -1792,7 +1792,7 @@ static void enic_free_intr(struct enic *enic)
free_irq(enic->pdev->irq, enic);
break;
case VNIC_DEV_INTR_MODE_MSIX:
- for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
+ for (i = 0; i < enic->intr_count; i++)
if (enic->msix[i].requested)
free_irq(enic->msix_entry[i].vector,
enic->msix[i].devid);
@@ -1859,7 +1859,7 @@ static int enic_request_intr(struct enic *enic)
enic->msix[intr].isr = enic_isr_msix_notify;
enic->msix[intr].devid = enic;
- for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
+ for (i = 0; i < enic->intr_count; i++)
enic->msix[i].requested = 0;
for (i = 0; i < enic->intr_count; i++) {
@@ -1989,10 +1989,10 @@ static int enic_open(struct net_device *netdev)
for (i = 0; i < enic->rq_count; i++) {
/* enable rq before updating rq desc */
- vnic_rq_enable(&enic->rq[i]);
- vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
+ vnic_rq_enable(&enic->rq[i].vrq);
+ vnic_rq_fill(&enic->rq[i].vrq, enic_rq_alloc_buf);
/* Need at least one buffer on ring to get going */
- if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
+ if (vnic_rq_desc_used(&enic->rq[i].vrq) == 0) {
netdev_err(netdev, "Unable to alloc receive buffers\n");
err = -ENOMEM;
goto err_out_free_rq;
@@ -2000,7 +2000,7 @@ static int enic_open(struct net_device *netdev)
}
for (i = 0; i < enic->wq_count; i++)
- vnic_wq_enable(&enic->wq[i]);
+ vnic_wq_enable(&enic->wq[i].vwq);
if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
enic_dev_add_station_addr(enic);
@@ -2027,9 +2027,9 @@ static int enic_open(struct net_device *netdev)
err_out_free_rq:
for (i = 0; i < enic->rq_count; i++) {
- ret = vnic_rq_disable(&enic->rq[i]);
+ ret = vnic_rq_disable(&enic->rq[i].vrq);
if (!ret)
- vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+ vnic_rq_clean(&enic->rq[i].vrq, enic_free_rq_buf);
}
enic_dev_notify_unset(enic);
err_out_free_intr:
@@ -2071,12 +2071,12 @@ static int enic_stop(struct net_device *netdev)
enic_dev_del_station_addr(enic);
for (i = 0; i < enic->wq_count; i++) {
- err = vnic_wq_disable(&enic->wq[i]);
+ err = vnic_wq_disable(&enic->wq[i].vwq);
if (err)
return err;
}
for (i = 0; i < enic->rq_count; i++) {
- err = vnic_rq_disable(&enic->rq[i]);
+ err = vnic_rq_disable(&enic->rq[i].vrq);
if (err)
return err;
}
@@ -2086,9 +2086,9 @@ static int enic_stop(struct net_device *netdev)
enic_free_intr(enic);
for (i = 0; i < enic->wq_count; i++)
- vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
+ vnic_wq_clean(&enic->wq[i].vwq, enic_free_wq_buf);
for (i = 0; i < enic->rq_count; i++)
- vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
+ vnic_rq_clean(&enic->rq[i].vrq, enic_free_rq_buf);
for (i = 0; i < enic->cq_count; i++)
vnic_cq_clean(&enic->cq[i]);
for (i = 0; i < enic->intr_count; i++)
@@ -2442,112 +2442,56 @@ static void enic_tx_hang_reset(struct work_struct *work)
static int enic_set_intr_mode(struct enic *enic)
{
- unsigned int n = min_t(unsigned int, enic->rq_count, ENIC_RQ_MAX);
- unsigned int m = min_t(unsigned int, enic->wq_count, ENIC_WQ_MAX);
unsigned int i;
+ int num_intr;
/* Set interrupt mode (INTx, MSI, MSI-X) depending
* on system capabilities.
*
* Try MSI-X first
- *
- * We need n RQs, m WQs, n+m CQs, and n+m+2 INTRs
- * (the second to last INTR is used for WQ/RQ errors)
- * (the last INTR is used for notifications)
- */
-
- BUG_ON(ARRAY_SIZE(enic->msix_entry) < n + m + 2);
- for (i = 0; i < n + m + 2; i++)
- enic->msix_entry[i].entry = i;
-
- /* Use multiple RQs if RSS is enabled
*/
- if (ENIC_SETTING(enic, RSS) &&
- enic->config.intr_mode < 1 &&
- enic->rq_count >= n &&
- enic->wq_count >= m &&
- enic->cq_count >= n + m &&
- enic->intr_count >= n + m + 2) {
-
- if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
- n + m + 2, n + m + 2) > 0) {
-
- enic->rq_count = n;
- enic->wq_count = m;
- enic->cq_count = n + m;
- enic->intr_count = n + m + 2;
-
- vnic_dev_set_intr_mode(enic->vdev,
- VNIC_DEV_INTR_MODE_MSIX);
-
- return 0;
- }
- }
-
if (enic->config.intr_mode < 1 &&
- enic->rq_count >= 1 &&
- enic->wq_count >= m &&
- enic->cq_count >= 1 + m &&
- enic->intr_count >= 1 + m + 2) {
- if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
- 1 + m + 2, 1 + m + 2) > 0) {
-
- enic->rq_count = 1;
- enic->wq_count = m;
- enic->cq_count = 1 + m;
- enic->intr_count = 1 + m + 2;
-
+ enic->intr_avail >= ENIC_MSIX_MIN_INTR) {
+ for (i = 0; i < enic->intr_avail; i++)
+ enic->msix_entry[i].entry = i;
+
+ num_intr = pci_enable_msix_range(enic->pdev, enic->msix_entry,
+ ENIC_MSIX_MIN_INTR,
+ enic->intr_avail);
+ if (num_intr > 0) {
vnic_dev_set_intr_mode(enic->vdev,
- VNIC_DEV_INTR_MODE_MSIX);
-
+ VNIC_DEV_INTR_MODE_MSIX);
+ enic->intr_avail = num_intr;
return 0;
}
}
/* Next try MSI
*
- * We need 1 RQ, 1 WQ, 2 CQs, and 1 INTR
+ * We need 1 INTR
*/
if (enic->config.intr_mode < 2 &&
- enic->rq_count >= 1 &&
- enic->wq_count >= 1 &&
- enic->cq_count >= 2 &&
- enic->intr_count >= 1 &&
+ enic->intr_avail >= 1 &&
!pci_enable_msi(enic->pdev)) {
-
- enic->rq_count = 1;
- enic->wq_count = 1;
- enic->cq_count = 2;
- enic->intr_count = 1;
-
+ enic->intr_avail = 1;
vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSI);
-
return 0;
}
/* Next try INTx
*
- * We need 1 RQ, 1 WQ, 2 CQs, and 3 INTRs
+ * We need 3 INTRs
* (the first INTR is used for WQ/RQ)
* (the second INTR is used for WQ/RQ errors)
* (the last INTR is used for notifications)
*/
if (enic->config.intr_mode < 3 &&
- enic->rq_count >= 1 &&
- enic->wq_count >= 1 &&
- enic->cq_count >= 2 &&
- enic->intr_count >= 3) {
-
- enic->rq_count = 1;
- enic->wq_count = 1;
- enic->cq_count = 2;
- enic->intr_count = 3;
-
+ enic->intr_avail >= 3) {
+ enic->intr_avail = 3;
vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_INTX);
-
return 0;
}
@@ -2572,11 +2516,81 @@ static void enic_clear_intr_mode(struct enic *enic)
vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
}
+static int enic_adjust_resources(struct enic *enic)
+{
+ unsigned int max_queues;
+ unsigned int rq_default;
+ unsigned int rq_avail;
+ unsigned int wq_avail;
+
+ if (enic->rq_avail < 1 || enic->wq_avail < 1 || enic->cq_avail < 2) {
+ dev_err(enic_get_dev(enic),
+ "Not enough resources available rq: %d wq: %d cq: %d\n",
+ enic->rq_avail, enic->wq_avail,
+ enic->cq_avail);
+ return -ENOSPC;
+ }
+
+ if (is_kdump_kernel()) {
+ dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n");
+ enic->rq_avail = 1;
+ enic->wq_avail = 1;
+ enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS;
+ enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS;
+ enic->config.mtu = min_t(u16, 1500, enic->config.mtu);
+ }
+
+ /* if RSS isn't set, then we can only use one RQ */
+ if (!ENIC_SETTING(enic, RSS))
+ enic->rq_avail = 1;
+
+ switch (vnic_dev_get_intr_mode(enic->vdev)) {
+ case VNIC_DEV_INTR_MODE_INTX:
+ case VNIC_DEV_INTR_MODE_MSI:
+ enic->rq_count = 1;
+ enic->wq_count = 1;
+ enic->cq_count = 2;
+ enic->intr_count = enic->intr_avail;
+ break;
+ case VNIC_DEV_INTR_MODE_MSIX:
+ /* Adjust the number of wqs/rqs/cqs/interrupts that will be
+ * used based on which resource is the most constrained
+ */
+ wq_avail = min(enic->wq_avail, ENIC_WQ_MAX);
+ rq_default = netif_get_num_default_rss_queues();
+ rq_avail = min3(enic->rq_avail, ENIC_RQ_MAX, rq_default);
+ max_queues = min(enic->cq_avail,
+ enic->intr_avail - ENIC_MSIX_RESERVED_INTR);
+ if (wq_avail + rq_avail <= max_queues) {
+ enic->rq_count = rq_avail;
+ enic->wq_count = wq_avail;
+ } else {
+ /* recalculate wq/rq count */
+ if (rq_avail < wq_avail) {
+ enic->rq_count = min(rq_avail, max_queues / 2);
+ enic->wq_count = max_queues - enic->rq_count;
+ } else {
+ enic->wq_count = min(wq_avail, max_queues / 2);
+ enic->rq_count = max_queues - enic->wq_count;
+ }
+ }
+ enic->cq_count = enic->rq_count + enic->wq_count;
+ enic->intr_count = enic->cq_count + ENIC_MSIX_RESERVED_INTR;
+
+ break;
+ default:
+ dev_err(enic_get_dev(enic), "Unknown interrupt mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void enic_get_queue_stats_rx(struct net_device *dev, int idx,
struct netdev_queue_stats_rx *rxs)
{
struct enic *enic = netdev_priv(dev);
- struct enic_rq_stats *rqstats = &enic->rq_stats[idx];
+ struct enic_rq_stats *rqstats = &enic->rq[idx].stats;
rxs->bytes = rqstats->bytes;
rxs->packets = rqstats->packets;
@@ -2590,7 +2604,7 @@ static void enic_get_queue_stats_tx(struct net_device *dev, int idx,
struct netdev_queue_stats_tx *txs)
{
struct enic *enic = netdev_priv(dev);
- struct enic_wq_stats *wqstats = &enic->wq_stats[idx];
+ struct enic_wq_stats *wqstats = &enic->wq[idx].stats;
txs->bytes = wqstats->bytes;
txs->packets = wqstats->packets;
@@ -2674,6 +2688,71 @@ static const struct netdev_stat_ops enic_netdev_stat_ops = {
.get_base_stats = enic_get_base_stats,
};
+static void enic_free_enic_resources(struct enic *enic)
+{
+ kfree(enic->wq);
+ enic->wq = NULL;
+
+ kfree(enic->rq);
+ enic->rq = NULL;
+
+ kfree(enic->cq);
+ enic->cq = NULL;
+
+ kfree(enic->napi);
+ enic->napi = NULL;
+
+ kfree(enic->msix_entry);
+ enic->msix_entry = NULL;
+
+ kfree(enic->msix);
+ enic->msix = NULL;
+
+ kfree(enic->intr);
+ enic->intr = NULL;
+}
+
+static int enic_alloc_enic_resources(struct enic *enic)
+{
+ enic->wq = kcalloc(enic->wq_avail, sizeof(struct enic_wq), GFP_KERNEL);
+ if (!enic->wq)
+ goto free_queues;
+
+ enic->rq = kcalloc(enic->rq_avail, sizeof(struct enic_rq), GFP_KERNEL);
+ if (!enic->rq)
+ goto free_queues;
+
+ enic->cq = kcalloc(enic->cq_avail, sizeof(struct vnic_cq), GFP_KERNEL);
+ if (!enic->cq)
+ goto free_queues;
+
+ enic->napi = kcalloc(enic->wq_avail + enic->rq_avail,
+ sizeof(struct napi_struct), GFP_KERNEL);
+ if (!enic->napi)
+ goto free_queues;
+
+ enic->msix_entry = kcalloc(enic->intr_avail, sizeof(struct msix_entry),
+ GFP_KERNEL);
+ if (!enic->msix_entry)
+ goto free_queues;
+
+ enic->msix = kcalloc(enic->intr_avail, sizeof(struct enic_msix_entry),
+ GFP_KERNEL);
+ if (!enic->msix)
+ goto free_queues;
+
+ enic->intr = kcalloc(enic->intr_avail, sizeof(struct vnic_intr),
+ GFP_KERNEL);
+ if (!enic->intr)
+ goto free_queues;
+
+ return 0;
+
+free_queues:
+ enic_free_enic_resources(enic);
+ return -ENOMEM;
+}
+
static void enic_dev_deinit(struct enic *enic)
{
unsigned int i;
@@ -2691,18 +2770,7 @@ static void enic_dev_deinit(struct enic *enic)
enic_free_vnic_resources(enic);
enic_clear_intr_mode(enic);
enic_free_affinity_hint(enic);
-}
-
-static void enic_kdump_kernel_config(struct enic *enic)
-{
- if (is_kdump_kernel()) {
- dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n");
- enic->rq_count = 1;
- enic->wq_count = 1;
- enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS;
- enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS;
- enic->config.mtu = min_t(u16, 1500, enic->config.mtu);
- }
+ enic_free_enic_resources(enic);
}
static int enic_dev_init(struct enic *enic)
@@ -2734,19 +2802,26 @@ static int enic_dev_init(struct enic *enic)
enic_get_res_counts(enic);
- /* modify resource count if we are in kdump_kernel
- */
- enic_kdump_kernel_config(enic);
+ err = enic_alloc_enic_resources(enic);
+ if (err) {
+ dev_err(dev, "Failed to allocate enic resources\n");
+ return err;
+ }
- /* Set interrupt mode based on resource counts and system
- * capabilities
- */
+ /* Set interrupt mode based on system capabilities */
err = enic_set_intr_mode(enic);
if (err) {
dev_err(dev, "Failed to set intr mode based on resource "
"counts and system capabilities, aborting\n");
- return err;
+ goto err_out_free_vnic_resources;
+ }
+
+ /* Adjust resource counts based on most constrained resources */
+ err = enic_adjust_resources(enic);
+ if (err) {
+ dev_err(dev, "Failed to adjust resources\n");
+ goto err_out_free_vnic_resources;
}
/* Allocate and configure vNIC resources
@@ -2788,6 +2863,7 @@ err_out_free_vnic_resources:
enic_free_affinity_hint(enic);
enic_clear_intr_mode(enic);
enic_free_vnic_resources(enic);
+ enic_free_enic_resources(enic);
return err;
}
@@ -2993,7 +3069,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
for (i = 0; i < enic->wq_count; i++)
- spin_lock_init(&enic->wq_lock[i]);
+ spin_lock_init(&enic->wq[i].lock);
/* Register net device
*/
diff --git a/drivers/net/ethernet/cisco/enic/enic_res.c b/drivers/net/ethernet/cisco/enic/enic_res.c
index 1c48aebdbab0..126125199833 100644
--- a/drivers/net/ethernet/cisco/enic/enic_res.c
+++ b/drivers/net/ethernet/cisco/enic/enic_res.c
@@ -176,9 +176,9 @@ void enic_free_vnic_resources(struct enic *enic)
unsigned int i;
for (i = 0; i < enic->wq_count; i++)
- vnic_wq_free(&enic->wq[i]);
+ vnic_wq_free(&enic->wq[i].vwq);
for (i = 0; i < enic->rq_count; i++)
- vnic_rq_free(&enic->rq[i]);
+ vnic_rq_free(&enic->rq[i].vrq);
for (i = 0; i < enic->cq_count; i++)
vnic_cq_free(&enic->cq[i]);
for (i = 0; i < enic->intr_count; i++)
@@ -187,16 +187,21 @@ void enic_free_vnic_resources(struct enic *enic)
void enic_get_res_counts(struct enic *enic)
{
- enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
- enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
- enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
- enic->intr_count = vnic_dev_get_res_count(enic->vdev,
- RES_TYPE_INTR_CTRL);
+ enic->wq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
+ enic->rq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
+ enic->cq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
+ enic->intr_avail = vnic_dev_get_res_count(enic->vdev,
+ RES_TYPE_INTR_CTRL);
+
+ enic->wq_count = enic->wq_avail;
+ enic->rq_count = enic->rq_avail;
+ enic->cq_count = enic->cq_avail;
+ enic->intr_count = enic->intr_avail;
dev_info(enic_get_dev(enic),
"vNIC resources avail: wq %d rq %d cq %d intr %d\n",
- enic->wq_count, enic->rq_count,
- enic->cq_count, enic->intr_count);
+ enic->wq_avail, enic->rq_avail,
+ enic->cq_avail, enic->intr_avail);
}
void enic_init_vnic_resources(struct enic *enic)
@@ -221,9 +226,12 @@ void enic_init_vnic_resources(struct enic *enic)
switch (intr_mode) {
case VNIC_DEV_INTR_MODE_INTX:
+ error_interrupt_enable = 1;
+ error_interrupt_offset = ENIC_LEGACY_ERR_INTR;
+ break;
case VNIC_DEV_INTR_MODE_MSIX:
error_interrupt_enable = 1;
- error_interrupt_offset = enic->intr_count - 2;
+ error_interrupt_offset = enic_msix_err_intr(enic);
break;
default:
error_interrupt_enable = 0;
@@ -233,7 +241,7 @@ void enic_init_vnic_resources(struct enic *enic)
for (i = 0; i < enic->rq_count; i++) {
cq_index = i;
- vnic_rq_init(&enic->rq[i],
+ vnic_rq_init(&enic->rq[i].vrq,
cq_index,
error_interrupt_enable,
error_interrupt_offset);
@@ -241,7 +249,7 @@ void enic_init_vnic_resources(struct enic *enic)
for (i = 0; i < enic->wq_count; i++) {
cq_index = enic->rq_count + i;
- vnic_wq_init(&enic->wq[i],
+ vnic_wq_init(&enic->wq[i].vwq,
cq_index,
error_interrupt_enable,
error_interrupt_offset);
@@ -249,15 +257,15 @@ void enic_init_vnic_resources(struct enic *enic)
/* Init CQ resources
*
- * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
- * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
+ * All CQs point to INTR[0] for INTx, MSI
+ * CQ[i] point to INTR[ENIC_MSIX_IO_INTR_BASE + i] for MSI-X
*/
for (i = 0; i < enic->cq_count; i++) {
switch (intr_mode) {
case VNIC_DEV_INTR_MODE_MSIX:
- interrupt_offset = i;
+ interrupt_offset = ENIC_MSIX_IO_INTR_BASE + i;
break;
default:
interrupt_offset = 0;
@@ -322,7 +330,7 @@ int enic_alloc_vnic_resources(struct enic *enic)
*/
for (i = 0; i < enic->wq_count; i++) {
- err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
+ err = vnic_wq_alloc(enic->vdev, &enic->wq[i].vwq, i,
enic->config.wq_desc_count,
sizeof(struct wq_enet_desc));
if (err)
@@ -330,7 +338,7 @@ int enic_alloc_vnic_resources(struct enic *enic)
}
for (i = 0; i < enic->rq_count; i++) {
- err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
+ err = vnic_rq_alloc(enic->vdev, &enic->rq[i].vrq, i,
enic->config.rq_desc_count,
sizeof(struct rq_enet_desc));
if (err)
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 10c1a2f11000..17ec35e75a65 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1918,35 +1918,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Connecting PHY failed\n");
goto err_phy_connect;
}
- } else if (np && of_phy_is_fixed_link(np)) {
- struct phy_device *phy;
-
- err = of_phy_register_fixed_link(np);
- if (err) {
- dev_err(&pdev->dev, "Failed to register fixed PHY\n");
- goto err_phy_connect;
- }
-
- phy = of_phy_get_and_connect(priv->netdev, np,
- &ftgmac100_adjust_link);
- if (!phy) {
- dev_err(&pdev->dev, "Failed to connect to fixed PHY\n");
- of_phy_deregister_fixed_link(np);
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- /* Display what we found */
- phy_attached_info(phy);
- } else if (np && of_get_property(np, "phy-handle", NULL)) {
+ } else if (np && (of_phy_is_fixed_link(np) ||
+ of_get_property(np, "phy-handle", NULL))) {
struct phy_device *phy;
/* Support "mdio"/"phy" child nodes for ast2400/2500 with
* an embedded MDIO controller. Automatically scan the DTS for
* available PHYs and register them.
*/
- if (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac")) {
+ if (of_get_property(np, "phy-handle", NULL) &&
+ (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
+ of_device_is_compatible(np, "aspeed,ast2500-mac"))) {
err = ftgmac100_setup_mdio(netdev);
if (err)
goto err_setup_mdio;
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index ac06b01fe934..bf5baef5c3e0 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1820,7 +1820,6 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
struct page *page, *head_page;
struct dpaa_bp *dpaa_bp;
void *vaddr, *sg_vaddr;
- int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
int page_offset;
@@ -1863,6 +1862,11 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
* on Tx, if extra headers are added.
*/
WARN_ON(fd_off != priv->rx_headroom);
+ /* The offset to data start within the buffer holding
+ * the SGT should always be equal to the offset to data
+ * start within the first buffer holding the frame.
+ */
+ WARN_ON_ONCE(fd_off != qm_sg_entry_get_off(&sgt[i]));
skb_reserve(skb, fd_off);
skb_put(skb, qm_sg_entry_get_len(&sgt[i]));
} else {
@@ -1876,21 +1880,23 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
page = virt_to_page(sg_vaddr);
head_page = virt_to_head_page(sg_vaddr);
- /* Compute offset in (possibly tail) page */
+ /* Compute offset of sg_vaddr in (possibly tail) page */
page_offset = ((unsigned long)sg_vaddr &
(PAGE_SIZE - 1)) +
(page_address(page) - page_address(head_page));
- /* page_offset only refers to the beginning of sgt[i];
- * but the buffer itself may have an internal offset.
+
+ /* Non-initial SGT entries should not have a buffer
+ * offset.
*/
- frag_off = qm_sg_entry_get_off(&sgt[i]) + page_offset;
- frag_len = qm_sg_entry_get_len(&sgt[i]);
+ WARN_ON_ONCE(qm_sg_entry_get_off(&sgt[i]));
+
/* skb_add_rx_frag() does no checking on the page; if
* we pass it a tail page, we'll end up with
- * bad page accounting and eventually with segafults.
+ * bad page accounting and eventually with segfaults.
*/
- skb_add_rx_frag(skb, i - 1, head_page, frag_off,
- frag_len, dpaa_bp->size);
+ skb_add_rx_frag(skb, i - 1, head_page, page_offset,
+ qm_sg_entry_get_len(&sgt[i]),
+ dpaa_bp->size);
}
/* Update the pool count for the current {cpu x bpool} */
@@ -2766,7 +2772,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use &&
!fman_port_get_hash_result_offset(priv->mac_dev->port[RX],
&hash_offset)) {
- hash = be32_to_cpu(*(u32 *)(vaddr + hash_offset));
+ hash = be32_to_cpu(*(__be32 *)(vaddr + hash_offset));
hash_valid = true;
}
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_trace.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_trace.h
index 6f0e58a2a58a..9e1d44ae92cc 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_trace.h
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_trace.h
@@ -56,7 +56,7 @@ DECLARE_EVENT_CLASS(dpaa_eth_fd,
__entry->fd_format = qm_fd_get_format(fd);
__entry->fd_offset = qm_fd_get_offset(fd);
__entry->fd_length = qm_fd_get_length(fd);
- __entry->fd_status = fd->status;
+ __entry->fd_status = __be32_to_cpu(fd->status);
__assign_str(name);
),
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
index b0060cf96090..9986f6e1f587 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
@@ -243,38 +243,24 @@ static void dpaa_get_ethtool_stats(struct net_device *net_dev,
static void dpaa_get_strings(struct net_device *net_dev, u32 stringset,
u8 *data)
{
- unsigned int i, j, num_cpus, size;
- char string_cpu[ETH_GSTRING_LEN];
- u8 *strings;
+ unsigned int i, j, num_cpus;
- memset(string_cpu, 0, sizeof(string_cpu));
- strings = data;
- num_cpus = num_online_cpus();
- size = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
+ num_cpus = num_online_cpus();
for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) {
- for (j = 0; j < num_cpus; j++) {
- snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]",
- dpaa_stats_percpu[i], j);
- memcpy(strings, string_cpu, ETH_GSTRING_LEN);
- strings += ETH_GSTRING_LEN;
- }
- snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]",
- dpaa_stats_percpu[i]);
- memcpy(strings, string_cpu, ETH_GSTRING_LEN);
- strings += ETH_GSTRING_LEN;
- }
- for (j = 0; j < num_cpus; j++) {
- snprintf(string_cpu, ETH_GSTRING_LEN,
- "bpool [CPU %d]", j);
- memcpy(strings, string_cpu, ETH_GSTRING_LEN);
- strings += ETH_GSTRING_LEN;
+ for (j = 0; j < num_cpus; j++)
+ ethtool_sprintf(&data, "%s [CPU %d]",
+ dpaa_stats_percpu[i], j);
+
+ ethtool_sprintf(&data, "%s [TOTAL]", dpaa_stats_percpu[i]);
}
- snprintf(string_cpu, ETH_GSTRING_LEN, "bpool [TOTAL]");
- memcpy(strings, string_cpu, ETH_GSTRING_LEN);
- strings += ETH_GSTRING_LEN;
+ for (i = 0; i < num_cpus; i++)
+ ethtool_sprintf(&data, "bpool [CPU %d]", i);
+
+ ethtool_puts(&data, "bpool [TOTAL]");
- memcpy(strings, dpaa_stats_global, size);
+ for (i = 0; i < DPAA_STATS_GLOBAL_LEN; i++)
+ ethtool_puts(&data, dpaa_stats_global[i]);
}
static int dpaa_get_hash_opts(struct net_device *dev,
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
index 7f476519b7ad..74ef77cb7078 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
@@ -217,20 +217,15 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev,
static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
- u8 *p = data;
int i;
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) {
- strscpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) {
- strscpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- dpaa2_mac_get_strings(p);
+ for (i = 0; i < DPAA2_ETH_NUM_STATS; i++)
+ ethtool_puts(&data, dpaa2_ethtool_stats[i]);
+ for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++)
+ ethtool_puts(&data, dpaa2_ethtool_extras[i]);
+ dpaa2_mac_get_strings(&data);
break;
}
}
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
index a69bb22c37ea..422ce13a7c94 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
@@ -558,15 +558,12 @@ int dpaa2_mac_get_sset_count(void)
return DPAA2_MAC_NUM_STATS;
}
-void dpaa2_mac_get_strings(u8 *data)
+void dpaa2_mac_get_strings(u8 **data)
{
- u8 *p = data;
int i;
- for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
- strscpy(p, dpaa2_mac_ethtool_stats[i], ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < DPAA2_MAC_NUM_STATS; i++)
+ ethtool_puts(data, dpaa2_mac_ethtool_stats[i]);
}
void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data)
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
index c1ec9efd413a..53f8d106d11e 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
@@ -49,7 +49,7 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac);
int dpaa2_mac_get_sset_count(void);
-void dpaa2_mac_get_strings(u8 *data);
+void dpaa2_mac_get_strings(u8 **data);
void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c
index 6bc1988be311..a888f6e6e9b0 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c
@@ -170,17 +170,16 @@ dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
u32 stringset, u8 *data)
{
- u8 *p = data;
+ const char *str;
int i;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
- memcpy(p, dpaa2_switch_ethtool_counters[i].name,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = dpaa2_switch_ethtool_counters[i].name;
+ ethtool_puts(&data, str);
}
- dpaa2_mac_get_strings(p);
+ dpaa2_mac_get_strings(&data);
break;
}
}
diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index 4d75e6807e92..6c2779047dcd 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -7,6 +7,14 @@ config FSL_ENETC_CORE
If compiled as module (M), the module name is fsl-enetc-core.
+config NXP_ENETC_PF_COMMON
+ tristate
+ help
+ This module supports common functionality between drivers of
+ different versions of NXP ENETC PF controllers.
+
+ If compiled as module (M), the module name is nxp-enetc-pf-common.
+
config FSL_ENETC
tristate "ENETC PF driver"
depends on PCI_MSI
@@ -14,6 +22,7 @@ config FSL_ENETC
select FSL_ENETC_CORE
select FSL_ENETC_IERB
select FSL_ENETC_MDIO
+ select NXP_ENETC_PF_COMMON
select PHYLINK
select PCS_LYNX
select DIMLIB
@@ -24,6 +33,23 @@ config FSL_ENETC
If compiled as module (M), the module name is fsl-enetc.
+config NXP_ENETC4
+ tristate "ENETC4 PF driver"
+ depends on PCI_MSI
+ select MDIO_DEVRES
+ select FSL_ENETC_CORE
+ select FSL_ENETC_MDIO
+ select NXP_ENETC_PF_COMMON
+ select PHYLINK
+ select DIMLIB
+ help
+ This driver supports NXP ENETC devices with major revision 4. ENETC is
+ as the NIC functionality in NETC, it supports virtualization/isolation
+ based on PCIe Single Root IO Virtualization (SR-IOV) and a full range
+ of TSN standards and NIC offload capabilities.
+
+ If compiled as module (M), the module name is nxp-enetc4.
+
config FSL_ENETC_VF
tristate "ENETC VF driver"
depends on PCI_MSI
@@ -75,3 +101,17 @@ config FSL_ENETC_QOS
enable/disable from user space via Qos commands(tc). In the kernel
side, it can be loaded by Qos driver. Currently, it is only support
taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu).
+
+config NXP_NETC_BLK_CTRL
+ tristate "NETC blocks control driver"
+ help
+ This driver configures Integrated Endpoint Register Block (IERB) and
+ Privileged Register Block (PRB) of NETC. For i.MX platforms, it also
+ includes the configuration of NETCMIX block.
+ The IERB contains registers that are used for pre-boot initialization,
+ debug, and non-customer configuration. The PRB controls global reset
+ and global error handling for NETC. The NETCMIX block is mainly used
+ to set MII protocol and PCS protocol of the links, it also contains
+ settings for some other functions.
+
+ If compiled as module (M), the module name is nxp-netc-blk-ctrl.
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index b13cbbabb2ea..6fd27ee4fcd1 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -3,11 +3,17 @@
obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o
fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o
+obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o
+nxp-enetc-pf-common-y := enetc_pf_common.o
+
obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
fsl-enetc-y := enetc_pf.o
fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
+obj-$(CONFIG_NXP_ENETC4) += nxp-enetc4.o
+nxp-enetc4-y := enetc4_pf.o
+
obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
fsl-enetc-vf-y := enetc_vf.o
@@ -19,3 +25,6 @@ fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
obj-$(CONFIG_FSL_ENETC_PTP_CLOCK) += fsl-enetc-ptp.o
fsl-enetc-ptp-y := enetc_ptp.o
+
+obj-$(CONFIG_NXP_NETC_BLK_CTRL) += nxp-netc-blk-ctrl.o
+nxp-netc-blk-ctrl-y := netc_blk_ctrl.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index c09370eab319..35634c516e26 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -3,6 +3,7 @@
#include "enetc.h"
#include <linux/bpf_trace.h>
+#include <linux/clk.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/vmalloc.h>
@@ -21,7 +22,7 @@ void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val)
{
enetc_port_wr(&si->hw, reg, val);
if (si->hw_features & ENETC_SI_F_QBU)
- enetc_port_wr(&si->hw, reg + ENETC_PMAC_OFFSET, val);
+ enetc_port_wr(&si->hw, reg + si->drvdata->pmac_offset, val);
}
EXPORT_SYMBOL_GPL(enetc_port_mac_wr);
@@ -700,8 +701,9 @@ static void enetc_rx_dim_work(struct work_struct *w)
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
struct enetc_int_vector *v =
container_of(dim, struct enetc_int_vector, rx_dim);
+ struct enetc_ndev_priv *priv = netdev_priv(v->rx_ring.ndev);
- v->rx_ictt = enetc_usecs_to_cycles(moder.usec);
+ v->rx_ictt = enetc_usecs_to_cycles(moder.usec, priv->sysclk_freq);
dim->state = DIM_START_MEASURE;
}
@@ -718,7 +720,7 @@ static void enetc_rx_net_dim(struct enetc_int_vector *v)
v->rx_ring.stats.packets,
v->rx_ring.stats.bytes,
&dim_sample);
- net_dim(&v->rx_dim, dim_sample);
+ net_dim(&v->rx_dim, &dim_sample);
}
static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
@@ -1736,9 +1738,15 @@ void enetc_get_si_caps(struct enetc_si *si)
si->num_rx_rings = (val >> 16) & 0xff;
si->num_tx_rings = val & 0xff;
- val = enetc_rd(hw, ENETC_SIRFSCAPR);
- si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val);
- si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE);
+ val = enetc_rd(hw, ENETC_SIPCAPR0);
+ if (val & ENETC_SIPCAPR0_RFS) {
+ val = enetc_rd(hw, ENETC_SIRFSCAPR);
+ si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val);
+ si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE);
+ } else {
+ /* ENETC which not supports RFS */
+ si->num_fs_entries = 0;
+ }
si->num_rss = 0;
val = enetc_rd(hw, ENETC_SIPCAPR0);
@@ -2066,7 +2074,10 @@ int enetc_configure_si(struct enetc_ndev_priv *priv)
/* enable SI */
enetc_wr(hw, ENETC_SIMR, ENETC_SIMR_EN);
- if (si->num_rss) {
+ /* TODO: RSS support for i.MX95 will be supported later, and the
+ * is_enetc_rev1() condition will be removed
+ */
+ if (si->num_rss && is_enetc_rev1(si)) {
err = enetc_setup_default_rss_table(si, priv->num_rx_rings);
if (err)
return err;
@@ -2090,9 +2101,9 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv)
*/
priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings);
priv->num_tx_rings = si->num_tx_rings;
- priv->bdr_int_num = cpus;
+ priv->bdr_int_num = priv->num_rx_rings;
priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL;
- priv->tx_ictt = ENETC_TXIC_TIMETHR;
+ priv->tx_ictt = enetc_usecs_to_cycles(600, priv->sysclk_freq);
}
EXPORT_SYMBOL_GPL(enetc_init_si_rings_params);
@@ -2501,10 +2512,14 @@ int enetc_open(struct net_device *ndev)
extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP);
- err = enetc_setup_irqs(priv);
+ err = clk_prepare_enable(priv->ref_clk);
if (err)
return err;
+ err = enetc_setup_irqs(priv);
+ if (err)
+ goto err_setup_irqs;
+
err = enetc_phylink_connect(ndev);
if (err)
goto err_phy_connect;
@@ -2536,6 +2551,8 @@ err_alloc_tx:
phylink_disconnect_phy(priv->phylink);
err_phy_connect:
enetc_free_irqs(priv);
+err_setup_irqs:
+ clk_disable_unprepare(priv->ref_clk);
return err;
}
@@ -2589,6 +2606,7 @@ int enetc_close(struct net_device *ndev)
enetc_assign_tx_resources(priv, NULL);
enetc_free_irqs(priv);
+ clk_disable_unprepare(priv->ref_clk);
return 0;
}
@@ -2995,13 +3013,99 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
}
EXPORT_SYMBOL_GPL(enetc_ioctl);
+static int enetc_int_vector_init(struct enetc_ndev_priv *priv, int i,
+ int v_tx_rings)
+{
+ struct enetc_int_vector *v;
+ struct enetc_bdr *bdr;
+ int j, err;
+
+ v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL);
+ if (!v)
+ return -ENOMEM;
+
+ priv->int_vector[i] = v;
+ bdr = &v->rx_ring;
+ bdr->index = i;
+ bdr->ndev = priv->ndev;
+ bdr->dev = priv->dev;
+ bdr->bd_count = priv->rx_bd_count;
+ bdr->buffer_offset = ENETC_RXB_PAD;
+ priv->rx_ring[i] = bdr;
+
+ err = xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0);
+ if (err)
+ goto free_vector;
+
+ err = xdp_rxq_info_reg_mem_model(&bdr->xdp.rxq, MEM_TYPE_PAGE_SHARED,
+ NULL);
+ if (err) {
+ xdp_rxq_info_unreg(&bdr->xdp.rxq);
+ goto free_vector;
+ }
+
+ /* init defaults for adaptive IC */
+ if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) {
+ v->rx_ictt = 0x1;
+ v->rx_dim_en = true;
+ }
+
+ INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work);
+ netif_napi_add(priv->ndev, &v->napi, enetc_poll);
+ v->count_tx_rings = v_tx_rings;
+
+ for (j = 0; j < v_tx_rings; j++) {
+ int idx;
+
+ /* default tx ring mapping policy */
+ idx = priv->bdr_int_num * j + i;
+ __set_bit(idx, &v->tx_rings_map);
+ bdr = &v->tx_ring[j];
+ bdr->index = idx;
+ bdr->ndev = priv->ndev;
+ bdr->dev = priv->dev;
+ bdr->bd_count = priv->tx_bd_count;
+ priv->tx_ring[idx] = bdr;
+ }
+
+ return 0;
+
+free_vector:
+ priv->rx_ring[i] = NULL;
+ priv->int_vector[i] = NULL;
+ kfree(v);
+
+ return err;
+}
+
+static void enetc_int_vector_destroy(struct enetc_ndev_priv *priv, int i)
+{
+ struct enetc_int_vector *v = priv->int_vector[i];
+ struct enetc_bdr *rx_ring = &v->rx_ring;
+ int j, tx_ring_index;
+
+ xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq);
+ xdp_rxq_info_unreg(&rx_ring->xdp.rxq);
+ netif_napi_del(&v->napi);
+ cancel_work_sync(&v->rx_dim.work);
+
+ for (j = 0; j < v->count_tx_rings; j++) {
+ tx_ring_index = priv->bdr_int_num * j + i;
+ priv->tx_ring[tx_ring_index] = NULL;
+ }
+
+ priv->rx_ring[i] = NULL;
+ priv->int_vector[i] = NULL;
+ kfree(v);
+}
+
int enetc_alloc_msix(struct enetc_ndev_priv *priv)
{
struct pci_dev *pdev = priv->si->pdev;
+ int v_tx_rings, v_remainder;
int num_stack_tx_queues;
int first_xdp_tx_ring;
int i, n, err, nvec;
- int v_tx_rings;
nvec = ENETC_BDR_INT_BASE_IDX + priv->bdr_int_num;
/* allocate MSIX for both messaging and Rx/Tx interrupts */
@@ -3015,64 +3119,17 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv)
/* # of tx rings per int vector */
v_tx_rings = priv->num_tx_rings / priv->bdr_int_num;
+ v_remainder = priv->num_tx_rings % priv->bdr_int_num;
for (i = 0; i < priv->bdr_int_num; i++) {
- struct enetc_int_vector *v;
- struct enetc_bdr *bdr;
- int j;
-
- v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL);
- if (!v) {
- err = -ENOMEM;
- goto fail;
- }
-
- priv->int_vector[i] = v;
-
- bdr = &v->rx_ring;
- bdr->index = i;
- bdr->ndev = priv->ndev;
- bdr->dev = priv->dev;
- bdr->bd_count = priv->rx_bd_count;
- bdr->buffer_offset = ENETC_RXB_PAD;
- priv->rx_ring[i] = bdr;
-
- err = xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0);
- if (err) {
- kfree(v);
- goto fail;
- }
+ /* Distribute the remaining TX rings to the first v_remainder
+ * interrupt vectors
+ */
+ int num_tx_rings = i < v_remainder ? v_tx_rings + 1 : v_tx_rings;
- err = xdp_rxq_info_reg_mem_model(&bdr->xdp.rxq,
- MEM_TYPE_PAGE_SHARED, NULL);
- if (err) {
- xdp_rxq_info_unreg(&bdr->xdp.rxq);
- kfree(v);
+ err = enetc_int_vector_init(priv, i, num_tx_rings);
+ if (err)
goto fail;
- }
-
- /* init defaults for adaptive IC */
- if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) {
- v->rx_ictt = 0x1;
- v->rx_dim_en = true;
- }
- INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work);
- netif_napi_add(priv->ndev, &v->napi, enetc_poll);
- v->count_tx_rings = v_tx_rings;
-
- for (j = 0; j < v_tx_rings; j++) {
- int idx;
-
- /* default tx ring mapping policy */
- idx = priv->bdr_int_num * j + i;
- __set_bit(idx, &v->tx_rings_map);
- bdr = &v->tx_ring[j];
- bdr->index = idx;
- bdr->ndev = priv->ndev;
- bdr->dev = priv->dev;
- bdr->bd_count = priv->tx_bd_count;
- priv->tx_ring[idx] = bdr;
- }
}
num_stack_tx_queues = enetc_num_stack_tx_queues(priv);
@@ -3092,16 +3149,8 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv)
return 0;
fail:
- while (i--) {
- struct enetc_int_vector *v = priv->int_vector[i];
- struct enetc_bdr *rx_ring = &v->rx_ring;
-
- xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq);
- xdp_rxq_info_unreg(&rx_ring->xdp.rxq);
- netif_napi_del(&v->napi);
- cancel_work_sync(&v->rx_dim.work);
- kfree(v);
- }
+ while (i--)
+ enetc_int_vector_destroy(priv, i);
pci_free_irq_vectors(pdev);
@@ -3113,26 +3162,8 @@ void enetc_free_msix(struct enetc_ndev_priv *priv)
{
int i;
- for (i = 0; i < priv->bdr_int_num; i++) {
- struct enetc_int_vector *v = priv->int_vector[i];
- struct enetc_bdr *rx_ring = &v->rx_ring;
-
- xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq);
- xdp_rxq_info_unreg(&rx_ring->xdp.rxq);
- netif_napi_del(&v->napi);
- cancel_work_sync(&v->rx_dim.work);
- }
-
- for (i = 0; i < priv->num_rx_rings; i++)
- priv->rx_ring[i] = NULL;
-
- for (i = 0; i < priv->num_tx_rings; i++)
- priv->tx_ring[i] = NULL;
-
- for (i = 0; i < priv->bdr_int_num; i++) {
- kfree(priv->int_vector[i]);
- priv->int_vector[i] = NULL;
- }
+ for (i = 0; i < priv->bdr_int_num; i++)
+ enetc_int_vector_destroy(priv, i);
/* disable all MSIX for this device */
pci_free_irq_vectors(priv->si->pdev);
@@ -3241,5 +3272,55 @@ void enetc_pci_remove(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(enetc_pci_remove);
+static const struct enetc_drvdata enetc_pf_data = {
+ .sysclk_freq = ENETC_CLK_400M,
+ .pmac_offset = ENETC_PMAC_OFFSET,
+ .eth_ops = &enetc_pf_ethtool_ops,
+};
+
+static const struct enetc_drvdata enetc4_pf_data = {
+ .sysclk_freq = ENETC_CLK_333M,
+ .pmac_offset = ENETC4_PMAC_OFFSET,
+ .eth_ops = &enetc4_pf_ethtool_ops,
+};
+
+static const struct enetc_drvdata enetc_vf_data = {
+ .sysclk_freq = ENETC_CLK_400M,
+ .eth_ops = &enetc_vf_ethtool_ops,
+};
+
+static const struct enetc_platform_info enetc_info[] = {
+ { .revision = ENETC_REV_1_0,
+ .dev_id = ENETC_DEV_ID_PF,
+ .data = &enetc_pf_data,
+ },
+ { .revision = ENETC_REV_4_1,
+ .dev_id = NXP_ENETC_PF_DEV_ID,
+ .data = &enetc4_pf_data,
+ },
+ { .revision = ENETC_REV_1_0,
+ .dev_id = ENETC_DEV_ID_VF,
+ .data = &enetc_vf_data,
+ },
+};
+
+int enetc_get_driver_data(struct enetc_si *si)
+{
+ u16 dev_id = si->pdev->device;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(enetc_info); i++) {
+ if (si->revision == enetc_info[i].revision &&
+ dev_id == enetc_info[i].dev_id) {
+ si->drvdata = enetc_info[i].data;
+
+ return 0;
+ }
+ }
+
+ return -ERANGE;
+}
+EXPORT_SYMBOL_GPL(enetc_get_driver_data);
+
MODULE_DESCRIPTION("NXP ENETC Ethernet driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index fb7d98d57783..72fa03dbc2dd 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -14,6 +14,7 @@
#include <net/xdp.h>
#include "enetc_hw.h"
+#include "enetc4_hw.h"
#define ENETC_MAC_MAXFRM_SIZE 9600
#define ENETC_MAX_MTU (ENETC_MAC_MAXFRM_SIZE - \
@@ -231,6 +232,18 @@ enum enetc_errata {
#define ENETC_SI_F_QBV BIT(1)
#define ENETC_SI_F_QBU BIT(2)
+struct enetc_drvdata {
+ u32 pmac_offset; /* Only valid for PSI which supports 802.1Qbu */
+ u64 sysclk_freq;
+ const struct ethtool_ops *eth_ops;
+};
+
+struct enetc_platform_info {
+ u16 revision;
+ u16 dev_id;
+ const struct enetc_drvdata *data;
+};
+
/* PCI IEP device data */
struct enetc_si {
struct pci_dev *pdev;
@@ -246,11 +259,18 @@ struct enetc_si {
int num_fs_entries;
int num_rss; /* number of RSS buckets */
unsigned short pad;
+ u16 revision;
int hw_features;
+ const struct enetc_drvdata *drvdata;
};
#define ENETC_SI_ALIGN 32
+static inline bool is_enetc_rev1(struct enetc_si *si)
+{
+ return si->pdev->revision == ENETC_REV1;
+}
+
static inline void *enetc_si_priv(const struct enetc_si *si)
{
return (char *)si + ALIGN(sizeof(struct enetc_si), ENETC_SI_ALIGN);
@@ -302,7 +322,7 @@ struct enetc_cls_rule {
int used;
};
-#define ENETC_MAX_BDR_INT 2 /* fixed to max # of available cpus */
+#define ENETC_MAX_BDR_INT 6 /* fixed to max # of available cpus */
struct psfp_cap {
u32 max_streamid;
u32 max_psfp_filter;
@@ -341,7 +361,6 @@ enum enetc_ic_mode {
#define ENETC_RXIC_PKTTHR min_t(u32, 256, ENETC_RX_RING_DEFAULT_SIZE / 2)
#define ENETC_TXIC_PKTTHR min_t(u32, 128, ENETC_TX_RING_DEFAULT_SIZE / 2)
-#define ENETC_TXIC_TIMETHR enetc_usecs_to_cycles(600)
struct enetc_ndev_priv {
struct net_device *ndev;
@@ -389,6 +408,9 @@ struct enetc_ndev_priv {
* and link state updates
*/
struct mutex mm_lock;
+
+ struct clk *ref_clk; /* RGMII/RMII reference clock */
+ u64 sysclk_freq; /* NETC system clock frequency */
};
/* Messaging */
@@ -418,6 +440,7 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv);
int enetc_alloc_si_resources(struct enetc_ndev_priv *priv);
void enetc_free_si_resources(struct enetc_ndev_priv *priv);
int enetc_configure_si(struct enetc_ndev_priv *priv);
+int enetc_get_driver_data(struct enetc_si *si);
int enetc_open(struct net_device *ndev);
int enetc_close(struct net_device *ndev);
@@ -434,6 +457,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
struct xdp_frame **frames, u32 flags);
/* ethtool */
+extern const struct ethtool_ops enetc_pf_ethtool_ops;
+extern const struct ethtool_ops enetc4_pf_ethtool_ops;
+extern const struct ethtool_ops enetc_vf_ethtool_ops;
void enetc_set_ethtool_ops(struct net_device *ndev);
void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link);
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
new file mode 100644
index 000000000000..26b220677448
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * This header file defines the register offsets and bit fields
+ * of ENETC4 PF and VFs. Note that the same registers as ENETC
+ * version 1.0 are defined in the enetc_hw.h file.
+ *
+ * Copyright 2024 NXP
+ */
+#ifndef __ENETC4_HW_H_
+#define __ENETC4_HW_H_
+
+#define NXP_ENETC_VENDOR_ID 0x1131
+#define NXP_ENETC_PF_DEV_ID 0xe101
+
+/***************************ENETC port registers**************************/
+#define ENETC4_ECAPR0 0x0
+#define ECAPR0_RFS BIT(2)
+#define ECAPR0_TSD BIT(5)
+#define ECAPR0_RSS BIT(8)
+#define ECAPR0_RSC BIT(9)
+#define ECAPR0_LSO BIT(10)
+#define ECAPR0_WO BIT(13)
+
+#define ENETC4_ECAPR1 0x4
+#define ECAPR1_NUM_TCS GENMASK(6, 4)
+#define ECAPR1_NUM_MCH GENMASK(9, 8)
+#define ECAPR1_NUM_UCH GENMASK(11, 10)
+#define ECAPR1_NUM_MSIX GENMASK(22, 12)
+#define ECAPR1_NUM_VSI GENMASK(27, 24)
+#define ECAPR1_NUM_IPV BIT(31)
+
+#define ENETC4_ECAPR2 0x8
+#define ECAPR2_NUM_TX_BDR GENMASK(9, 0)
+#define ECAPR2_NUM_RX_BDR GENMASK(25, 16)
+
+#define ENETC4_PMR 0x10
+#define PMR_SI_EN(a) BIT((16 + (a)))
+
+/* Port Pause ON/OFF threshold register */
+#define ENETC4_PPAUONTR 0x108
+#define ENETC4_PPAUOFFTR 0x10c
+
+/* Port Station interface promiscuous MAC mode register */
+#define ENETC4_PSIPMMR 0x200
+#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */
+#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16)
+
+/* Port Station interface promiscuous VLAN mode register */
+#define ENETC4_PSIPVMR 0x204
+
+/* Port RSS key register n. n = 0,1,2,...,9 */
+#define ENETC4_PRSSKR(n) ((n) * 0x4 + 0x250)
+
+/* Port station interface MAC address filtering capability register */
+#define ENETC4_PSIMAFCAPR 0x280
+#define PSIMAFCAPR_NUM_MAC_AFTE GENMASK(11, 0)
+
+/* Port station interface VLAN filtering capability register */
+#define ENETC4_PSIVLANFCAPR 0x2c0
+#define PSIVLANFCAPR_NUM_VLAN_FTE GENMASK(11, 0)
+
+/* Port station interface VLAN filtering mode register */
+#define ENETC4_PSIVLANFMR 0x2c4
+#define PSIVLANFMR_VS BIT(0)
+
+/* Port Station interface a primary MAC address registers */
+#define ENETC4_PSIPMAR0(a) ((a) * 0x80 + 0x2000)
+#define ENETC4_PSIPMAR1(a) ((a) * 0x80 + 0x2004)
+
+/* Port station interface a configuration register 0/2 */
+#define ENETC4_PSICFGR0(a) ((a) * 0x80 + 0x2010)
+#define PSICFGR0_VASE BIT(13)
+#define PSICFGR0_ASE BIT(15)
+#define PSICFGR0_ANTI_SPOOFING (PSICFGR0_VASE | PSICFGR0_ASE)
+
+#define ENETC4_PSICFGR2(a) ((a) * 0x80 + 0x2018)
+#define PSICFGR2_NUM_MSIX GENMASK(5, 0)
+
+#define ENETC4_PMCAPR 0x4004
+#define PMCAPR_HD BIT(8)
+#define PMCAPR_FP GENMASK(10, 9)
+
+/* Port configuration register */
+#define ENETC4_PCR 0x4010
+#define PCR_HDR_FMT BIT(0)
+#define PCR_L2DOSE BIT(4)
+#define PCR_TIMER_CS BIT(8)
+#define PCR_PSPEED GENMASK(29, 16)
+#define PCR_PSPEED_VAL(speed) (((speed) / 10 - 1) << 16)
+
+/* Port MAC address register 0/1 */
+#define ENETC4_PMAR0 0x4020
+#define ENETC4_PMAR1 0x4024
+
+/* Port operational register */
+#define ENETC4_POR 0x4100
+
+/* Port traffic class a transmit maximum SDU register */
+#define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208)
+#define PTCTMSDUR_MAXSDU GENMASK(15, 0)
+#define PTCTMSDUR_SDU_TYPE GENMASK(17, 16)
+#define SDU_TYPE_PPDU 0
+#define SDU_TYPE_MPDU 1
+#define SDU_TYPE_MSDU 2
+
+#define ENETC4_PMAC_OFFSET 0x400
+#define ENETC4_PM_CMD_CFG(mac) (0x5008 + (mac) * 0x400)
+#define PM_CMD_CFG_TX_EN BIT(0)
+#define PM_CMD_CFG_RX_EN BIT(1)
+#define PM_CMD_CFG_PAUSE_FWD BIT(7)
+#define PM_CMD_CFG_PAUSE_IGN BIT(8)
+#define PM_CMD_CFG_TX_ADDR_INS BIT(9)
+#define PM_CMD_CFG_LOOP_EN BIT(10)
+#define PM_CMD_CFG_LPBK_MODE GENMASK(12, 11)
+#define LPBCK_MODE_EXT_TX_CLK 0
+#define LPBCK_MODE_MAC_LEVEL 1
+#define LPBCK_MODE_INT_TX_CLK 2
+#define PM_CMD_CFG_CNT_FRM_EN BIT(13)
+#define PM_CMD_CFG_TXP BIT(15)
+#define PM_CMD_CFG_SEND_IDLE BIT(16)
+#define PM_CMD_CFG_HD_FCEN BIT(18)
+#define PM_CMD_CFG_SFD BIT(21)
+#define PM_CMD_CFG_TX_FLUSH BIT(22)
+#define PM_CMD_CFG_TX_LOWP_EN BIT(23)
+#define PM_CMD_CFG_RX_LOWP_EMPTY BIT(24)
+#define PM_CMD_CFG_SWR BIT(26)
+#define PM_CMD_CFG_TS_MODE BIT(30)
+#define PM_CMD_CFG_MG BIT(31)
+
+/* Port MAC 0/1 Maximum Frame Length Register */
+#define ENETC4_PM_MAXFRM(mac) (0x5014 + (mac) * 0x400)
+
+/* Port MAC 0/1 Pause Quanta Register */
+#define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400)
+
+/* Port MAC 0/1 Pause Quanta Threshold Register */
+#define ENETC4_PM_PAUSE_THRESH(mac) (0x5064 + (mac) * 0x400)
+
+/* Port MAC 0 Interface Mode Control Register */
+#define ENETC4_PM_IF_MODE(mac) (0x5300 + (mac) * 0x400)
+#define PM_IF_MODE_IFMODE GENMASK(2, 0)
+#define IFMODE_XGMII 0
+#define IFMODE_RMII 3
+#define IFMODE_RGMII 4
+#define IFMODE_SGMII 5
+#define PM_IF_MODE_REVMII BIT(3)
+#define PM_IF_MODE_M10 BIT(4)
+#define PM_IF_MODE_HD BIT(6)
+#define PM_IF_MODE_SSP GENMASK(14, 13)
+#define SSP_100M 0
+#define SSP_10M 1
+#define SSP_1G 2
+#define PM_IF_MODE_ENA BIT(15)
+
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
new file mode 100644
index 000000000000..fc41078c4f5d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2024 NXP */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/unaligned.h>
+
+#include "enetc_pf_common.h"
+
+#define ENETC_SI_MAX_RING_NUM 8
+
+static void enetc4_get_port_caps(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ u32 val;
+
+ val = enetc_port_rd(hw, ENETC4_ECAPR1);
+ pf->caps.num_vsi = (val & ECAPR1_NUM_VSI) >> 24;
+ pf->caps.num_msix = ((val & ECAPR1_NUM_MSIX) >> 12) + 1;
+
+ val = enetc_port_rd(hw, ENETC4_ECAPR2);
+ pf->caps.num_rx_bdr = (val & ECAPR2_NUM_RX_BDR) >> 16;
+ pf->caps.num_tx_bdr = val & ECAPR2_NUM_TX_BDR;
+
+ val = enetc_port_rd(hw, ENETC4_PMCAPR);
+ pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0;
+}
+
+static void enetc4_pf_set_si_primary_mac(struct enetc_hw *hw, int si,
+ const u8 *addr)
+{
+ u16 lower = get_unaligned_le16(addr + 4);
+ u32 upper = get_unaligned_le32(addr);
+
+ if (si != 0) {
+ __raw_writel(upper, hw->port + ENETC4_PSIPMAR0(si));
+ __raw_writew(lower, hw->port + ENETC4_PSIPMAR1(si));
+ } else {
+ __raw_writel(upper, hw->port + ENETC4_PMAR0);
+ __raw_writew(lower, hw->port + ENETC4_PMAR1);
+ }
+}
+
+static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
+ u8 *addr)
+{
+ u32 upper;
+ u16 lower;
+
+ upper = __raw_readl(hw->port + ENETC4_PSIPMAR0(si));
+ lower = __raw_readw(hw->port + ENETC4_PSIPMAR1(si));
+
+ put_unaligned_le32(upper, addr);
+ put_unaligned_le16(lower, addr + 4);
+}
+
+static const struct enetc_pf_ops enetc4_pf_ops = {
+ .set_si_primary_mac = enetc4_pf_set_si_primary_mac,
+ .get_si_primary_mac = enetc4_pf_get_si_primary_mac,
+};
+
+static int enetc4_pf_struct_init(struct enetc_si *si)
+{
+ struct enetc_pf *pf = enetc_si_priv(si);
+
+ pf->si = si;
+ pf->total_vfs = pci_sriov_get_totalvfs(si->pdev);
+ pf->ops = &enetc4_pf_ops;
+
+ enetc4_get_port_caps(pf);
+
+ return 0;
+}
+
+static u32 enetc4_psicfgr0_val_construct(bool is_vf, u32 num_tx_bdr, u32 num_rx_bdr)
+{
+ u32 val;
+
+ val = ENETC_PSICFGR0_SET_TXBDR(num_tx_bdr);
+ val |= ENETC_PSICFGR0_SET_RXBDR(num_rx_bdr);
+ val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S);
+
+ if (is_vf)
+ val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE;
+
+ return val;
+}
+
+static void enetc4_default_rings_allocation(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ u32 num_rx_bdr, num_tx_bdr, val;
+ u32 vf_tx_bdr, vf_rx_bdr;
+ int i, rx_rem, tx_rem;
+
+ if (pf->caps.num_rx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi)
+ num_rx_bdr = pf->caps.num_rx_bdr - pf->caps.num_vsi;
+ else
+ num_rx_bdr = ENETC_SI_MAX_RING_NUM;
+
+ if (pf->caps.num_tx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi)
+ num_tx_bdr = pf->caps.num_tx_bdr - pf->caps.num_vsi;
+ else
+ num_tx_bdr = ENETC_SI_MAX_RING_NUM;
+
+ val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr);
+ enetc_port_wr(hw, ENETC4_PSICFGR0(0), val);
+
+ num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr;
+ rx_rem = num_rx_bdr % pf->caps.num_vsi;
+ num_rx_bdr = num_rx_bdr / pf->caps.num_vsi;
+
+ num_tx_bdr = pf->caps.num_tx_bdr - num_tx_bdr;
+ tx_rem = num_tx_bdr % pf->caps.num_vsi;
+ num_tx_bdr = num_tx_bdr / pf->caps.num_vsi;
+
+ for (i = 0; i < pf->caps.num_vsi; i++) {
+ vf_tx_bdr = (i < tx_rem) ? num_tx_bdr + 1 : num_tx_bdr;
+ vf_rx_bdr = (i < rx_rem) ? num_rx_bdr + 1 : num_rx_bdr;
+ val = enetc4_psicfgr0_val_construct(true, vf_tx_bdr, vf_rx_bdr);
+ enetc_port_wr(hw, ENETC4_PSICFGR0(i + 1), val);
+ }
+}
+
+static void enetc4_allocate_si_rings(struct enetc_pf *pf)
+{
+ enetc4_default_rings_allocation(pf);
+}
+
+static void enetc4_pf_set_si_vlan_promisc(struct enetc_hw *hw, int si, bool en)
+{
+ u32 val = enetc_port_rd(hw, ENETC4_PSIPVMR);
+
+ if (en)
+ val |= BIT(si);
+ else
+ val &= ~BIT(si);
+
+ enetc_port_wr(hw, ENETC4_PSIPVMR, val);
+}
+
+static void enetc4_set_default_si_vlan_promisc(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ int num_si = pf->caps.num_vsi + 1;
+ int i;
+
+ /* enforce VLAN promiscuous mode for all SIs */
+ for (i = 0; i < num_si; i++)
+ enetc4_pf_set_si_vlan_promisc(hw, i, true);
+}
+
+/* Allocate the number of MSI-X vectors for per SI. */
+static void enetc4_set_si_msix_num(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ int i, num_msix, total_si;
+ u32 val;
+
+ total_si = pf->caps.num_vsi + 1;
+
+ num_msix = pf->caps.num_msix / total_si +
+ pf->caps.num_msix % total_si - 1;
+ val = num_msix & PSICFGR2_NUM_MSIX;
+ enetc_port_wr(hw, ENETC4_PSICFGR2(0), val);
+
+ num_msix = pf->caps.num_msix / total_si - 1;
+ val = num_msix & PSICFGR2_NUM_MSIX;
+ for (i = 0; i < pf->caps.num_vsi; i++)
+ enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), val);
+}
+
+static void enetc4_enable_all_si(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ int num_si = pf->caps.num_vsi + 1;
+ u32 si_bitmap = 0;
+ int i;
+
+ /* Master enable for all SIs */
+ for (i = 0; i < num_si; i++)
+ si_bitmap |= PMR_SI_EN(i);
+
+ enetc_port_wr(hw, ENETC4_PMR, si_bitmap);
+}
+
+static void enetc4_configure_port_si(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+
+ enetc4_allocate_si_rings(pf);
+
+ /* Outer VLAN tag will be used for VLAN filtering */
+ enetc_port_wr(hw, ENETC4_PSIVLANFMR, PSIVLANFMR_VS);
+
+ enetc4_set_default_si_vlan_promisc(pf);
+
+ /* Disable SI MAC multicast & unicast promiscuous */
+ enetc_port_wr(hw, ENETC4_PSIPMMR, 0);
+
+ enetc4_set_si_msix_num(pf);
+
+ enetc4_enable_all_si(pf);
+}
+
+static void enetc4_pf_reset_tc_msdu(struct enetc_hw *hw)
+{
+ u32 val = ENETC_MAC_MAXFRM_SIZE;
+ int tc;
+
+ val = u32_replace_bits(val, SDU_TYPE_MPDU, PTCTMSDUR_SDU_TYPE);
+
+ for (tc = 0; tc < ENETC_NUM_TC; tc++)
+ enetc_port_wr(hw, ENETC4_PTCTMSDUR(tc), val);
+}
+
+static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
+{
+ struct enetc_si *si = pf->si;
+
+ enetc_port_mac_wr(si, ENETC4_PM_MAXFRM(0),
+ ENETC_SET_MAXFRM(ENETC_MAC_MAXFRM_SIZE));
+
+ enetc4_pf_reset_tc_msdu(&si->hw);
+}
+
+static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
+{
+ int i;
+
+ for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
+ enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]);
+}
+
+static void enetc4_set_default_rss_key(struct enetc_pf *pf)
+{
+ u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0};
+ struct enetc_hw *hw = &pf->si->hw;
+
+ /* set up hash key */
+ get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
+ enetc4_set_rss_key(hw, hash_key);
+}
+
+static void enetc4_enable_trx(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+
+ /* Enable port transmit/receive */
+ enetc_port_wr(hw, ENETC4_POR, 0);
+}
+
+static void enetc4_configure_port(struct enetc_pf *pf)
+{
+ enetc4_configure_port_si(pf);
+ enetc4_set_trx_frame_size(pf);
+ enetc4_set_default_rss_key(pf);
+ enetc4_enable_trx(pf);
+}
+
+static int enetc4_pf_init(struct enetc_pf *pf)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ int err;
+
+ /* Initialize the MAC address for PF and VFs */
+ err = enetc_setup_mac_addresses(dev->of_node, pf);
+ if (err) {
+ dev_err(dev, "Failed to set MAC addresses\n");
+ return err;
+ }
+
+ enetc4_configure_port(pf);
+
+ return 0;
+}
+
+static const struct net_device_ops enetc4_ndev_ops = {
+ .ndo_open = enetc_open,
+ .ndo_stop = enetc_close,
+ .ndo_start_xmit = enetc_xmit,
+ .ndo_get_stats = enetc_get_stats,
+ .ndo_set_mac_address = enetc_pf_set_mac_addr,
+};
+
+static struct phylink_pcs *
+enetc4_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
+{
+ struct enetc_pf *pf = phylink_to_enetc_pf(config);
+
+ return pf->pcs;
+}
+
+static void enetc4_mac_config(struct enetc_pf *pf, unsigned int mode,
+ phy_interface_t phy_mode)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev);
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0));
+ val &= ~(PM_IF_MODE_IFMODE | PM_IF_MODE_ENA);
+
+ switch (phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val |= IFMODE_RGMII;
+ /* We need to enable auto-negotiation for the MAC
+ * if its RGMII interface support In-Band status.
+ */
+ if (phylink_autoneg_inband(mode))
+ val |= PM_IF_MODE_ENA;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ val |= IFMODE_RMII;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ val |= IFMODE_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ val |= IFMODE_XGMII;
+ break;
+ default:
+ dev_err(priv->dev,
+ "Unsupported PHY mode:%d\n", phy_mode);
+ return;
+ }
+
+ enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val);
+}
+
+static void enetc4_pl_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct enetc_pf *pf = phylink_to_enetc_pf(config);
+
+ enetc4_mac_config(pf, mode, state->interface);
+}
+
+static void enetc4_set_port_speed(struct enetc_ndev_priv *priv, int speed)
+{
+ u32 old_speed = priv->speed;
+ u32 val;
+
+ if (speed == old_speed)
+ return;
+
+ val = enetc_port_rd(&priv->si->hw, ENETC4_PCR);
+ val &= ~PCR_PSPEED;
+
+ switch (speed) {
+ case SPEED_100:
+ case SPEED_1000:
+ case SPEED_2500:
+ case SPEED_10000:
+ val |= (PCR_PSPEED & PCR_PSPEED_VAL(speed));
+ break;
+ case SPEED_10:
+ default:
+ val |= (PCR_PSPEED & PCR_PSPEED_VAL(SPEED_10));
+ }
+
+ priv->speed = speed;
+ enetc_port_wr(&priv->si->hw, ENETC4_PCR, val);
+}
+
+static void enetc4_set_rgmii_mac(struct enetc_pf *pf, int speed, int duplex)
+{
+ struct enetc_si *si = pf->si;
+ u32 old_val, val;
+
+ old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0));
+ val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_M10 | PM_IF_MODE_REVMII);
+
+ switch (speed) {
+ case SPEED_1000:
+ val = u32_replace_bits(val, SSP_1G, PM_IF_MODE_SSP);
+ break;
+ case SPEED_100:
+ val = u32_replace_bits(val, SSP_100M, PM_IF_MODE_SSP);
+ break;
+ case SPEED_10:
+ val = u32_replace_bits(val, SSP_10M, PM_IF_MODE_SSP);
+ }
+
+ val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1,
+ PM_IF_MODE_HD);
+
+ if (val == old_val)
+ return;
+
+ enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val);
+}
+
+static void enetc4_set_rmii_mac(struct enetc_pf *pf, int speed, int duplex)
+{
+ struct enetc_si *si = pf->si;
+ u32 old_val, val;
+
+ old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0));
+ val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_SSP);
+
+ switch (speed) {
+ case SPEED_100:
+ val &= ~PM_IF_MODE_M10;
+ break;
+ case SPEED_10:
+ val |= PM_IF_MODE_M10;
+ }
+
+ val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1,
+ PM_IF_MODE_HD);
+
+ if (val == old_val)
+ return;
+
+ enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val);
+}
+
+static void enetc4_set_hd_flow_control(struct enetc_pf *pf, bool enable)
+{
+ struct enetc_si *si = pf->si;
+ u32 old_val, val;
+
+ if (!pf->caps.half_duplex)
+ return;
+
+ old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+ val = u32_replace_bits(old_val, enable ? 1 : 0, PM_CMD_CFG_HD_FCEN);
+ if (val == old_val)
+ return;
+
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+}
+
+static void enetc4_set_rx_pause(struct enetc_pf *pf, bool rx_pause)
+{
+ struct enetc_si *si = pf->si;
+ u32 old_val, val;
+
+ old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+ val = u32_replace_bits(old_val, rx_pause ? 0 : 1, PM_CMD_CFG_PAUSE_IGN);
+ if (val == old_val)
+ return;
+
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+}
+
+static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_pause)
+{
+ u32 pause_off_thresh = 0, pause_on_thresh = 0;
+ u32 init_quanta = 0, refresh_quanta = 0;
+ struct enetc_hw *hw = &pf->si->hw;
+ u32 rbmr, old_rbmr;
+ int i;
+
+ for (i = 0; i < num_rxbdr; i++) {
+ old_rbmr = enetc_rxbdr_rd(hw, i, ENETC_RBMR);
+ rbmr = u32_replace_bits(old_rbmr, tx_pause ? 1 : 0, ENETC_RBMR_CM);
+ if (rbmr == old_rbmr)
+ continue;
+
+ enetc_rxbdr_wr(hw, i, ENETC_RBMR, rbmr);
+ }
+
+ if (tx_pause) {
+ /* When the port first enters congestion, send a PAUSE request
+ * with the maximum number of quanta. When the port exits
+ * congestion, it will automatically send a PAUSE frame with
+ * zero quanta.
+ */
+ init_quanta = 0xffff;
+
+ /* Also, set up the refresh timer to send follow-up PAUSE
+ * frames at half the quanta value, in case the congestion
+ * condition persists.
+ */
+ refresh_quanta = 0xffff / 2;
+
+ /* Start emitting PAUSE frames when 3 large frames (or more
+ * smaller frames) have accumulated in the FIFO waiting to be
+ * DMAed to the RX ring.
+ */
+ pause_on_thresh = 3 * ENETC_MAC_MAXFRM_SIZE;
+ pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE;
+ }
+
+ enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_QUANTA(0), init_quanta);
+ enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_THRESH(0), refresh_quanta);
+ enetc_port_wr(hw, ENETC4_PPAUONTR, pause_on_thresh);
+ enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh);
+}
+
+static void enetc4_enable_mac(struct enetc_pf *pf, bool en)
+{
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+ val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN);
+ val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0;
+
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+}
+
+static void enetc4_pl_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 enetc_pf *pf = phylink_to_enetc_pf(config);
+ struct enetc_si *si = pf->si;
+ struct enetc_ndev_priv *priv;
+ bool hd_fc = false;
+
+ priv = netdev_priv(si->ndev);
+ enetc4_set_port_speed(priv, speed);
+
+ if (!phylink_autoneg_inband(mode) &&
+ phy_interface_mode_is_rgmii(interface))
+ enetc4_set_rgmii_mac(pf, speed, duplex);
+
+ if (interface == PHY_INTERFACE_MODE_RMII)
+ enetc4_set_rmii_mac(pf, speed, duplex);
+
+ if (duplex == DUPLEX_FULL) {
+ /* When preemption is enabled, generation of PAUSE frames
+ * must be disabled, as stated in the IEEE 802.3 standard.
+ */
+ if (priv->active_offloads & ENETC_F_QBU)
+ tx_pause = false;
+ } else { /* DUPLEX_HALF */
+ if (tx_pause || rx_pause)
+ hd_fc = true;
+
+ /* As per 802.3 annex 31B, PAUSE frames are only supported
+ * when the link is configured for full duplex operation.
+ */
+ tx_pause = false;
+ rx_pause = false;
+ }
+
+ enetc4_set_hd_flow_control(pf, hd_fc);
+ enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause);
+ enetc4_set_rx_pause(pf, rx_pause);
+ enetc4_enable_mac(pf, true);
+}
+
+static void enetc4_pl_mac_link_down(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ struct enetc_pf *pf = phylink_to_enetc_pf(config);
+
+ enetc4_enable_mac(pf, false);
+}
+
+static const struct phylink_mac_ops enetc_pl_mac_ops = {
+ .mac_select_pcs = enetc4_pl_mac_select_pcs,
+ .mac_config = enetc4_pl_mac_config,
+ .mac_link_up = enetc4_pl_mac_link_up,
+ .mac_link_down = enetc4_pl_mac_link_down,
+};
+
+static void enetc4_pci_remove(void *data)
+{
+ struct pci_dev *pdev = data;
+
+ enetc_pci_remove(pdev);
+}
+
+static int enetc4_link_init(struct enetc_ndev_priv *priv,
+ struct device_node *node)
+{
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct device *dev = priv->dev;
+ int err;
+
+ err = of_get_phy_mode(node, &pf->if_mode);
+ if (err) {
+ dev_err(dev, "Failed to get PHY mode\n");
+ return err;
+ }
+
+ err = enetc_mdiobus_create(pf, node);
+ if (err) {
+ dev_err(dev, "Failed to create MDIO bus\n");
+ return err;
+ }
+
+ err = enetc_phylink_create(priv, node, &enetc_pl_mac_ops);
+ if (err) {
+ dev_err(dev, "Failed to create phylink\n");
+ goto err_phylink_create;
+ }
+
+ return 0;
+
+err_phylink_create:
+ enetc_mdiobus_destroy(pf);
+
+ return err;
+}
+
+static void enetc4_link_deinit(struct enetc_ndev_priv *priv)
+{
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+
+ enetc_phylink_destroy(priv);
+ enetc_mdiobus_destroy(pf);
+}
+
+static int enetc4_pf_netdev_create(struct enetc_si *si)
+{
+ struct device *dev = &si->pdev->dev;
+ struct enetc_ndev_priv *priv;
+ struct net_device *ndev;
+ int err;
+
+ ndev = alloc_etherdev_mqs(sizeof(struct enetc_ndev_priv),
+ si->num_tx_rings, si->num_rx_rings);
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+ priv->ref_clk = devm_clk_get_optional(dev, "ref");
+ if (IS_ERR(priv->ref_clk)) {
+ dev_err(dev, "Get reference clock failed\n");
+ err = PTR_ERR(priv->ref_clk);
+ goto err_clk_get;
+ }
+
+ enetc_pf_netdev_setup(si, ndev, &enetc4_ndev_ops);
+
+ enetc_init_si_rings_params(priv);
+
+ err = enetc_configure_si(priv);
+ if (err) {
+ dev_err(dev, "Failed to configure SI\n");
+ goto err_config_si;
+ }
+
+ err = enetc_alloc_msix(priv);
+ if (err) {
+ dev_err(dev, "Failed to alloc MSI-X\n");
+ goto err_alloc_msix;
+ }
+
+ err = enetc4_link_init(priv, dev->of_node);
+ if (err)
+ goto err_link_init;
+
+ err = register_netdev(ndev);
+ if (err) {
+ dev_err(dev, "Failed to register netdev\n");
+ goto err_reg_netdev;
+ }
+
+ return 0;
+
+err_reg_netdev:
+ enetc4_link_deinit(priv);
+err_link_init:
+ enetc_free_msix(priv);
+err_alloc_msix:
+err_config_si:
+err_clk_get:
+ mutex_destroy(&priv->mm_lock);
+ free_netdev(ndev);
+
+ return err;
+}
+
+static void enetc4_pf_netdev_destroy(struct enetc_si *si)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(si->ndev);
+ struct net_device *ndev = si->ndev;
+
+ unregister_netdev(ndev);
+ enetc_free_msix(priv);
+ free_netdev(ndev);
+}
+
+static int enetc4_pf_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct enetc_si *si;
+ struct enetc_pf *pf;
+ int err;
+
+ err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
+ if (err)
+ return dev_err_probe(dev, err, "PCIe probing failed\n");
+
+ err = devm_add_action_or_reset(dev, enetc4_pci_remove, pdev);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Add enetc4_pci_remove() action failed\n");
+
+ /* si is the private data. */
+ si = pci_get_drvdata(pdev);
+ if (!si->hw.port || !si->hw.global)
+ return dev_err_probe(dev, -ENODEV,
+ "Couldn't map PF only space\n");
+
+ si->revision = enetc_get_ip_revision(&si->hw);
+ err = enetc_get_driver_data(si);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Could not get VF driver data\n");
+
+ err = enetc4_pf_struct_init(si);
+ if (err)
+ return err;
+
+ pf = enetc_si_priv(si);
+ err = enetc4_pf_init(pf);
+ if (err)
+ return err;
+
+ enetc_get_si_caps(si);
+
+ return enetc4_pf_netdev_create(si);
+}
+
+static void enetc4_pf_remove(struct pci_dev *pdev)
+{
+ struct enetc_si *si = pci_get_drvdata(pdev);
+
+ enetc4_pf_netdev_destroy(si);
+}
+
+static const struct pci_device_id enetc4_pf_id_table[] = {
+ { PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_PF_DEV_ID) },
+ { 0, } /* End of table. */
+};
+MODULE_DEVICE_TABLE(pci, enetc4_pf_id_table);
+
+static struct pci_driver enetc4_pf_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = enetc4_pf_id_table,
+ .probe = enetc4_pf_probe,
+ .remove = enetc4_pf_remove,
+};
+module_pci_driver(enetc4_pf_driver);
+
+MODULE_DESCRIPTION("ENETC4 PF 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 2563eb8ac7b6..bf34b5bb1e35 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -247,38 +247,25 @@ static int enetc_get_sset_count(struct net_device *ndev, int sset)
static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
- u8 *p = data;
int i, j;
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++) {
- strscpy(p, enetc_si_counters[i].name, ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < priv->num_tx_rings; i++) {
- for (j = 0; j < ARRAY_SIZE(tx_ring_stats); j++) {
- snprintf(p, ETH_GSTRING_LEN, tx_ring_stats[j],
- i);
- p += ETH_GSTRING_LEN;
- }
- }
- for (i = 0; i < priv->num_rx_rings; i++) {
- for (j = 0; j < ARRAY_SIZE(rx_ring_stats); j++) {
- snprintf(p, ETH_GSTRING_LEN, rx_ring_stats[j],
- i);
- p += ETH_GSTRING_LEN;
- }
- }
+ for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++)
+ ethtool_puts(&data, enetc_si_counters[i].name);
+ for (i = 0; i < priv->num_tx_rings; i++)
+ for (j = 0; j < ARRAY_SIZE(tx_ring_stats); j++)
+ ethtool_sprintf(&data, tx_ring_stats[j], i);
+ for (i = 0; i < priv->num_rx_rings; i++)
+ for (j = 0; j < ARRAY_SIZE(rx_ring_stats); j++)
+ ethtool_sprintf(&data, rx_ring_stats[j], i);
if (!enetc_si_is_pf(priv->si))
break;
- for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++) {
- strscpy(p, enetc_port_counters[i].name,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++)
+ ethtool_puts(&data, enetc_port_counters[i].name);
+
break;
}
}
@@ -775,9 +762,10 @@ static int enetc_get_coalesce(struct net_device *ndev,
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_int_vector *v = priv->int_vector[0];
+ u64 clk_freq = priv->sysclk_freq;
- ic->tx_coalesce_usecs = enetc_cycles_to_usecs(priv->tx_ictt);
- ic->rx_coalesce_usecs = enetc_cycles_to_usecs(v->rx_ictt);
+ ic->tx_coalesce_usecs = enetc_cycles_to_usecs(priv->tx_ictt, clk_freq);
+ ic->rx_coalesce_usecs = enetc_cycles_to_usecs(v->rx_ictt, clk_freq);
ic->tx_max_coalesced_frames = ENETC_TXIC_PKTTHR;
ic->rx_max_coalesced_frames = ENETC_RXIC_PKTTHR;
@@ -793,12 +781,13 @@ static int enetc_set_coalesce(struct net_device *ndev,
struct netlink_ext_ack *extack)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ u64 clk_freq = priv->sysclk_freq;
u32 rx_ictt, tx_ictt;
int i, ic_mode;
bool changed;
- tx_ictt = enetc_usecs_to_cycles(ic->tx_coalesce_usecs);
- rx_ictt = enetc_usecs_to_cycles(ic->rx_coalesce_usecs);
+ tx_ictt = enetc_usecs_to_cycles(ic->tx_coalesce_usecs, clk_freq);
+ rx_ictt = enetc_usecs_to_cycles(ic->rx_coalesce_usecs, clk_freq);
if (ic->rx_max_coalesced_frames != ENETC_RXIC_PKTTHR)
return -EOPNOTSUPP;
@@ -1178,7 +1167,7 @@ void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link)
}
EXPORT_SYMBOL_GPL(enetc_mm_link_state_update);
-static const struct ethtool_ops enetc_pf_ethtool_ops = {
+const struct ethtool_ops enetc_pf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
@@ -1213,7 +1202,7 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
.get_mm_stats = enetc_get_mm_stats,
};
-static const struct ethtool_ops enetc_vf_ethtool_ops = {
+const struct ethtool_ops enetc_vf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
@@ -1234,13 +1223,26 @@ static const struct ethtool_ops enetc_vf_ethtool_ops = {
.get_ts_info = enetc_get_ts_info,
};
+const struct ethtool_ops enetc4_pf_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_MAX_FRAMES |
+ ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
+ .get_ringparam = enetc_get_ringparam,
+ .get_coalesce = enetc_get_coalesce,
+ .set_coalesce = enetc_set_coalesce,
+ .get_link_ksettings = enetc_get_link_ksettings,
+ .set_link_ksettings = enetc_set_link_ksettings,
+ .get_link = ethtool_op_get_link,
+ .get_wol = enetc_get_wol,
+ .set_wol = enetc_set_wol,
+ .get_pauseparam = enetc_get_pauseparam,
+ .set_pauseparam = enetc_set_pauseparam,
+};
+
void enetc_set_ethtool_ops(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
- if (enetc_si_is_pf(priv->si))
- ndev->ethtool_ops = &enetc_pf_ethtool_ops;
- else
- ndev->ethtool_ops = &enetc_vf_ethtool_ops;
+ ndev->ethtool_ops = priv->si->drvdata->eth_ops;
}
EXPORT_SYMBOL_GPL(enetc_set_ethtool_ops);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 1619943fb263..7c3285584f8a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -6,6 +6,8 @@
#define ENETC_MM_VERIFY_SLEEP_US USEC_PER_MSEC
#define ENETC_MM_VERIFY_RETRIES 3
+#define ENETC_NUM_TC 8
+
/* ENETC device IDs */
#define ENETC_DEV_ID_PF 0xe100
#define ENETC_DEV_ID_VF 0xef00
@@ -25,6 +27,7 @@
#define ENETC_SIPCAPR0_RSS BIT(8)
#define ENETC_SIPCAPR0_QBV BIT(4)
#define ENETC_SIPCAPR0_QBU BIT(3)
+#define ENETC_SIPCAPR0_RFS BIT(2)
#define ENETC_SIPCAPR1 0x24
#define ENETC_SITGTGR 0x30
#define ENETC_SIRBGCR 0x38
@@ -368,6 +371,10 @@ enum enetc_bdr_type {TX, RX};
/** Global regs, offset: 2_0000h */
#define ENETC_GLOBAL_BASE 0x20000
#define ENETC_G_EIPBRR0 0x0bf8
+#define EIPBRR0_REVISION GENMASK(15, 0)
+#define ENETC_REV_1_0 0x0100
+#define ENETC_REV_4_1 0X0401
+
#define ENETC_G_EIPBRR1 0x0bfc
#define ENETC_G_EPFBLPR(n) (0xd00 + 4 * (n))
#define ENETC_G_EPFBLPR1_XGMII 0x80000000
@@ -396,18 +403,22 @@ struct enetc_hw {
*/
extern rwlock_t enetc_mdio_lock;
+DECLARE_STATIC_KEY_FALSE(enetc_has_err050089);
+
/* use this locking primitive only on the fast datapath to
* group together multiple non-MDIO register accesses to
* minimize the overhead of the lock
*/
static inline void enetc_lock_mdio(void)
{
- read_lock(&enetc_mdio_lock);
+ if (static_branch_unlikely(&enetc_has_err050089))
+ read_lock(&enetc_mdio_lock);
}
static inline void enetc_unlock_mdio(void)
{
- read_unlock(&enetc_mdio_lock);
+ if (static_branch_unlikely(&enetc_has_err050089))
+ read_unlock(&enetc_mdio_lock);
}
/* use these accessors only on the fast datapath under
@@ -416,14 +427,16 @@ static inline void enetc_unlock_mdio(void)
*/
static inline u32 enetc_rd_reg_hot(void __iomem *reg)
{
- lockdep_assert_held(&enetc_mdio_lock);
+ if (static_branch_unlikely(&enetc_has_err050089))
+ lockdep_assert_held(&enetc_mdio_lock);
return ioread32(reg);
}
static inline void enetc_wr_reg_hot(void __iomem *reg, u32 val)
{
- lockdep_assert_held(&enetc_mdio_lock);
+ if (static_branch_unlikely(&enetc_has_err050089))
+ lockdep_assert_held(&enetc_mdio_lock);
iowrite32(val, reg);
}
@@ -452,9 +465,13 @@ static inline u32 _enetc_rd_mdio_reg_wa(void __iomem *reg)
unsigned long flags;
u32 val;
- write_lock_irqsave(&enetc_mdio_lock, flags);
- val = ioread32(reg);
- write_unlock_irqrestore(&enetc_mdio_lock, flags);
+ if (static_branch_unlikely(&enetc_has_err050089)) {
+ write_lock_irqsave(&enetc_mdio_lock, flags);
+ val = ioread32(reg);
+ write_unlock_irqrestore(&enetc_mdio_lock, flags);
+ } else {
+ val = ioread32(reg);
+ }
return val;
}
@@ -463,9 +480,13 @@ static inline void _enetc_wr_mdio_reg_wa(void __iomem *reg, u32 val)
{
unsigned long flags;
- write_lock_irqsave(&enetc_mdio_lock, flags);
- iowrite32(val, reg);
- write_unlock_irqrestore(&enetc_mdio_lock, flags);
+ if (static_branch_unlikely(&enetc_has_err050089)) {
+ write_lock_irqsave(&enetc_mdio_lock, flags);
+ iowrite32(val, reg);
+ write_unlock_irqrestore(&enetc_mdio_lock, flags);
+ } else {
+ iowrite32(val, reg);
+ }
}
#ifdef ioread64
@@ -957,15 +978,17 @@ struct enetc_cbd {
u8 status_flags;
};
-#define ENETC_CLK 400000000ULL
-static inline u32 enetc_cycles_to_usecs(u32 cycles)
+#define ENETC_CLK_400M 400000000ULL
+#define ENETC_CLK_333M 333000000ULL
+
+static inline u32 enetc_cycles_to_usecs(u32 cycles, u64 clk_freq)
{
- return (u32)div_u64(cycles * 1000000ULL, ENETC_CLK);
+ return (u32)div_u64(cycles * 1000000ULL, clk_freq);
}
-static inline u32 enetc_usecs_to_cycles(u32 usecs)
+static inline u32 enetc_usecs_to_cycles(u32 usecs, u64 clk_freq)
{
- return (u32)div_u64(usecs * ENETC_CLK, 1000000ULL);
+ return (u32)div_u64(usecs * clk_freq, 1000000ULL);
}
/* Port traffic class frame preemption register */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
index a1b595bd7993..e108cac8288d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c
@@ -4,11 +4,35 @@
#include <linux/of_mdio.h>
#include "enetc_pf.h"
+#define NETC_EMDIO_VEN_ID 0x1131
+#define NETC_EMDIO_DEV_ID 0xee00
#define ENETC_MDIO_DEV_ID 0xee01
#define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO"
#define ENETC_MDIO_BUS_NAME ENETC_MDIO_DEV_NAME " Bus"
#define ENETC_MDIO_DRV_NAME ENETC_MDIO_DEV_NAME " driver"
+DEFINE_STATIC_KEY_FALSE(enetc_has_err050089);
+EXPORT_SYMBOL_GPL(enetc_has_err050089);
+
+static void enetc_emdio_enable_err050089(struct pci_dev *pdev)
+{
+ if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
+ pdev->device == ENETC_MDIO_DEV_ID) {
+ static_branch_inc(&enetc_has_err050089);
+ dev_info(&pdev->dev, "Enabled ERR050089 workaround\n");
+ }
+}
+
+static void enetc_emdio_disable_err050089(struct pci_dev *pdev)
+{
+ if (pdev->vendor == PCI_VENDOR_ID_FREESCALE &&
+ pdev->device == ENETC_MDIO_DEV_ID) {
+ static_branch_dec(&enetc_has_err050089);
+ if (!static_key_enabled(&enetc_has_err050089.key))
+ dev_info(&pdev->dev, "Disabled ERR050089 workaround\n");
+ }
+}
+
static int enetc_pci_mdio_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -62,6 +86,8 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
goto err_pci_mem_reg;
}
+ enetc_emdio_enable_err050089(pdev);
+
err = of_mdiobus_register(bus, dev->of_node);
if (err)
goto err_mdiobus_reg;
@@ -71,6 +97,7 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev,
return 0;
err_mdiobus_reg:
+ enetc_emdio_disable_err050089(pdev);
pci_release_region(pdev, 0);
err_pci_mem_reg:
pci_disable_device(pdev);
@@ -88,6 +115,9 @@ static void enetc_pci_mdio_remove(struct pci_dev *pdev)
struct enetc_mdio_priv *mdio_priv;
mdiobus_unregister(bus);
+
+ enetc_emdio_disable_err050089(pdev);
+
mdio_priv = bus->priv;
iounmap(mdio_priv->hw->port);
pci_release_region(pdev, 0);
@@ -96,6 +126,7 @@ static void enetc_pci_mdio_remove(struct pci_dev *pdev)
static const struct pci_device_id enetc_pci_mdio_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) },
+ { PCI_DEVICE(NETC_EMDIO_VEN_ID, NETC_EMDIO_DEV_ID) },
{ 0, } /* End of table. */
};
MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 8f6b0bf48139..c47b4a743d93 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -2,15 +2,13 @@
/* Copyright 2017-2019 NXP */
#include <linux/unaligned.h>
-#include <linux/mdio.h>
#include <linux/module.h>
-#include <linux/fsl/enetc_mdio.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/pcs-lynx.h>
#include "enetc_ierb.h"
-#include "enetc_pf.h"
+#include "enetc_pf_common.h"
#define ENETC_DRV_NAME_STR "ENETC PF driver"
@@ -33,18 +31,15 @@ static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si,
__raw_writew(lower, hw->port + ENETC_PSIPMAR1(si));
}
-static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
+static struct phylink_pcs *enetc_pf_create_pcs(struct enetc_pf *pf,
+ struct mii_bus *bus)
{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct sockaddr *saddr = addr;
-
- if (!is_valid_ether_addr(saddr->sa_data))
- return -EADDRNOTAVAIL;
-
- eth_hw_addr_set(ndev, saddr->sa_data);
- enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data);
+ return lynx_pcs_create_mdiodev(bus, 0);
+}
- return 0;
+static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs)
+{
+ lynx_pcs_destroy(pcs);
}
static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map)
@@ -393,56 +388,6 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en)
return 0;
}
-static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
- int si)
-{
- struct device *dev = &pf->si->pdev->dev;
- struct enetc_hw *hw = &pf->si->hw;
- u8 mac_addr[ETH_ALEN] = { 0 };
- int err;
-
- /* (1) try to get the MAC address from the device tree */
- if (np) {
- err = of_get_mac_address(np, mac_addr);
- if (err == -EPROBE_DEFER)
- return err;
- }
-
- /* (2) bootloader supplied MAC address */
- if (is_zero_ether_addr(mac_addr))
- enetc_pf_get_primary_mac_addr(hw, si, mac_addr);
-
- /* (3) choose a random one */
- if (is_zero_ether_addr(mac_addr)) {
- eth_random_addr(mac_addr);
- dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
- si, mac_addr);
- }
-
- enetc_pf_set_primary_mac_addr(hw, si, mac_addr);
-
- return 0;
-}
-
-static int enetc_setup_mac_addresses(struct device_node *np,
- struct enetc_pf *pf)
-{
- int err, i;
-
- /* The PF might take its MAC from the device tree */
- err = enetc_setup_mac_address(np, pf, 0);
- if (err)
- return err;
-
- for (i = 0; i < pf->total_vfs; i++) {
- err = enetc_setup_mac_address(NULL, pf, i + 1);
- if (err)
- return err;
- }
-
- return 0;
-}
-
static void enetc_port_assign_rfs_entries(struct enetc_si *si)
{
struct enetc_pf *pf = enetc_si_priv(si);
@@ -665,19 +610,11 @@ static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (!num_vfs) {
enetc_msg_psi_free(pf);
- kfree(pf->vf_state);
pf->num_vfs = 0;
pci_disable_sriov(pdev);
} else {
pf->num_vfs = num_vfs;
- pf->vf_state = kcalloc(num_vfs, sizeof(struct enetc_vf_state),
- GFP_KERNEL);
- if (!pf->vf_state) {
- pf->num_vfs = 0;
- return -ENOMEM;
- }
-
err = enetc_msg_psi_init(pf);
if (err) {
dev_err(&pdev->dev, "enetc_msg_psi_init (%d)\n", err);
@@ -696,7 +633,6 @@ static int enetc_sriov_configure(struct pci_dev *pdev, int num_vfs)
err_en_sriov:
enetc_msg_psi_free(pf);
err_msg_psi:
- kfree(pf->vf_state);
pf->num_vfs = 0;
return err;
@@ -775,187 +711,6 @@ static const struct net_device_ops enetc_ndev_ops = {
.ndo_xdp_xmit = enetc_xdp_xmit,
};
-static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
- const struct net_device_ops *ndev_ops)
-{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
-
- SET_NETDEV_DEV(ndev, &si->pdev->dev);
- priv->ndev = ndev;
- priv->si = si;
- priv->dev = &si->pdev->dev;
- si->ndev = ndev;
-
- priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
- ndev->netdev_ops = ndev_ops;
- enetc_set_ethtool_ops(ndev);
- ndev->watchdog_timeo = 5 * HZ;
- ndev->max_mtu = ENETC_MAX_MTU;
-
- ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
- NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
- NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
- ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_CTAG_TX |
- NETIF_F_HW_VLAN_CTAG_RX |
- NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
- ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6;
-
- if (si->num_rss)
- ndev->hw_features |= NETIF_F_RXHASH;
-
- ndev->priv_flags |= IFF_UNICAST_FLT;
- ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
- NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
- NETDEV_XDP_ACT_NDO_XMIT_SG;
-
- if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) {
- priv->active_offloads |= ENETC_F_QCI;
- ndev->features |= NETIF_F_HW_TC;
- ndev->hw_features |= NETIF_F_HW_TC;
- }
-
- /* pick up primary MAC address from SI */
- enetc_load_primary_mac_addr(&si->hw, ndev);
-}
-
-static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
-{
- struct device *dev = &pf->si->pdev->dev;
- struct enetc_mdio_priv *mdio_priv;
- struct mii_bus *bus;
- int err;
-
- bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
- if (!bus)
- return -ENOMEM;
-
- bus->name = "Freescale ENETC MDIO Bus";
- bus->read = enetc_mdio_read_c22;
- bus->write = enetc_mdio_write_c22;
- bus->read_c45 = enetc_mdio_read_c45;
- bus->write_c45 = enetc_mdio_write_c45;
- bus->parent = dev;
- mdio_priv = bus->priv;
- mdio_priv->hw = &pf->si->hw;
- mdio_priv->mdio_base = ENETC_EMDIO_BASE;
- snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
-
- err = of_mdiobus_register(bus, np);
- if (err)
- return dev_err_probe(dev, err, "cannot register MDIO bus\n");
-
- pf->mdio = bus;
-
- return 0;
-}
-
-static void enetc_mdio_remove(struct enetc_pf *pf)
-{
- if (pf->mdio)
- mdiobus_unregister(pf->mdio);
-}
-
-static int enetc_imdio_create(struct enetc_pf *pf)
-{
- struct device *dev = &pf->si->pdev->dev;
- struct enetc_mdio_priv *mdio_priv;
- struct phylink_pcs *phylink_pcs;
- struct mii_bus *bus;
- int err;
-
- bus = mdiobus_alloc_size(sizeof(*mdio_priv));
- if (!bus)
- return -ENOMEM;
-
- bus->name = "Freescale ENETC internal MDIO Bus";
- bus->read = enetc_mdio_read_c22;
- bus->write = enetc_mdio_write_c22;
- bus->read_c45 = enetc_mdio_read_c45;
- bus->write_c45 = enetc_mdio_write_c45;
- bus->parent = dev;
- bus->phy_mask = ~0;
- mdio_priv = bus->priv;
- mdio_priv->hw = &pf->si->hw;
- mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
- snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
-
- err = mdiobus_register(bus);
- if (err) {
- dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
- goto free_mdio_bus;
- }
-
- phylink_pcs = lynx_pcs_create_mdiodev(bus, 0);
- if (IS_ERR(phylink_pcs)) {
- err = PTR_ERR(phylink_pcs);
- dev_err(dev, "cannot create lynx pcs (%d)\n", err);
- goto unregister_mdiobus;
- }
-
- pf->imdio = bus;
- pf->pcs = phylink_pcs;
-
- return 0;
-
-unregister_mdiobus:
- mdiobus_unregister(bus);
-free_mdio_bus:
- mdiobus_free(bus);
- return err;
-}
-
-static void enetc_imdio_remove(struct enetc_pf *pf)
-{
- if (pf->pcs)
- lynx_pcs_destroy(pf->pcs);
- if (pf->imdio) {
- mdiobus_unregister(pf->imdio);
- mdiobus_free(pf->imdio);
- }
-}
-
-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);
-}
-
-static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
-{
- struct device_node *mdio_np;
- int err;
-
- mdio_np = of_get_child_by_name(node, "mdio");
- if (mdio_np) {
- err = enetc_mdio_probe(pf, mdio_np);
-
- of_node_put(mdio_np);
- if (err)
- return err;
- }
-
- if (enetc_port_has_pcs(pf)) {
- err = enetc_imdio_create(pf);
- if (err) {
- enetc_mdio_remove(pf);
- return err;
- }
- }
-
- return 0;
-}
-
-static void enetc_mdiobus_destroy(struct enetc_pf *pf)
-{
- enetc_mdio_remove(pf);
- enetc_imdio_remove(pf);
-}
-
static struct phylink_pcs *
enetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface)
{
@@ -1101,47 +856,6 @@ static const struct phylink_mac_ops enetc_mac_phylink_ops = {
.mac_link_down = enetc_pl_mac_link_down,
};
-static int enetc_phylink_create(struct enetc_ndev_priv *priv,
- struct device_node *node)
-{
- struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct phylink *phylink;
- int err;
-
- pf->phylink_config.dev = &priv->ndev->dev;
- pf->phylink_config.type = PHYLINK_NETDEV;
- pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
- MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
-
- __set_bit(PHY_INTERFACE_MODE_INTERNAL,
- 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,
- pf->phylink_config.supported_interfaces);
- phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
-
- phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
- pf->if_mode, &enetc_mac_phylink_ops);
- if (IS_ERR(phylink)) {
- err = PTR_ERR(phylink);
- return err;
- }
-
- priv->phylink = phylink;
-
- return 0;
-}
-
-static void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
-{
- phylink_destroy(priv->phylink);
-}
-
/* Initialize the entire shared memory for the flow steering entries
* of this port (PF + VFs)
*/
@@ -1224,6 +938,13 @@ static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
goto out_pci_remove;
}
+ si->revision = enetc_get_ip_revision(&si->hw);
+ err = enetc_get_driver_data(si);
+ if (err) {
+ dev_err(&pdev->dev, "Could not get PF driver data\n");
+ goto out_pci_remove;
+ }
+
err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE,
&si->cbd_ring);
if (err)
@@ -1259,6 +980,14 @@ static void enetc_psi_destroy(struct pci_dev *pdev)
enetc_pci_remove(pdev);
}
+static const struct enetc_pf_ops enetc_pf_ops = {
+ .set_si_primary_mac = enetc_pf_set_primary_mac_addr,
+ .get_si_primary_mac = enetc_pf_get_primary_mac_addr,
+ .create_pcs = enetc_pf_create_pcs,
+ .destroy_pcs = enetc_pf_destroy_pcs,
+ .enable_psfp = enetc_psfp_enable,
+};
+
static int enetc_pf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1285,7 +1014,15 @@ static int enetc_pf_probe(struct pci_dev *pdev,
pf = enetc_si_priv(si);
pf->si = si;
+ pf->ops = &enetc_pf_ops;
+
pf->total_vfs = pci_sriov_get_totalvfs(pdev);
+ if (pf->total_vfs) {
+ pf->vf_state = kcalloc(pf->total_vfs, sizeof(struct enetc_vf_state),
+ GFP_KERNEL);
+ if (!pf->vf_state)
+ goto err_alloc_vf_state;
+ }
err = enetc_setup_mac_addresses(node, pf);
if (err)
@@ -1338,7 +1075,7 @@ static int enetc_pf_probe(struct pci_dev *pdev,
if (err)
goto err_mdiobus_create;
- err = enetc_phylink_create(priv, node);
+ err = enetc_phylink_create(priv, node, &enetc_mac_phylink_ops);
if (err)
goto err_phylink_create;
@@ -1363,6 +1100,8 @@ err_alloc_si_res:
free_netdev(ndev);
err_alloc_netdev:
err_setup_mac_addresses:
+ kfree(pf->vf_state);
+err_alloc_vf_state:
enetc_psi_destroy(pdev);
err_psi_create:
return err;
@@ -1389,6 +1128,7 @@ static void enetc_pf_remove(struct pci_dev *pdev)
enetc_free_si_resources(priv);
free_netdev(si->ndev);
+ kfree(pf->vf_state);
enetc_psi_destroy(pdev);
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index c26bd66e4597..a26a12863855 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -28,6 +28,24 @@ struct enetc_vf_state {
enum enetc_vf_flags flags;
};
+struct enetc_port_caps {
+ u32 half_duplex:1;
+ int num_vsi;
+ int num_msix;
+ int num_rx_bdr;
+ int num_tx_bdr;
+};
+
+struct enetc_pf;
+
+struct enetc_pf_ops {
+ void (*set_si_primary_mac)(struct enetc_hw *hw, int si, const u8 *addr);
+ void (*get_si_primary_mac)(struct enetc_hw *hw, int si, u8 *addr);
+ struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
+ void (*destroy_pcs)(struct phylink_pcs *pcs);
+ int (*enable_psfp)(struct enetc_ndev_priv *priv);
+};
+
struct enetc_pf {
struct enetc_si *si;
int num_vfs; /* number of active VFs, after sriov_init */
@@ -50,6 +68,9 @@ struct enetc_pf {
phy_interface_t if_mode;
struct phylink_config phylink_config;
+
+ struct enetc_port_caps caps;
+ const struct enetc_pf_ops *ops;
};
#define phylink_to_enetc_pf(config) \
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
new file mode 100644
index 000000000000..0eecfc833164
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/* Copyright 2024 NXP */
+
+#include <linux/fsl/enetc_mdio.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+
+#include "enetc_pf_common.h"
+
+static void enetc_set_si_hw_addr(struct enetc_pf *pf, int si,
+ const u8 *mac_addr)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+
+ pf->ops->set_si_primary_mac(hw, si, mac_addr);
+}
+
+static void enetc_get_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+
+ pf->ops->get_si_primary_mac(hw, si, mac_addr);
+}
+
+int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct sockaddr *saddr = addr;
+
+ if (!is_valid_ether_addr(saddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ eth_hw_addr_set(ndev, saddr->sa_data);
+ enetc_set_si_hw_addr(pf, 0, saddr->sa_data);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr);
+
+static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf,
+ int si)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ u8 mac_addr[ETH_ALEN] = { 0 };
+ int err;
+
+ /* (1) try to get the MAC address from the device tree */
+ if (np) {
+ err = of_get_mac_address(np, mac_addr);
+ if (err == -EPROBE_DEFER)
+ return err;
+ }
+
+ /* (2) bootloader supplied MAC address */
+ if (is_zero_ether_addr(mac_addr))
+ enetc_get_si_hw_addr(pf, si, mac_addr);
+
+ /* (3) choose a random one */
+ if (is_zero_ether_addr(mac_addr)) {
+ eth_random_addr(mac_addr);
+ dev_info(dev, "no MAC address specified for SI%d, using %pM\n",
+ si, mac_addr);
+ }
+
+ enetc_set_si_hw_addr(pf, si, mac_addr);
+
+ return 0;
+}
+
+int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
+{
+ int err, i;
+
+ /* The PF might take its MAC from the device tree */
+ err = enetc_setup_mac_address(np, pf, 0);
+ if (err)
+ return err;
+
+ for (i = 0; i < pf->total_vfs; i++) {
+ err = enetc_setup_mac_address(NULL, pf, i + 1);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
+
+void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
+ const struct net_device_ops *ndev_ops)
+{
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(si);
+
+ SET_NETDEV_DEV(ndev, &si->pdev->dev);
+ priv->ndev = ndev;
+ priv->si = si;
+ priv->dev = &si->pdev->dev;
+ si->ndev = ndev;
+
+ priv->msg_enable = (NETIF_MSG_WOL << 1) - 1;
+ priv->sysclk_freq = si->drvdata->sysclk_freq;
+ ndev->netdev_ops = ndev_ops;
+ enetc_set_ethtool_ops(ndev);
+ ndev->watchdog_timeo = 5 * HZ;
+ ndev->max_mtu = ENETC_MAX_MTU;
+
+ ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK |
+ NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
+ ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
+ ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6;
+
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+
+ /* TODO: currently, i.MX95 ENETC driver does not support advanced features */
+ if (!is_enetc_rev1(si)) {
+ ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);
+ goto end;
+ }
+
+ if (si->num_rss)
+ ndev->hw_features |= NETIF_F_RXHASH;
+
+ ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
+ NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
+ NETDEV_XDP_ACT_NDO_XMIT_SG;
+
+ if (si->hw_features & ENETC_SI_F_PSFP && pf->ops->enable_psfp &&
+ !pf->ops->enable_psfp(priv)) {
+ priv->active_offloads |= ENETC_F_QCI;
+ ndev->features |= NETIF_F_HW_TC;
+ ndev->hw_features |= NETIF_F_HW_TC;
+ }
+
+end:
+ /* pick up primary MAC address from SI */
+ enetc_load_primary_mac_addr(&si->hw, ndev);
+}
+EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup);
+
+static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ struct enetc_mdio_priv *mdio_priv;
+ struct mii_bus *bus;
+ int err;
+
+ bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "Freescale ENETC MDIO Bus";
+ bus->read = enetc_mdio_read_c22;
+ bus->write = enetc_mdio_write_c22;
+ bus->read_c45 = enetc_mdio_read_c45;
+ bus->write_c45 = enetc_mdio_write_c45;
+ bus->parent = dev;
+ mdio_priv = bus->priv;
+ mdio_priv->hw = &pf->si->hw;
+ mdio_priv->mdio_base = ENETC_EMDIO_BASE;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+ err = of_mdiobus_register(bus, np);
+ if (err)
+ return dev_err_probe(dev, err, "cannot register MDIO bus\n");
+
+ pf->mdio = bus;
+
+ return 0;
+}
+
+static void enetc_mdio_remove(struct enetc_pf *pf)
+{
+ if (pf->mdio)
+ mdiobus_unregister(pf->mdio);
+}
+
+static int enetc_imdio_create(struct enetc_pf *pf)
+{
+ struct device *dev = &pf->si->pdev->dev;
+ struct enetc_mdio_priv *mdio_priv;
+ struct phylink_pcs *phylink_pcs;
+ struct mii_bus *bus;
+ int err;
+
+ if (!pf->ops->create_pcs) {
+ dev_err(dev, "Creating PCS is not supported\n");
+
+ return -EOPNOTSUPP;
+ }
+
+ bus = mdiobus_alloc_size(sizeof(*mdio_priv));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "Freescale ENETC internal MDIO Bus";
+ bus->read = enetc_mdio_read_c22;
+ bus->write = enetc_mdio_write_c22;
+ bus->read_c45 = enetc_mdio_read_c45;
+ bus->write_c45 = enetc_mdio_write_c45;
+ bus->parent = dev;
+ bus->phy_mask = ~0;
+ mdio_priv = bus->priv;
+ mdio_priv->hw = &pf->si->hw;
+ mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
+
+ err = mdiobus_register(bus);
+ if (err) {
+ dev_err(dev, "cannot register internal MDIO bus (%d)\n", err);
+ goto free_mdio_bus;
+ }
+
+ phylink_pcs = pf->ops->create_pcs(pf, bus);
+ if (IS_ERR(phylink_pcs)) {
+ err = PTR_ERR(phylink_pcs);
+ dev_err(dev, "cannot create lynx pcs (%d)\n", err);
+ goto unregister_mdiobus;
+ }
+
+ pf->imdio = bus;
+ pf->pcs = phylink_pcs;
+
+ return 0;
+
+unregister_mdiobus:
+ mdiobus_unregister(bus);
+free_mdio_bus:
+ mdiobus_free(bus);
+ return err;
+}
+
+static void enetc_imdio_remove(struct enetc_pf *pf)
+{
+ if (pf->pcs && pf->ops->destroy_pcs)
+ pf->ops->destroy_pcs(pf->pcs);
+
+ if (pf->imdio) {
+ mdiobus_unregister(pf->imdio);
+ mdiobus_free(pf->imdio);
+ }
+}
+
+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);
+}
+
+int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node)
+{
+ struct device_node *mdio_np;
+ int err;
+
+ mdio_np = of_get_child_by_name(node, "mdio");
+ if (mdio_np) {
+ err = enetc_mdio_probe(pf, mdio_np);
+
+ of_node_put(mdio_np);
+ if (err)
+ return err;
+ }
+
+ if (enetc_port_has_pcs(pf)) {
+ err = enetc_imdio_create(pf);
+ if (err) {
+ enetc_mdio_remove(pf);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_mdiobus_create);
+
+void enetc_mdiobus_destroy(struct enetc_pf *pf)
+{
+ enetc_mdio_remove(pf);
+ enetc_imdio_remove(pf);
+}
+EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy);
+
+int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
+ const struct phylink_mac_ops *ops)
+{
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct phylink *phylink;
+ int err;
+
+ pf->phylink_config.dev = &priv->ndev->dev;
+ pf->phylink_config.type = PHYLINK_NETDEV;
+ pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+ MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD;
+
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ 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,
+ pf->phylink_config.supported_interfaces);
+ phy_interface_set_rgmii(pf->phylink_config.supported_interfaces);
+
+ phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node),
+ pf->if_mode, ops);
+ if (IS_ERR(phylink)) {
+ err = PTR_ERR(phylink);
+ return err;
+ }
+
+ priv->phylink = phylink;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_phylink_create);
+
+void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
+{
+ phylink_destroy(priv->phylink);
+}
+EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
+
+MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
new file mode 100644
index 000000000000..48f55ee743ad
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2024 NXP */
+
+#include "enetc_pf.h"
+
+int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr);
+int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf);
+void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
+ const struct net_device_ops *ndev_ops);
+int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node);
+void enetc_mdiobus_destroy(struct enetc_pf *pf);
+int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
+ const struct phylink_mac_ops *ops);
+void enetc_phylink_destroy(struct enetc_ndev_priv *priv);
+
+static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
+{
+ return enetc_global_rd(hw, ENETC_G_EIPBRR0) & EIPBRR0_REVISION;
+}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
index b65da49dd926..ccf86651455c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
@@ -336,7 +336,7 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
*
* (enetClockFrequency / portTransmitRate) * 100
*/
- hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit,
+ hi_credit_reg = (u32)div_u64((priv->sysclk_freq * 100ULL) * hi_credit_bit,
port_transmit_rate * 1000000ULL);
enetc_port_wr(hw, ENETC_PTCCBSR1(tc), hi_credit_reg);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index dfcaac302e24..a5f8ce576b6e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -78,11 +78,18 @@ static int enetc_vf_set_mac_addr(struct net_device *ndev, void *addr)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct sockaddr *saddr = addr;
+ int err;
if (!is_valid_ether_addr(saddr->sa_data))
return -EADDRNOTAVAIL;
- return enetc_msg_vsi_set_primary_mac_addr(priv, saddr);
+ err = enetc_msg_vsi_set_primary_mac_addr(priv, saddr);
+ if (err)
+ return err;
+
+ eth_hw_addr_set(ndev, saddr->sa_data);
+
+ return 0;
}
static int enetc_vf_set_features(struct net_device *ndev,
@@ -128,6 +135,7 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
si->ndev = ndev;
priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
+ priv->sysclk_freq = si->drvdata->sysclk_freq;
ndev->netdev_ops = ndev_ops;
enetc_set_ethtool_ops(ndev);
ndev->watchdog_timeo = 5 * HZ;
@@ -164,6 +172,13 @@ static int enetc_vf_probe(struct pci_dev *pdev,
return dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
si = pci_get_drvdata(pdev);
+ si->revision = ENETC_REV_1_0;
+ err = enetc_get_driver_data(si);
+ if (err) {
+ dev_err_probe(&pdev->dev, err,
+ "Could not get VF driver data\n");
+ goto err_alloc_netdev;
+ }
enetc_get_si_caps(si);
diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
new file mode 100644
index 000000000000..bcb8eefeb93c
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * NXP NETC Blocks Control Driver
+ *
+ * Copyright 2024 NXP
+ *
+ * This driver is used for pre-initialization of NETC, such as PCS and MII
+ * protocols, LDID, warm reset, etc. Therefore, all NETC device drivers can
+ * only be probed after the netc-blk-crtl driver has completed initialization.
+ * In addition, when the system enters suspend mode, IERB, PRB, and NETCMIX
+ * will be powered off, except for WOL. Therefore, when the system resumes,
+ * these blocks need to be reinitialized.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fsl/netc_global.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+
+/* NETCMIX registers */
+#define IMX95_CFG_LINK_IO_VAR 0x0
+#define IO_VAR_16FF_16G_SERDES 0x1
+#define IO_VAR(port, var) (((var) & 0xf) << ((port) << 2))
+
+#define IMX95_CFG_LINK_MII_PROT 0x4
+#define CFG_LINK_MII_PORT_0 GENMASK(3, 0)
+#define CFG_LINK_MII_PORT_1 GENMASK(7, 4)
+#define MII_PROT_MII 0x0
+#define MII_PROT_RMII 0x1
+#define MII_PROT_RGMII 0x2
+#define MII_PROT_SERIAL 0x3
+#define MII_PROT(port, prot) (((prot) & 0xf) << ((port) << 2))
+
+#define IMX95_CFG_LINK_PCS_PROT(a) (0x8 + (a) * 4)
+#define PCS_PROT_1G_SGMII BIT(0)
+#define PCS_PROT_2500M_SGMII BIT(1)
+#define PCS_PROT_XFI BIT(3)
+#define PCS_PROT_SFI BIT(4)
+#define PCS_PROT_10G_SXGMII BIT(6)
+
+/* NETC privileged register block register */
+#define PRB_NETCRR 0x100
+#define NETCRR_SR BIT(0)
+#define NETCRR_LOCK BIT(1)
+
+#define PRB_NETCSR 0x104
+#define NETCSR_ERROR BIT(0)
+#define NETCSR_STATE BIT(1)
+
+/* NETC integrated endpoint register block register */
+#define IERB_EMDIOFAUXR 0x344
+#define IERB_T0FAUXR 0x444
+#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a))
+#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a))
+#define FAUXR_LDID GENMASK(3, 0)
+
+/* Platform information */
+#define IMX95_ENETC0_BUS_DEVFN 0x0
+#define IMX95_ENETC1_BUS_DEVFN 0x40
+#define IMX95_ENETC2_BUS_DEVFN 0x80
+
+/* Flags for different platforms */
+#define NETC_HAS_NETCMIX BIT(0)
+
+struct netc_devinfo {
+ u32 flags;
+ int (*netcmix_init)(struct platform_device *pdev);
+ int (*ierb_init)(struct platform_device *pdev);
+};
+
+struct netc_blk_ctrl {
+ void __iomem *prb;
+ void __iomem *ierb;
+ void __iomem *netcmix;
+
+ const struct netc_devinfo *devinfo;
+ struct platform_device *pdev;
+ struct dentry *debugfs_root;
+};
+
+static void netc_reg_write(void __iomem *base, u32 offset, u32 val)
+{
+ netc_write(base + offset, val);
+}
+
+static u32 netc_reg_read(void __iomem *base, u32 offset)
+{
+ return netc_read(base + offset);
+}
+
+static int netc_of_pci_get_bus_devfn(struct device_node *np)
+{
+ u32 reg[5];
+ int error;
+
+ error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
+ if (error)
+ return error;
+
+ return (reg[0] >> 8) & 0xffff;
+}
+
+static int netc_get_link_mii_protocol(phy_interface_t interface)
+{
+ switch (interface) {
+ case PHY_INTERFACE_MODE_MII:
+ return MII_PROT_MII;
+ case PHY_INTERFACE_MODE_RMII:
+ return MII_PROT_RMII;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ return MII_PROT_RGMII;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return MII_PROT_SERIAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx95_netcmix_init(struct platform_device *pdev)
+{
+ struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ phy_interface_t interface;
+ int bus_devfn, mii_proto;
+ u32 val;
+ int err;
+
+ /* Default setting of MII protocol */
+ val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII) |
+ MII_PROT(2, MII_PROT_SERIAL);
+
+ /* Update the link MII protocol through parsing phy-mode */
+ for_each_available_child_of_node_scoped(np, child) {
+ for_each_available_child_of_node_scoped(child, gchild) {
+ if (!of_device_is_compatible(gchild, "pci1131,e101"))
+ continue;
+
+ bus_devfn = netc_of_pci_get_bus_devfn(gchild);
+ if (bus_devfn < 0)
+ return -EINVAL;
+
+ if (bus_devfn == IMX95_ENETC2_BUS_DEVFN)
+ continue;
+
+ err = of_get_phy_mode(gchild, &interface);
+ if (err)
+ continue;
+
+ mii_proto = netc_get_link_mii_protocol(interface);
+ if (mii_proto < 0)
+ return -EINVAL;
+
+ switch (bus_devfn) {
+ case IMX95_ENETC0_BUS_DEVFN:
+ val = u32_replace_bits(val, mii_proto,
+ CFG_LINK_MII_PORT_0);
+ break;
+ case IMX95_ENETC1_BUS_DEVFN:
+ val = u32_replace_bits(val, mii_proto,
+ CFG_LINK_MII_PORT_1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Configure Link I/O variant */
+ netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR,
+ IO_VAR(2, IO_VAR_16FF_16G_SERDES));
+ /* Configure Link 2 PCS protocol */
+ netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(2),
+ PCS_PROT_10G_SXGMII);
+ netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val);
+
+ return 0;
+}
+
+static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv)
+{
+ return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK);
+}
+
+static int netc_lock_ierb(struct netc_blk_ctrl *priv)
+{
+ u32 val;
+
+ netc_reg_write(priv->prb, PRB_NETCRR, NETCRR_LOCK);
+
+ return read_poll_timeout(netc_reg_read, val, !(val & NETCSR_STATE),
+ 100, 2000, false, priv->prb, PRB_NETCSR);
+}
+
+static int netc_unlock_ierb_with_warm_reset(struct netc_blk_ctrl *priv)
+{
+ u32 val;
+
+ netc_reg_write(priv->prb, PRB_NETCRR, 0);
+
+ return read_poll_timeout(netc_reg_read, val, !(val & NETCRR_LOCK),
+ 1000, 100000, true, priv->prb, PRB_NETCRR);
+}
+
+static int imx95_ierb_init(struct platform_device *pdev)
+{
+ struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
+
+ /* EMDIO : No MSI-X intterupt */
+ netc_reg_write(priv->ierb, IERB_EMDIOFAUXR, 0);
+ /* ENETC0 PF */
+ netc_reg_write(priv->ierb, IERB_EFAUXR(0), 0);
+ /* ENETC0 VF0 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(0), 1);
+ /* ENETC0 VF1 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(1), 2);
+ /* ENETC1 PF */
+ netc_reg_write(priv->ierb, IERB_EFAUXR(1), 3);
+ /* ENETC1 VF0 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(2), 5);
+ /* ENETC1 VF1 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(3), 6);
+ /* ENETC2 PF */
+ netc_reg_write(priv->ierb, IERB_EFAUXR(2), 4);
+ /* ENETC2 VF0 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(4), 5);
+ /* ENETC2 VF1 */
+ netc_reg_write(priv->ierb, IERB_VFAUXR(5), 6);
+ /* NETC TIMER */
+ netc_reg_write(priv->ierb, IERB_T0FAUXR, 7);
+
+ return 0;
+}
+
+static int netc_ierb_init(struct platform_device *pdev)
+{
+ struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
+ const struct netc_devinfo *devinfo = priv->devinfo;
+ int err;
+
+ if (netc_ierb_is_locked(priv)) {
+ err = netc_unlock_ierb_with_warm_reset(priv);
+ if (err) {
+ dev_err(&pdev->dev, "Unlock IERB failed.\n");
+ return err;
+ }
+ }
+
+ if (devinfo->ierb_init) {
+ err = devinfo->ierb_init(pdev);
+ if (err)
+ return err;
+ }
+
+ err = netc_lock_ierb(priv);
+ if (err) {
+ dev_err(&pdev->dev, "Lock IERB failed.\n");
+ return err;
+ }
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+static int netc_prb_show(struct seq_file *s, void *data)
+{
+ struct netc_blk_ctrl *priv = s->private;
+ u32 val;
+
+ val = netc_reg_read(priv->prb, PRB_NETCRR);
+ seq_printf(s, "[PRB NETCRR] Lock:%d SR:%d\n",
+ (val & NETCRR_LOCK) ? 1 : 0,
+ (val & NETCRR_SR) ? 1 : 0);
+
+ val = netc_reg_read(priv->prb, PRB_NETCSR);
+ seq_printf(s, "[PRB NETCSR] State:%d Error:%d\n",
+ (val & NETCSR_STATE) ? 1 : 0,
+ (val & NETCSR_ERROR) ? 1 : 0);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(netc_prb);
+
+static void netc_blk_ctrl_create_debugfs(struct netc_blk_ctrl *priv)
+{
+ struct dentry *root;
+
+ root = debugfs_create_dir("netc_blk_ctrl", NULL);
+ if (IS_ERR(root))
+ return;
+
+ priv->debugfs_root = root;
+
+ debugfs_create_file("prb", 0444, root, priv, &netc_prb_fops);
+}
+
+static void netc_blk_ctrl_remove_debugfs(struct netc_blk_ctrl *priv)
+{
+ debugfs_remove_recursive(priv->debugfs_root);
+ priv->debugfs_root = NULL;
+}
+
+#else
+
+static void netc_blk_ctrl_create_debugfs(struct netc_blk_ctrl *priv)
+{
+}
+
+static void netc_blk_ctrl_remove_debugfs(struct netc_blk_ctrl *priv)
+{
+}
+#endif
+
+static int netc_prb_check_error(struct netc_blk_ctrl *priv)
+{
+ if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR)
+ return -1;
+
+ return 0;
+}
+
+static const struct netc_devinfo imx95_devinfo = {
+ .flags = NETC_HAS_NETCMIX,
+ .netcmix_init = imx95_netcmix_init,
+ .ierb_init = imx95_ierb_init,
+};
+
+static const struct of_device_id netc_blk_ctrl_match[] = {
+ { .compatible = "nxp,imx95-netc-blk-ctrl", .data = &imx95_devinfo },
+ {},
+};
+MODULE_DEVICE_TABLE(of, netc_blk_ctrl_match);
+
+static int netc_blk_ctrl_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ const struct netc_devinfo *devinfo;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *id;
+ struct netc_blk_ctrl *priv;
+ struct clk *ipg_clk;
+ void __iomem *regs;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdev = pdev;
+ ipg_clk = devm_clk_get_optional_enabled(dev, "ipg");
+ if (IS_ERR(ipg_clk))
+ return dev_err_probe(dev, PTR_ERR(ipg_clk),
+ "Set ipg clock failed\n");
+
+ id = of_match_device(netc_blk_ctrl_match, dev);
+ if (!id)
+ return dev_err_probe(dev, -EINVAL, "Cannot match device\n");
+
+ devinfo = (struct netc_devinfo *)id->data;
+ if (!devinfo)
+ return dev_err_probe(dev, -EINVAL, "No device information\n");
+
+ priv->devinfo = devinfo;
+ regs = devm_platform_ioremap_resource_byname(pdev, "ierb");
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs),
+ "Missing IERB resource\n");
+
+ priv->ierb = regs;
+ regs = devm_platform_ioremap_resource_byname(pdev, "prb");
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs),
+ "Missing PRB resource\n");
+
+ priv->prb = regs;
+ if (devinfo->flags & NETC_HAS_NETCMIX) {
+ regs = devm_platform_ioremap_resource_byname(pdev, "netcmix");
+ if (IS_ERR(regs))
+ return dev_err_probe(dev, PTR_ERR(regs),
+ "Missing NETCMIX resource\n");
+ priv->netcmix = regs;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ if (devinfo->netcmix_init) {
+ err = devinfo->netcmix_init(pdev);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Initializing NETCMIX failed\n");
+ }
+
+ err = netc_ierb_init(pdev);
+ if (err)
+ return dev_err_probe(dev, err, "Initializing IERB failed\n");
+
+ if (netc_prb_check_error(priv) < 0)
+ dev_warn(dev, "The current IERB configuration is invalid\n");
+
+ netc_blk_ctrl_create_debugfs(priv);
+
+ err = of_platform_populate(node, NULL, NULL, dev);
+ if (err) {
+ netc_blk_ctrl_remove_debugfs(priv);
+ return dev_err_probe(dev, err, "of_platform_populate failed\n");
+ }
+
+ return 0;
+}
+
+static void netc_blk_ctrl_remove(struct platform_device *pdev)
+{
+ struct netc_blk_ctrl *priv = platform_get_drvdata(pdev);
+
+ of_platform_depopulate(&pdev->dev);
+ netc_blk_ctrl_remove_debugfs(priv);
+}
+
+static struct platform_driver netc_blk_ctrl_driver = {
+ .driver = {
+ .name = "nxp-netc-blk-ctrl",
+ .of_match_table = netc_blk_ctrl_match,
+ },
+ .probe = netc_blk_ctrl_probe,
+ .remove = netc_blk_ctrl_remove,
+};
+
+module_platform_driver(netc_blk_ctrl_driver);
+
+MODULE_DESCRIPTION("NXP NETC Blocks Control Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index d96028f01770..fb416d60dcd7 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -24,7 +24,6 @@
/* General defines */
#define FMAN_LIODN_TBL 64 /* size of LIODN table */
-#define MAX_NUM_OF_MACS 10
#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4
#define BASE_RX_PORTID 0x08
#define BASE_TX_PORTID 0x28
diff --git a/drivers/net/ethernet/freescale/fman/fman.h b/drivers/net/ethernet/freescale/fman/fman.h
index 2ea575a46675..74eb62eba0d7 100644
--- a/drivers/net/ethernet/freescale/fman/fman.h
+++ b/drivers/net/ethernet/freescale/fman/fman.h
@@ -74,6 +74,9 @@
#define BM_MAX_NUM_OF_POOLS 64 /* Buffers pools */
#define FMAN_PORT_MAX_EXT_POOLS_NUM 8 /* External BM pools per Rx port */
+/* General defines */
+#define MAX_NUM_OF_MACS 10
+
struct fman; /* FMan data */
/* Enum for defining port types */
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index c7bff9490ce0..a39fcea6a77a 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -217,6 +217,11 @@ static int mac_probe(struct platform_device *_of_dev)
err = -EINVAL;
goto _return_dev_put;
}
+ if (val >= MAX_NUM_OF_MACS) {
+ dev_err(dev, "cell-index value is too big for %pOF\n", mac_node);
+ err = -EINVAL;
+ goto _return_dev_put;
+ }
priv->cell_index = (u8)val;
/* Get the MAC address */
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index a99b95c4bcfb..781d92e703cb 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -115,12 +115,14 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = {
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
{
struct gfar_private *priv = netdev_priv(dev);
+ int i;
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
- memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < GFAR_STATS_LEN; i++)
+ ethtool_puts(&buf, stat_gstrings[i]);
else
- memcpy(buf, stat_gstrings,
- GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ ethtool_puts(&buf, stat_gstrings[i]);
}
/* Fill in an array of 64-bit statistics from various sources.
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index d3ddca22d6b0..6663c1768089 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3591,22 +3591,23 @@ static int ucc_geth_probe(struct platform_device* ofdev)
if ((ucc_num < 0) || (ucc_num > 7))
return -ENODEV;
- ug_info = kmemdup(&ugeth_primary_info, sizeof(*ug_info), GFP_KERNEL);
- if (ug_info == NULL)
+ ug_info = devm_kmemdup(&ofdev->dev, &ugeth_primary_info,
+ sizeof(*ug_info), GFP_KERNEL);
+ if (!ug_info)
return -ENOMEM;
ug_info->uf_info.ucc_num = ucc_num;
err = ucc_geth_parse_clock(np, "rx", &ug_info->uf_info.rx_clock);
if (err)
- goto err_free_info;
+ return err;
err = ucc_geth_parse_clock(np, "tx", &ug_info->uf_info.tx_clock);
if (err)
- goto err_free_info;
+ return err;
err = of_address_to_resource(np, 0, &res);
if (err)
- goto err_free_info;
+ return err;
ug_info->uf_info.regs = res.start;
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
@@ -3619,7 +3620,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
*/
err = of_phy_register_fixed_link(np);
if (err)
- goto err_free_info;
+ return err;
ug_info->phy_node = of_node_get(np);
}
@@ -3687,9 +3688,8 @@ static int ucc_geth_probe(struct platform_device* ofdev)
ug_info->uf_info.irq);
/* Create an ethernet device instance */
- dev = alloc_etherdev(sizeof(*ugeth));
-
- if (dev == NULL) {
+ dev = devm_alloc_etherdev(&ofdev->dev, sizeof(*ugeth));
+ if (!dev) {
err = -ENOMEM;
goto err_deregister_fixed_link;
}
@@ -3724,15 +3724,17 @@ static int ucc_geth_probe(struct platform_device* ofdev)
/* Carrier starts down, phylib will bring it up */
netif_carrier_off(dev);
- err = register_netdev(dev);
+ err = devm_register_netdev(&ofdev->dev, dev);
if (err) {
if (netif_msg_probe(ugeth))
pr_err("%s: Cannot register net device, aborting\n",
dev->name);
- goto err_free_netdev;
+ goto err_deregister_fixed_link;
}
- of_get_ethdev_address(np, dev);
+ err = of_get_ethdev_address(np, dev);
+ if (err == -EPROBE_DEFER)
+ goto err_deregister_fixed_link;
ugeth->ug_info = ug_info;
ugeth->dev = device;
@@ -3741,16 +3743,11 @@ static int ucc_geth_probe(struct platform_device* ofdev)
return 0;
-err_free_netdev:
- free_netdev(dev);
err_deregister_fixed_link:
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(ug_info->tbi_node);
of_node_put(ug_info->phy_node);
-err_free_info:
- kfree(ug_info);
-
return err;
}
@@ -3760,14 +3757,11 @@ static void ucc_geth_remove(struct platform_device* ofdev)
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct device_node *np = ofdev->dev.of_node;
- unregister_netdev(dev);
ucc_geth_memclean(ugeth);
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(ugeth->ug_info->tbi_node);
of_node_put(ugeth->ug_info->phy_node);
- kfree(ugeth->ug_info);
- free_netdev(dev);
}
static const struct of_device_id ucc_geth_match[] = {
diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
index 601beb93d3b3..699f346faf5c 100644
--- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
+++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
@@ -287,20 +287,17 @@ static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
{
struct ucc_geth_private *ugeth = netdev_priv(netdev);
u32 stats_mode = ugeth->ug_info->statisticsMode;
+ int i;
- if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
- memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
- ETH_GSTRING_LEN);
- buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
- }
- if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
- memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
- ETH_GSTRING_LEN);
- buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
- }
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
+ for (i = 0; i < UEC_HW_STATS_LEN; i++)
+ ethtool_puts(&buf, hw_stat_gstrings[i]);
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
+ for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
+ ethtool_puts(&buf, tx_fw_stat_gstrings[i]);
if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
- memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
- ETH_GSTRING_LEN);
+ for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
+ ethtool_puts(&buf, rx_fw_stat_gstrings[i]);
}
static void uec_get_ethtool_stats(struct net_device *netdev,
diff --git a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
index 05bf1f80a79c..403f0f335ba6 100644
--- a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
@@ -210,8 +210,7 @@ void gve_free_to_page_pool(struct gve_rx_ring *rx,
if (!page)
return;
- page_pool_put_page(page->pp, page, buf_state->page_info.buf_size,
- allow_direct);
+ page_pool_put_full_page(page->pp, page, allow_direct);
buf_state->page_info.page = NULL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
index d72657444ef3..2ae34d01fd36 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -512,7 +512,7 @@ struct hnae_ae_ops {
struct net_device_stats *net_stats);
void (*get_stats)(struct hnae_handle *handle, u64 *data);
void (*get_strings)(struct hnae_handle *handle,
- u32 stringset, u8 *data);
+ u32 stringset, u8 **data);
int (*get_sset_count)(struct hnae_handle *handle, int stringset);
void (*update_led_status)(struct hnae_handle *handle);
int (*set_led_id)(struct hnae_handle *handle,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index bc3e406f0139..8ce910f8d0cc 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -730,15 +730,14 @@ static void hns_ae_get_stats(struct hnae_handle *handle, u64 *data)
hns_dsaf_get_stats(vf_cb->dsaf_dev, p, vf_cb->port_index);
}
-static void hns_ae_get_strings(struct hnae_handle *handle,
- u32 stringset, u8 *data)
+static void hns_ae_get_strings(struct hnae_handle *handle, u32 stringset,
+ u8 **data)
{
int port;
int idx;
struct hns_mac_cb *mac_cb;
struct hns_ppe_cb *ppe_cb;
struct dsaf_device *dsaf_dev = hns_ae_get_dsaf_dev(handle->dev);
- u8 *p = data;
struct hnae_vf_cb *vf_cb;
assert(handle);
@@ -748,19 +747,14 @@ static void hns_ae_get_strings(struct hnae_handle *handle,
mac_cb = hns_get_mac_cb(handle);
ppe_cb = hns_get_ppe_cb(handle);
- for (idx = 0; idx < handle->q_num; idx++) {
- hns_rcb_get_strings(stringset, p, idx);
- p += ETH_GSTRING_LEN * hns_rcb_get_ring_sset_count(stringset);
- }
-
- hns_ppe_get_strings(ppe_cb, stringset, p);
- p += ETH_GSTRING_LEN * hns_ppe_get_sset_count(stringset);
+ for (idx = 0; idx < handle->q_num; idx++)
+ hns_rcb_get_strings(stringset, data, idx);
- hns_mac_get_strings(mac_cb, stringset, p);
- p += ETH_GSTRING_LEN * hns_mac_get_sset_count(mac_cb, stringset);
+ hns_ppe_get_strings(ppe_cb, stringset, data);
+ hns_mac_get_strings(mac_cb, stringset, data);
if (mac_cb->mac_type == HNAE_PORT_SERVICE)
- hns_dsaf_get_strings(stringset, p, port, dsaf_dev);
+ hns_dsaf_get_strings(stringset, data, port, dsaf_dev);
}
static int hns_ae_get_sset_count(struct hnae_handle *handle, int stringset)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index bdb7afaabdd0..400933ca1a29 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -669,16 +669,15 @@ static void hns_gmac_get_stats(void *mac_drv, u64 *data)
}
}
-static void hns_gmac_get_strings(u32 stringset, u8 *data)
+static void hns_gmac_get_strings(u32 stringset, u8 **data)
{
- u8 *buff = data;
u32 i;
if (stringset != ETH_SS_STATS)
return;
for (i = 0; i < ARRAY_SIZE(g_gmac_stats_string); i++)
- ethtool_puts(&buff, g_gmac_stats_string[i].desc);
+ ethtool_puts(data, 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_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 5fa9b2eeb929..bc6b269be299 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -1190,8 +1190,7 @@ void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data)
mac_ctrl_drv->get_ethtool_stats(mac_ctrl_drv, data);
}
-void hns_mac_get_strings(struct hns_mac_cb *mac_cb,
- int stringset, u8 *data)
+void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data)
{
struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index edf0bcf76ac9..630f01cf7a71 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -378,7 +378,7 @@ struct mac_driver {
void (*get_regs)(void *mac_drv, void *data);
int (*get_regs_count)(void);
/* get strings name for ethtool statistic */
- void (*get_strings)(u32 stringset, u8 *data);
+ void (*get_strings)(u32 stringset, u8 **data);
/* get the number of strings*/
int (*get_sset_count)(int stringset);
@@ -445,7 +445,7 @@ int hns_mac_config_mac_loopback(struct hns_mac_cb *mac_cb,
enum hnae_loop loop, int en);
void hns_mac_update_stats(struct hns_mac_cb *mac_cb);
void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data);
-void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 *data);
+void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data);
int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset);
void hns_mac_get_regs(struct hns_mac_cb *mac_cb, void *data);
int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index eb60f45a3460..851490346261 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -2590,55 +2590,34 @@ void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data)
p[i] = 0xdddddddd;
}
-static char *hns_dsaf_get_node_stats_strings(char *data, int node,
- struct dsaf_device *dsaf_dev)
+static void hns_dsaf_get_node_stats_strings(u8 **data, int node,
+ struct dsaf_device *dsaf_dev)
{
- char *buff = data;
- int i;
bool is_ver1 = AE_IS_VER1(dsaf_dev->dsaf_ver);
+ int i;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_pad_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_manage_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkt_id", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pause_frame", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_release_buf_num", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_sbm_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_crc_false_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_bp_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_lookup_rslt_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_local_rslt_fail_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_vlan_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
- snprintf(buff, ETH_GSTRING_LEN, "innod%d_stp_drop_pkts", node);
- buff += ETH_GSTRING_LEN;
+ ethtool_sprintf(data, "innod%d_pad_drop_pkts", node);
+ ethtool_sprintf(data, "innod%d_manage_pkts", node);
+ ethtool_sprintf(data, "innod%d_rx_pkts", node);
+ ethtool_sprintf(data, "innod%d_rx_pkt_id", node);
+ ethtool_sprintf(data, "innod%d_rx_pause_frame", node);
+ ethtool_sprintf(data, "innod%d_release_buf_num", node);
+ ethtool_sprintf(data, "innod%d_sbm_drop_pkts", node);
+ ethtool_sprintf(data, "innod%d_crc_false_pkts", node);
+ ethtool_sprintf(data, "innod%d_bp_drop_pkts", node);
+ ethtool_sprintf(data, "innod%d_lookup_rslt_drop_pkts", node);
+ ethtool_sprintf(data, "innod%d_local_rslt_fail_pkts", node);
+ ethtool_sprintf(data, "innod%d_vlan_drop_pkts", node);
+ ethtool_sprintf(data, "innod%d_stp_drop_pkts", node);
if (node < DSAF_SERVICE_NW_NUM && !is_ver1) {
for (i = 0; i < DSAF_PRIO_NR; i++) {
- snprintf(buff + 0 * ETH_GSTRING_LEN * DSAF_PRIO_NR,
- ETH_GSTRING_LEN, "inod%d_pfc_prio%d_pkts",
- node, i);
- snprintf(buff + 1 * ETH_GSTRING_LEN * DSAF_PRIO_NR,
- ETH_GSTRING_LEN, "onod%d_pfc_prio%d_pkts",
- node, i);
- buff += ETH_GSTRING_LEN;
+ ethtool_sprintf(data, "inod%d_pfc_prio%d_pkts", node,
+ i);
+ ethtool_sprintf(data, "onod%d_pfc_prio%d_pkts", node,
+ i);
}
- buff += 1 * DSAF_PRIO_NR * ETH_GSTRING_LEN;
}
- snprintf(buff, ETH_GSTRING_LEN, "onnod%d_tx_pkts", node);
- buff += ETH_GSTRING_LEN;
-
- return buff;
+ ethtool_sprintf(data, "onnod%d_tx_pkts", node);
}
static u64 *hns_dsaf_get_node_stats(struct dsaf_device *ddev, u64 *data,
@@ -2720,21 +2699,20 @@ int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset)
*@port:port index
*@dsaf_dev: dsaf device
*/
-void hns_dsaf_get_strings(int stringset, u8 *data, int port,
+void hns_dsaf_get_strings(int stringset, u8 **data, int port,
struct dsaf_device *dsaf_dev)
{
- char *buff = (char *)data;
int node = port;
if (stringset != ETH_SS_STATS)
return;
/* for ge/xge node info */
- buff = hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev);
+ hns_dsaf_get_node_stats_strings(data, node, dsaf_dev);
/* for ppe node info */
node = port + DSAF_PPE_INODE_BASE;
- (void)hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev);
+ hns_dsaf_get_node_stats_strings(data, node, dsaf_dev);
}
/**
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
index 5526a10caac5..0eb03dff1a8b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
@@ -442,7 +442,7 @@ void hns_dsaf_update_stats(struct dsaf_device *dsaf_dev, u32 inode_num);
int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset);
void hns_dsaf_get_stats(struct dsaf_device *ddev, u64 *data, int port);
-void hns_dsaf_get_strings(int stringset, u8 *data, int port,
+void hns_dsaf_get_strings(int stringset, u8 **data, int port,
struct dsaf_device *dsaf_dev);
void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index a08d1f0a5a16..5013beb4d282 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -457,24 +457,23 @@ int hns_ppe_get_regs_count(void)
* @stringset: string set type
* @data: output string
*/
-void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data)
+void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data)
{
int index = ppe_cb->index;
- u8 *buff = data;
-
- ethtool_sprintf(&buff, "ppe%d_rx_sw_pkt", index);
- ethtool_sprintf(&buff, "ppe%d_rx_pkt_ok", index);
- ethtool_sprintf(&buff, "ppe%d_rx_drop_pkt_no_bd", index);
- ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_fail", index);
- ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_wait", index);
- ethtool_sprintf(&buff, "ppe%d_rx_pkt_drop_no_buf", index);
- ethtool_sprintf(&buff, "ppe%d_rx_pkt_err_fifo_full", index);
-
- ethtool_sprintf(&buff, "ppe%d_tx_bd", index);
- ethtool_sprintf(&buff, "ppe%d_tx_pkt", index);
- ethtool_sprintf(&buff, "ppe%d_tx_pkt_ok", index);
- ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_fifo_empty", index);
- ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_csum_fail", index);
+
+ ethtool_sprintf(data, "ppe%d_rx_sw_pkt", index);
+ ethtool_sprintf(data, "ppe%d_rx_pkt_ok", index);
+ ethtool_sprintf(data, "ppe%d_rx_drop_pkt_no_bd", index);
+ ethtool_sprintf(data, "ppe%d_rx_alloc_buf_fail", index);
+ ethtool_sprintf(data, "ppe%d_rx_alloc_buf_wait", index);
+ ethtool_sprintf(data, "ppe%d_rx_pkt_drop_no_buf", index);
+ ethtool_sprintf(data, "ppe%d_rx_pkt_err_fifo_full", index);
+
+ ethtool_sprintf(data, "ppe%d_tx_bd", index);
+ ethtool_sprintf(data, "ppe%d_tx_pkt", index);
+ ethtool_sprintf(data, "ppe%d_tx_pkt_ok", index);
+ ethtool_sprintf(data, "ppe%d_tx_pkt_err_fifo_empty", index);
+ ethtool_sprintf(data, "ppe%d_tx_pkt_err_csum_fail", index);
}
void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
index 7e00231c1acf..602c8e971fe4 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
@@ -109,7 +109,7 @@ int hns_ppe_get_sset_count(int stringset);
int hns_ppe_get_regs_count(void);
void hns_ppe_get_regs(struct hns_ppe_cb *ppe_cb, void *data);
-void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data);
+void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data);
void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data);
void hns_ppe_set_tso_enable(struct hns_ppe_cb *ppe_cb, u32 value);
void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb,
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index 93344563a259..46af467aa596 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -923,44 +923,42 @@ int hns_rcb_get_ring_regs_count(void)
*@data:strings name value
*@index:queue index
*/
-void hns_rcb_get_strings(int stringset, u8 *data, int index)
+void hns_rcb_get_strings(int stringset, u8 **data, int index)
{
- u8 *buff = data;
-
if (stringset != ETH_SS_STATS)
return;
- ethtool_sprintf(&buff, "tx_ring%d_rcb_pkt_num", index);
- ethtool_sprintf(&buff, "tx_ring%d_ppe_tx_pkt_num", index);
- ethtool_sprintf(&buff, "tx_ring%d_ppe_drop_pkt_num", index);
- ethtool_sprintf(&buff, "tx_ring%d_fbd_num", index);
-
- ethtool_sprintf(&buff, "tx_ring%d_pkt_num", index);
- ethtool_sprintf(&buff, "tx_ring%d_bytes", index);
- ethtool_sprintf(&buff, "tx_ring%d_err_cnt", index);
- ethtool_sprintf(&buff, "tx_ring%d_io_err", index);
- ethtool_sprintf(&buff, "tx_ring%d_sw_err", index);
- ethtool_sprintf(&buff, "tx_ring%d_seg_pkt", index);
- ethtool_sprintf(&buff, "tx_ring%d_restart_queue", index);
- ethtool_sprintf(&buff, "tx_ring%d_tx_busy", index);
-
- ethtool_sprintf(&buff, "rx_ring%d_rcb_pkt_num", index);
- ethtool_sprintf(&buff, "rx_ring%d_ppe_pkt_num", index);
- ethtool_sprintf(&buff, "rx_ring%d_ppe_drop_pkt_num", index);
- ethtool_sprintf(&buff, "rx_ring%d_fbd_num", index);
-
- ethtool_sprintf(&buff, "rx_ring%d_pkt_num", index);
- ethtool_sprintf(&buff, "rx_ring%d_bytes", index);
- ethtool_sprintf(&buff, "rx_ring%d_err_cnt", index);
- ethtool_sprintf(&buff, "rx_ring%d_io_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_sw_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_seg_pkt", index);
- ethtool_sprintf(&buff, "rx_ring%d_reuse_pg", index);
- ethtool_sprintf(&buff, "rx_ring%d_len_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_non_vld_desc_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_bd_num_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_l2_err", index);
- ethtool_sprintf(&buff, "rx_ring%d_l3l4csum_err", index);
+ ethtool_sprintf(data, "tx_ring%d_rcb_pkt_num", index);
+ ethtool_sprintf(data, "tx_ring%d_ppe_tx_pkt_num", index);
+ ethtool_sprintf(data, "tx_ring%d_ppe_drop_pkt_num", index);
+ ethtool_sprintf(data, "tx_ring%d_fbd_num", index);
+
+ ethtool_sprintf(data, "tx_ring%d_pkt_num", index);
+ ethtool_sprintf(data, "tx_ring%d_bytes", index);
+ ethtool_sprintf(data, "tx_ring%d_err_cnt", index);
+ ethtool_sprintf(data, "tx_ring%d_io_err", index);
+ ethtool_sprintf(data, "tx_ring%d_sw_err", index);
+ ethtool_sprintf(data, "tx_ring%d_seg_pkt", index);
+ ethtool_sprintf(data, "tx_ring%d_restart_queue", index);
+ ethtool_sprintf(data, "tx_ring%d_tx_busy", index);
+
+ ethtool_sprintf(data, "rx_ring%d_rcb_pkt_num", index);
+ ethtool_sprintf(data, "rx_ring%d_ppe_pkt_num", index);
+ ethtool_sprintf(data, "rx_ring%d_ppe_drop_pkt_num", index);
+ ethtool_sprintf(data, "rx_ring%d_fbd_num", index);
+
+ ethtool_sprintf(data, "rx_ring%d_pkt_num", index);
+ ethtool_sprintf(data, "rx_ring%d_bytes", index);
+ ethtool_sprintf(data, "rx_ring%d_err_cnt", index);
+ ethtool_sprintf(data, "rx_ring%d_io_err", index);
+ ethtool_sprintf(data, "rx_ring%d_sw_err", index);
+ ethtool_sprintf(data, "rx_ring%d_seg_pkt", index);
+ ethtool_sprintf(data, "rx_ring%d_reuse_pg", index);
+ ethtool_sprintf(data, "rx_ring%d_len_err", index);
+ ethtool_sprintf(data, "rx_ring%d_non_vld_desc_err", index);
+ ethtool_sprintf(data, "rx_ring%d_bd_num_err", index);
+ ethtool_sprintf(data, "rx_ring%d_l2_err", index);
+ ethtool_sprintf(data, "rx_ring%d_l3l4csum_err", index);
}
void hns_rcb_get_common_regs(struct rcb_common_cb *rcb_com, void *data)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
index c1e9b6997853..0f4cc184ef39 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h
@@ -157,7 +157,7 @@ int hns_rcb_get_ring_regs_count(void);
void hns_rcb_get_ring_regs(struct hnae_queue *queue, void *data);
-void hns_rcb_get_strings(int stringset, u8 *data, int index);
+void hns_rcb_get_strings(int stringset, u8 **data, int index);
void hns_rcb_set_rx_ring_bs(struct hnae_queue *q, u32 buf_size);
void hns_rcb_set_tx_ring_bs(struct hnae_queue *q, u32 buf_size);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
index c58833eb4830..dbc44c2c26c2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
@@ -743,16 +743,15 @@ static void hns_xgmac_get_stats(void *mac_drv, u64 *data)
*@stringset: type of values in data
*@data:data for value of string name
*/
-static void hns_xgmac_get_strings(u32 stringset, u8 *data)
+static void hns_xgmac_get_strings(u32 stringset, u8 **data)
{
- u8 *buff = data;
u32 i;
if (stringset != ETH_SS_STATS)
return;
for (i = 0; i < ARRAY_SIZE(g_xgmac_stats_string); i++)
- ethtool_puts(&buff, g_xgmac_stats_string[i].desc);
+ ethtool_puts(data, 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 a5bb306b2cf1..6c458f037262 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -903,7 +903,6 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{
struct hns_nic_priv *priv = netdev_priv(netdev);
struct hnae_handle *h = priv->ae_handle;
- u8 *buff = data;
if (!h->dev->ops->get_strings) {
netdev_err(netdev, "h->dev->ops->get_strings is null!\n");
@@ -912,43 +911,43 @@ 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_puts(&buff,
+ ethtool_puts(&data,
hns_nic_test_strs[MAC_INTERNALLOOP_MAC]);
- ethtool_puts(&buff, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
+ ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
if ((netdev->phydev) && (!netdev->phydev->is_c45))
- ethtool_puts(&buff,
+ ethtool_puts(&data,
hns_nic_test_strs[MAC_INTERNALLOOP_PHY]);
} else {
- 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);
+ ethtool_puts(&data, "rx_packets");
+ ethtool_puts(&data, "tx_packets");
+ ethtool_puts(&data, "rx_bytes");
+ ethtool_puts(&data, "tx_bytes");
+ ethtool_puts(&data, "rx_errors");
+ ethtool_puts(&data, "tx_errors");
+ ethtool_puts(&data, "rx_dropped");
+ ethtool_puts(&data, "tx_dropped");
+ ethtool_puts(&data, "multicast");
+ ethtool_puts(&data, "collisions");
+ ethtool_puts(&data, "rx_over_errors");
+ ethtool_puts(&data, "rx_crc_errors");
+ ethtool_puts(&data, "rx_frame_errors");
+ ethtool_puts(&data, "rx_fifo_errors");
+ ethtool_puts(&data, "rx_missed_errors");
+ ethtool_puts(&data, "tx_aborted_errors");
+ ethtool_puts(&data, "tx_carrier_errors");
+ ethtool_puts(&data, "tx_fifo_errors");
+ ethtool_puts(&data, "tx_heartbeat_errors");
+ ethtool_puts(&data, "rx_length_errors");
+ ethtool_puts(&data, "tx_window_errors");
+ ethtool_puts(&data, "rx_compressed");
+ ethtool_puts(&data, "tx_compressed");
+ ethtool_puts(&data, "netdev_rx_dropped");
+ ethtool_puts(&data, "netdev_tx_dropped");
+
+ ethtool_puts(&data, "netdev_tx_timeout");
+
+ h->dev->ops->get_strings(h, stringset, &data);
}
}
@@ -970,7 +969,7 @@ static int hns_get_sset_count(struct net_device *netdev, int stringset)
return -EOPNOTSUPP;
}
if (stringset == ETH_SS_TEST) {
- u32 cnt = (sizeof(hns_nic_test_strs) / ETH_GSTRING_LEN);
+ u32 cnt = ARRAY_SIZE(hns_nic_test_strs);
if (priv->ae_handle->phy_if == PHY_INTERFACE_MODE_XGMII)
cnt--;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
index 67b0bf310daa..9a63fbc69408 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -25,8 +25,11 @@ void hnae3_unregister_ae_algo_prepare(struct hnae3_ae_algo *ae_algo)
pci_id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
if (!pci_id)
continue;
- if (IS_ENABLED(CONFIG_PCI_IOV))
+ if (IS_ENABLED(CONFIG_PCI_IOV)) {
+ device_lock(&ae_dev->pdev->dev);
pci_disable_sriov(ae_dev->pdev);
+ device_unlock(&ae_dev->pdev->dev);
+ }
}
}
EXPORT_SYMBOL(hnae3_unregister_ae_algo_prepare);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index 27dbe367f3d3..710a8f9f2248 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -677,7 +677,7 @@ struct hnae3_ae_ops {
void (*get_mac_stats)(struct hnae3_handle *handle,
struct hns3_mac_stats *mac_stats);
void (*get_strings)(struct hnae3_handle *handle,
- u32 stringset, u8 *data);
+ u32 stringset, u8 **data);
int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
void (*get_regs)(struct hnae3_handle *handle, u32 *version,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c
index 2b31188ff555..f9a3d6fc4416 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c
@@ -36,27 +36,22 @@ int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle)
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_sset_count);
-u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data)
+void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
- u8 *buff = data;
u16 i;
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_comm_tqp *tqp =
container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "txq%u_pktnum_rcd", tqp->index);
- buff += ETH_GSTRING_LEN;
+ ethtool_sprintf(data, "txq%u_pktnum_rcd", tqp->index);
}
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_comm_tqp *tqp =
container_of(kinfo->tqp[i], struct hclge_comm_tqp, q);
- snprintf(buff, ETH_GSTRING_LEN, "rxq%u_pktnum_rcd", tqp->index);
- buff += ETH_GSTRING_LEN;
+ ethtool_sprintf(data, "rxq%u_pktnum_rcd", tqp->index);
}
-
- return buff;
}
EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_strings);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h
index a46350162ee8..b9ff424c0bc2 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h
@@ -32,7 +32,7 @@ struct hclge_comm_tqp {
u64 *hclge_comm_tqps_get_stats(struct hnae3_handle *handle, u64 *data);
int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle);
-u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data);
+void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data);
void hclge_comm_reset_tqp_stats(struct hnae3_handle *handle);
int hclge_comm_tqps_update_stats(struct hnae3_handle *handle,
struct hclge_comm_hw *hw);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 4cbc4d069a1f..43377a7b2426 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -4448,7 +4448,7 @@ static void hns3_update_rx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector)
dim_update_sample(tqp_vector->event_cnt, rx_group->total_packets,
rx_group->total_bytes, &sample);
- net_dim(&rx_group->dim, sample);
+ net_dim(&rx_group->dim, &sample);
}
static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector)
@@ -4461,7 +4461,7 @@ static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector)
dim_update_sample(tqp_vector->event_cnt, tx_group->total_packets,
tx_group->total_bytes, &sample);
- net_dim(&tx_group->dim, sample);
+ net_dim(&tx_group->dim, &sample);
}
static int hns3_nic_common_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index b1e988347347..b771a2daba43 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -509,54 +509,37 @@ static int hns3_get_sset_count(struct net_device *netdev, int stringset)
}
}
-static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats,
- u32 stat_count, u32 num_tqps, const char *prefix)
+static void hns3_update_strings(u8 **data, const struct hns3_stats *stats,
+ u32 stat_count, u32 num_tqps,
+ const char *prefix)
{
-#define MAX_PREFIX_SIZE (6 + 4)
- u32 size_left;
u32 i, j;
- u32 n1;
- for (i = 0; i < num_tqps; i++) {
- for (j = 0; j < stat_count; j++) {
- data[ETH_GSTRING_LEN - 1] = '\0';
-
- /* first, prepend the prefix string */
- n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%u_",
- prefix, i);
- size_left = (ETH_GSTRING_LEN - 1) - n1;
-
- /* now, concatenate the stats string to it */
- strncat(data, stats[j].stats_string, size_left);
- data += ETH_GSTRING_LEN;
- }
- }
-
- return data;
+ for (i = 0; i < num_tqps; i++)
+ for (j = 0; j < stat_count; j++)
+ ethtool_sprintf(data, "%s%u_%s", prefix, i,
+ stats[j].stats_string);
}
-static u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data)
+static void hns3_get_strings_tqps(struct hnae3_handle *handle, u8 **data)
{
struct hnae3_knic_private_info *kinfo = &handle->kinfo;
const char tx_prefix[] = "txq";
const char rx_prefix[] = "rxq";
/* get strings for Tx */
- data = hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT,
- kinfo->num_tqps, tx_prefix);
+ hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT,
+ kinfo->num_tqps, tx_prefix);
/* get strings for Rx */
- data = hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT,
- kinfo->num_tqps, rx_prefix);
-
- return data;
+ hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT,
+ kinfo->num_tqps, rx_prefix);
}
static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = h->ae_algo->ops;
- char *buff = (char *)data;
int i;
if (!ops->get_strings)
@@ -564,18 +547,15 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
- buff = hns3_get_strings_tqps(h, buff);
- ops->get_strings(h, stringset, (u8 *)buff);
+ hns3_get_strings_tqps(h, &data);
+ ops->get_strings(h, stringset, &data);
break;
case ETH_SS_TEST:
- ops->get_strings(h, stringset, data);
+ ops->get_strings(h, stringset, &data);
break;
case ETH_SS_PRIV_FLAGS:
- for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) {
- snprintf(buff, ETH_GSTRING_LEN, "%s",
- hns3_priv_flags[i].name);
- buff += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++)
+ ethtool_puts(&data, hns3_priv_flags[i].name);
break;
default:
break;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index bd86efd92a5a..05942fa78b11 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -594,25 +594,21 @@ static u64 *hclge_comm_get_stats(struct hclge_dev *hdev,
return buf;
}
-static u8 *hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset,
- const struct hclge_comm_stats_str strs[],
- int size, u8 *data)
+static void hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset,
+ const struct hclge_comm_stats_str strs[],
+ int size, u8 **data)
{
- char *buff = (char *)data;
u32 i;
if (stringset != ETH_SS_STATS)
- return buff;
+ return;
for (i = 0; i < size; i++) {
if (strs[i].stats_num > hdev->ae_dev->dev_specs.mac_stats_num)
continue;
- snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc);
- buff = buff + ETH_GSTRING_LEN;
+ ethtool_puts(data, strs[i].desc);
}
-
- return (u8 *)buff;
}
static void hclge_update_stats_for_all(struct hclge_dev *hdev)
@@ -717,44 +713,38 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
}
static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset,
- u8 *data)
+ u8 **data)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
- u8 *p = (char *)data;
+ const char *str;
int size;
if (stringset == ETH_SS_STATS) {
size = ARRAY_SIZE(g_mac_stats_string);
- p = hclge_comm_get_strings(hdev, stringset, g_mac_stats_string,
- size, p);
- p = hclge_comm_tqps_get_strings(handle, p);
+ hclge_comm_get_strings(hdev, stringset, g_mac_stats_string,
+ size, data);
+ hclge_comm_tqps_get_strings(handle, data);
} else if (stringset == ETH_SS_TEST) {
if (handle->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK) {
- memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL];
+ ethtool_puts(data, str);
}
if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) {
- memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = hns3_nic_test_strs[HNAE3_LOOP_APP];
+ ethtool_puts(data, str);
}
if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) {
- memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES];
+ ethtool_puts(data, str);
}
if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) {
- memcpy(p,
- hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES];
+ ethtool_puts(data, str);
}
if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) {
- memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PHY],
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
+ str = hns3_nic_test_strs[HNAE3_LOOP_PHY];
+ ethtool_puts(data, str);
}
}
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
index 094a7c7b5592..2f6ffb88e700 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
@@ -130,12 +130,10 @@ static int hclgevf_get_sset_count(struct hnae3_handle *handle, int strset)
}
static void hclgevf_get_strings(struct hnae3_handle *handle, u32 strset,
- u8 *data)
+ u8 **data)
{
- u8 *p = (char *)data;
-
if (strset == ETH_SS_STATS)
- p = hclge_comm_tqps_get_strings(handle, p);
+ hclge_comm_tqps_get_strings(handle, data);
}
static void hclgevf_get_stats(struct hnae3_handle *handle, u64 *data)
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index dadd987efb6b..25b8a3556004 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -1727,6 +1727,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
/* NAPI poll context */
static int emac_poll_rx(void *param, int budget)
{
+ LIST_HEAD(rx_list);
struct emac_instance *dev = param;
int slot = dev->rx_slot, received = 0;
@@ -1783,8 +1784,7 @@ static int emac_poll_rx(void *param, int budget)
skb->protocol = eth_type_trans(skb, dev->ndev);
emac_rx_csum(dev, skb, ctrl);
- if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
- ++dev->estats.rx_dropped_stack;
+ list_add_tail(&skb->list, &rx_list);
next:
++dev->stats.rx_packets;
skip:
@@ -1828,6 +1828,8 @@ static int emac_poll_rx(void *param, int budget)
goto next;
}
+ netif_receive_skb_list(&rx_list);
+
if (received) {
DBG2(dev, "rx %d BDs" NL, received);
dev->rx_slot = slot;
@@ -2935,9 +2937,12 @@ static int emac_init_config(struct emac_instance *dev)
/* Read MAC-address */
err = of_get_ethdev_address(np, dev->ndev);
- if (err)
- return dev_err_probe(&dev->ofdev->dev, err,
- "Can't get valid [local-]mac-address from OF !\n");
+ if (err == -EPROBE_DEFER)
+ return err;
+ if (err) {
+ dev_warn(&dev->ofdev->dev, "Can't get valid mac-address. Generating random.");
+ eth_hw_addr_random(dev->ndev);
+ }
/* IAHT and GAHT filter parameterization */
if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) {
@@ -3019,8 +3024,14 @@ static int emac_probe(struct platform_device *ofdev)
SET_NETDEV_DEV(ndev, &ofdev->dev);
/* Initialize some embedded data structures */
- mutex_init(&dev->mdio_lock);
- mutex_init(&dev->link_lock);
+ err = devm_mutex_init(&ofdev->dev, &dev->mdio_lock);
+ if (err)
+ goto err_gone;
+
+ err = devm_mutex_init(&ofdev->dev, &dev->link_lock);
+ if (err)
+ goto err_gone;
+
spin_lock_init(&dev->lock);
INIT_WORK(&dev->reset_work, emac_reset_work);
@@ -3029,15 +3040,8 @@ static int emac_probe(struct platform_device *ofdev)
if (err)
goto err_gone;
- /* Get interrupts. EMAC irq is mandatory */
- dev->emac_irq = irq_of_parse_and_map(np, 0);
- if (!dev->emac_irq) {
- printk(KERN_ERR "%pOF: Can't map main interrupt\n", np);
- err = -ENODEV;
- goto err_gone;
- }
-
/* Setup error IRQ handler */
+ dev->emac_irq = platform_get_irq(ofdev, 0);
err = devm_request_irq(&ofdev->dev, dev->emac_irq, emac_irq, 0, "EMAC",
dev);
if (err) {
@@ -3048,12 +3052,10 @@ static int emac_probe(struct platform_device *ofdev)
ndev->irq = dev->emac_irq;
- /* Map EMAC regs */
- // TODO : platform_get_resource() and devm_ioremap_resource()
- dev->emacp = devm_of_iomap(&ofdev->dev, np, 0, NULL);
- if (!dev->emacp) {
+ dev->emacp = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->emacp)) {
dev_err(&ofdev->dev, "can't map device registers");
- err = -ENOMEM;
+ err = PTR_ERR(dev->emacp);
goto err_gone;
}
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index c634534710d9..7d70056e9008 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -524,7 +524,8 @@ static int mal_probe(struct platform_device *ofdev)
unsigned long irqflags;
irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
- mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
+ mal = devm_kzalloc(&ofdev->dev, sizeof(struct mal_instance),
+ GFP_KERNEL);
if (!mal)
return -ENOMEM;
@@ -539,8 +540,7 @@ static int mal_probe(struct platform_device *ofdev)
printk(KERN_ERR
"mal%d: can't find MAL num-tx-chans property!\n",
index);
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
mal->num_tx_chans = prop[0];
@@ -549,8 +549,7 @@ static int mal_probe(struct platform_device *ofdev)
printk(KERN_ERR
"mal%d: can't find MAL num-rx-chans property!\n",
index);
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
mal->num_rx_chans = prop[0];
@@ -558,15 +557,13 @@ static int mal_probe(struct platform_device *ofdev)
if (dcr_base == 0) {
printk(KERN_ERR
"mal%d: can't find DCR resource!\n", index);
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
mal->dcr_host = dcr_map(ofdev->dev.of_node, dcr_base, 0x100);
if (!DCR_MAP_OK(mal->dcr_host)) {
printk(KERN_ERR
"mal%d: failed to map DCRs !\n", index);
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
if (of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal-405ez")) {
@@ -582,25 +579,6 @@ static int mal_probe(struct platform_device *ofdev)
#endif
}
- mal->txeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
- mal->rxeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
- mal->serr_irq = irq_of_parse_and_map(ofdev->dev.of_node, 2);
-
- if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
- mal->txde_irq = mal->rxde_irq = mal->serr_irq;
- } else {
- mal->txde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 3);
- mal->rxde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 4);
- }
-
- if (!mal->txeob_irq || !mal->rxeob_irq || !mal->serr_irq ||
- !mal->txde_irq || !mal->rxde_irq) {
- printk(KERN_ERR
- "mal%d: failed to map interrupts !\n", index);
- err = -ENODEV;
- goto fail_unmap;
- }
-
INIT_LIST_HEAD(&mal->poll_list);
INIT_LIST_HEAD(&mal->list);
spin_lock_init(&mal->lock);
@@ -654,31 +632,43 @@ static int mal_probe(struct platform_device *ofdev)
sizeof(struct mal_descriptor) *
mal_rx_bd_offset(mal, i));
+ mal->txeob_irq = platform_get_irq(ofdev, 0);
+ mal->rxeob_irq = platform_get_irq(ofdev, 1);
+ mal->serr_irq = platform_get_irq(ofdev, 2);
+
if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
+ mal->txde_irq = mal->rxde_irq = mal->serr_irq;
irqflags = IRQF_SHARED;
hdlr_serr = hdlr_txde = hdlr_rxde = mal_int;
} else {
+ mal->txde_irq = platform_get_irq(ofdev, 3);
+ mal->rxde_irq = platform_get_irq(ofdev, 4);
irqflags = 0;
hdlr_serr = mal_serr;
hdlr_txde = mal_txde;
hdlr_rxde = mal_rxde;
}
- err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal);
+ err = devm_request_irq(&ofdev->dev, mal->serr_irq, hdlr_serr, irqflags,
+ "MAL SERR", mal);
if (err)
goto fail2;
- err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal);
+ err = devm_request_irq(&ofdev->dev, mal->txde_irq, hdlr_txde, irqflags,
+ "MAL TX DE", mal);
if (err)
- goto fail3;
- err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
+ goto fail2;
+ err = devm_request_irq(&ofdev->dev, mal->txeob_irq, mal_txeob, 0,
+ "MAL TX EOB", mal);
if (err)
- goto fail4;
- err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal);
+ goto fail2;
+ err = devm_request_irq(&ofdev->dev, mal->rxde_irq, hdlr_rxde, irqflags,
+ "MAL RX DE", mal);
if (err)
- goto fail5;
- err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
+ goto fail2;
+ err = devm_request_irq(&ofdev->dev, mal->rxeob_irq, mal_rxeob, 0,
+ "MAL RX EOB", mal);
if (err)
- goto fail6;
+ goto fail2;
/* Enable all MAL SERR interrupt sources */
set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
@@ -697,23 +687,12 @@ static int mal_probe(struct platform_device *ofdev)
return 0;
- fail6:
- free_irq(mal->rxde_irq, mal);
- fail5:
- free_irq(mal->txeob_irq, mal);
- fail4:
- free_irq(mal->txde_irq, mal);
- fail3:
- free_irq(mal->serr_irq, mal);
fail2:
dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
fail_dummy:
free_netdev(mal->dummy_dev);
fail_unmap:
dcr_unmap(mal->dcr_host, 0x100);
- fail:
- kfree(mal);
-
return err;
}
@@ -732,12 +711,6 @@ static void mal_remove(struct platform_device *ofdev)
"mal%d: commac list is not empty on remove!\n",
mal->index);
- free_irq(mal->serr_irq, mal);
- free_irq(mal->txde_irq, mal);
- free_irq(mal->txeob_irq, mal);
- free_irq(mal->rxde_irq, mal);
- free_irq(mal->rxeob_irq, mal);
-
mal_reset(mal);
free_netdev(mal->dummy_dev);
@@ -746,10 +719,9 @@ static void mal_remove(struct platform_device *ofdev)
dma_free_coherent(&ofdev->dev,
sizeof(struct mal_descriptor) *
- (NUM_TX_BUFF * mal->num_tx_chans +
- NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt,
- mal->bd_dma);
- kfree(mal);
+ (NUM_TX_BUFF * mal->num_tx_chans +
+ NUM_RX_BUFF * mal->num_rx_chans),
+ mal->bd_virt, mal->bd_dma);
}
static const struct of_device_id mal_platform_match[] =
diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c
index 317c22d09172..b544dd8633b7 100644
--- a/drivers/net/ethernet/ibm/emac/rgmii.c
+++ b/drivers/net/ethernet/ibm/emac/rgmii.c
@@ -216,31 +216,24 @@ void *rgmii_dump_regs(struct platform_device *ofdev, void *buf)
static int rgmii_probe(struct platform_device *ofdev)
{
- struct device_node *np = ofdev->dev.of_node;
struct rgmii_instance *dev;
- struct resource regs;
- int rc;
+ int err;
- rc = -ENOMEM;
- dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL);
- if (dev == NULL)
- goto err_gone;
+ dev = devm_kzalloc(&ofdev->dev, sizeof(struct rgmii_instance),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
- mutex_init(&dev->lock);
- dev->ofdev = ofdev;
+ err = devm_mutex_init(&ofdev->dev, &dev->lock);
+ if (err)
+ return err;
- rc = -ENXIO;
- if (of_address_to_resource(np, 0, &regs)) {
- printk(KERN_ERR "%pOF: Can't get registers address\n", np);
- goto err_free;
- }
+ dev->ofdev = ofdev;
- rc = -ENOMEM;
- dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start,
- sizeof(struct rgmii_regs));
- if (dev->base == NULL) {
- printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
- goto err_free;
+ dev->base = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->base)) {
+ dev_err(&ofdev->dev, "can't map device registers");
+ return PTR_ERR(dev->base);
}
/* Check for RGMII flags */
@@ -266,21 +259,6 @@ static int rgmii_probe(struct platform_device *ofdev)
platform_set_drvdata(ofdev, dev);
return 0;
-
- err_free:
- kfree(dev);
- err_gone:
- return rc;
-}
-
-static void rgmii_remove(struct platform_device *ofdev)
-{
- struct rgmii_instance *dev = platform_get_drvdata(ofdev);
-
- WARN_ON(dev->users != 0);
-
- iounmap(dev->base);
- kfree(dev);
}
static const struct of_device_id rgmii_match[] =
@@ -300,7 +278,6 @@ static struct platform_driver rgmii_driver = {
.of_match_table = rgmii_match,
},
.probe = rgmii_probe,
- .remove = rgmii_remove,
};
int __init rgmii_init(void)
diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index c605c8ff933e..09f6373ed2f9 100644
--- a/drivers/net/ethernet/ibm/emac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
@@ -87,31 +87,24 @@ void *tah_dump_regs(struct platform_device *ofdev, void *buf)
static int tah_probe(struct platform_device *ofdev)
{
- struct device_node *np = ofdev->dev.of_node;
struct tah_instance *dev;
- struct resource regs;
- int rc;
+ int err;
- rc = -ENOMEM;
- dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL);
- if (dev == NULL)
- goto err_gone;
+ dev = devm_kzalloc(&ofdev->dev, sizeof(struct tah_instance),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
- mutex_init(&dev->lock);
- dev->ofdev = ofdev;
+ err = devm_mutex_init(&ofdev->dev, &dev->lock);
+ if (err)
+ return err;
- rc = -ENXIO;
- if (of_address_to_resource(np, 0, &regs)) {
- printk(KERN_ERR "%pOF: Can't get registers address\n", np);
- goto err_free;
- }
+ dev->ofdev = ofdev;
- rc = -ENOMEM;
- dev->base = (struct tah_regs __iomem *)ioremap(regs.start,
- sizeof(struct tah_regs));
- if (dev->base == NULL) {
- printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
- goto err_free;
+ dev->base = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->base)) {
+ dev_err(&ofdev->dev, "can't map device registers");
+ return PTR_ERR(dev->base);
}
platform_set_drvdata(ofdev, dev);
@@ -123,21 +116,6 @@ static int tah_probe(struct platform_device *ofdev)
wmb();
return 0;
-
- err_free:
- kfree(dev);
- err_gone:
- return rc;
-}
-
-static void tah_remove(struct platform_device *ofdev)
-{
- struct tah_instance *dev = platform_get_drvdata(ofdev);
-
- WARN_ON(dev->users != 0);
-
- iounmap(dev->base);
- kfree(dev);
}
static const struct of_device_id tah_match[] =
@@ -158,7 +136,6 @@ static struct platform_driver tah_driver = {
.of_match_table = tah_match,
},
.probe = tah_probe,
- .remove = tah_remove,
};
int __init tah_init(void)
diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c
index 03bab3f95fe4..69ca6065de1c 100644
--- a/drivers/net/ethernet/ibm/emac/zmii.c
+++ b/drivers/net/ethernet/ibm/emac/zmii.c
@@ -232,32 +232,25 @@ void *zmii_dump_regs(struct platform_device *ofdev, void *buf)
static int zmii_probe(struct platform_device *ofdev)
{
- struct device_node *np = ofdev->dev.of_node;
struct zmii_instance *dev;
- struct resource regs;
- int rc;
+ int err;
- rc = -ENOMEM;
- dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL);
- if (dev == NULL)
- goto err_gone;
+ dev = devm_kzalloc(&ofdev->dev, sizeof(struct zmii_instance),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ err = devm_mutex_init(&ofdev->dev, &dev->lock);
+ if (err)
+ return err;
- mutex_init(&dev->lock);
dev->ofdev = ofdev;
dev->mode = PHY_INTERFACE_MODE_NA;
- rc = -ENXIO;
- if (of_address_to_resource(np, 0, &regs)) {
- printk(KERN_ERR "%pOF: Can't get registers address\n", np);
- goto err_free;
- }
-
- rc = -ENOMEM;
- dev->base = (struct zmii_regs __iomem *)ioremap(regs.start,
- sizeof(struct zmii_regs));
- if (dev->base == NULL) {
- printk(KERN_ERR "%pOF: Can't map device registers!\n", np);
- goto err_free;
+ dev->base = devm_platform_ioremap_resource(ofdev, 0);
+ if (IS_ERR(dev->base)) {
+ dev_err(&ofdev->dev, "can't map device registers");
+ return PTR_ERR(dev->base);
}
/* We may need FER value for autodetection later */
@@ -271,21 +264,6 @@ static int zmii_probe(struct platform_device *ofdev)
platform_set_drvdata(ofdev, dev);
return 0;
-
- err_free:
- kfree(dev);
- err_gone:
- return rc;
-}
-
-static void zmii_remove(struct platform_device *ofdev)
-{
- struct zmii_instance *dev = platform_get_drvdata(ofdev);
-
- WARN_ON(dev->users != 0);
-
- iounmap(dev->base);
- kfree(dev);
}
static const struct of_device_id zmii_match[] =
@@ -306,7 +284,6 @@ static struct platform_driver zmii_driver = {
.of_match_table = zmii_match,
},
.probe = zmii_probe,
- .remove = zmii_remove,
};
int __init zmii_init(void)
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index cca2ed6ad289..e95ae0d39948 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -3808,32 +3808,20 @@ static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
if (stringset != ETH_SS_STATS)
return;
- for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN)
- memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
+ for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++)
+ ethtool_puts(&data, ibmvnic_stats[i].name);
for (i = 0; i < adapter->req_tx_queues; i++) {
- snprintf(data, ETH_GSTRING_LEN, "tx%d_batched_packets", i);
- data += ETH_GSTRING_LEN;
-
- snprintf(data, ETH_GSTRING_LEN, "tx%d_direct_packets", i);
- data += ETH_GSTRING_LEN;
-
- snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i);
- data += ETH_GSTRING_LEN;
-
- snprintf(data, ETH_GSTRING_LEN, "tx%d_dropped_packets", i);
- data += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "tx%d_batched_packets", i);
+ ethtool_sprintf(&data, "tx%d_direct_packets", i);
+ ethtool_sprintf(&data, "tx%d_bytes", i);
+ ethtool_sprintf(&data, "tx%d_dropped_packets", i);
}
for (i = 0; i < adapter->req_rx_queues; i++) {
- snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i);
- data += ETH_GSTRING_LEN;
-
- snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i);
- data += ETH_GSTRING_LEN;
-
- snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i);
- data += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "rx%d_packets", i);
+ ethtool_sprintf(&data, "rx%d_bytes", i);
+ ethtool_sprintf(&data, "rx%d_interrupts", i);
}
}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 4de9b156b2be..3f089c3d47b2 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -3509,7 +3509,9 @@ static void e1000_reset_task(struct work_struct *work)
container_of(work, struct e1000_adapter, reset_task);
e_err(drv, "Reset adapter\n");
+ rtnl_lock();
e1000_reinit_locked(adapter);
+ rtnl_unlock();
}
/**
@@ -5074,7 +5076,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
usleep_range(10000, 20000);
WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
+ rtnl_lock();
e1000_down(adapter);
+ rtnl_unlock();
}
status = er32(STATUS);
@@ -5235,16 +5239,20 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
+ rtnl_lock();
netif_device_detach(netdev);
- if (state == pci_channel_io_perm_failure)
+ if (state == pci_channel_io_perm_failure) {
+ rtnl_unlock();
return PCI_ERS_RESULT_DISCONNECT;
+ }
if (netif_running(netdev))
e1000_down(adapter);
if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags))
pci_disable_device(pdev);
+ rtnl_unlock();
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index ce227b56cf72..2f9655cf5dd9 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1205,12 +1205,10 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
if (ret_val)
goto out;
- if (hw->mac.type != e1000_pch_mtp) {
- ret_val = e1000e_force_smbus(hw);
- if (ret_val) {
- e_dbg("Failed to force SMBUS: %d\n", ret_val);
- goto release;
- }
+ ret_val = e1000e_force_smbus(hw);
+ if (ret_val) {
+ e_dbg("Failed to force SMBUS: %d\n", ret_val);
+ goto release;
}
/* Si workaround for ULP entry flow on i127/rev6 h/w. Enable
@@ -1273,13 +1271,6 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
}
release:
- if (hw->mac.type == e1000_pch_mtp) {
- ret_val = e1000e_force_smbus(hw);
- if (ret_val)
- e_dbg("Failed to force SMBUS over MTL system: %d\n",
- ret_val);
- }
-
hw->phy.ops.release(hw);
out:
if (ret_val)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 2089a0e172bf..d4255c2706fa 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -755,6 +755,7 @@ enum i40e_filter_state {
I40E_FILTER_ACTIVE, /* Added to switch by FW */
I40E_FILTER_FAILED, /* Rejected by FW */
I40E_FILTER_REMOVE, /* To be removed */
+ I40E_FILTER_NEW_SYNC, /* New, not sent yet, is in i40e_sync_vsi_filters() */
/* There is no 'removed' state; the filter struct is freed */
};
struct i40e_mac_filter {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index abf624d770e6..208c2f0857b6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -89,6 +89,7 @@ static char *i40e_filter_state_string[] = {
"ACTIVE",
"FAILED",
"REMOVE",
+ "NEW_SYNC",
};
/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 25295ae370b2..ab5febf83ec3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -1255,6 +1255,7 @@ int i40e_count_filters(struct i40e_vsi *vsi)
hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_NEW ||
+ f->state == I40E_FILTER_NEW_SYNC ||
f->state == I40E_FILTER_ACTIVE)
++cnt;
}
@@ -1441,6 +1442,8 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
new->f = add_head;
new->state = add_head->state;
+ if (add_head->state == I40E_FILTER_NEW)
+ add_head->state = I40E_FILTER_NEW_SYNC;
/* Add the new filter to the tmp list */
hlist_add_head(&new->hlist, tmp_add_list);
@@ -1550,6 +1553,8 @@ static int i40e_correct_vf_mac_vlan_filters(struct i40e_vsi *vsi,
return -ENOMEM;
new_mac->f = add_head;
new_mac->state = add_head->state;
+ if (add_head->state == I40E_FILTER_NEW)
+ add_head->state = I40E_FILTER_NEW_SYNC;
/* Add the new filter to the tmp list */
hlist_add_head(&new_mac->hlist, tmp_add_list);
@@ -2437,7 +2442,8 @@ static int
i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
struct i40e_mac_filter *f)
{
- bool enable = f->state == I40E_FILTER_NEW;
+ bool enable = f->state == I40E_FILTER_NEW ||
+ f->state == I40E_FILTER_NEW_SYNC;
struct i40e_hw *hw = &vsi->back->hw;
int aq_ret;
@@ -2611,6 +2617,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* Add it to the hash list */
hlist_add_head(&new->hlist, &tmp_add_list);
+ f->state = I40E_FILTER_NEW_SYNC;
}
/* Count the number of active (current and new) VLAN
@@ -2762,7 +2769,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
spin_lock_bh(&vsi->mac_filter_hash_lock);
hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) {
/* Only update the state if we're still NEW */
- if (new->f->state == I40E_FILTER_NEW)
+ if (new->f->state == I40E_FILTER_NEW ||
+ new->f->state == I40E_FILTER_NEW_SYNC)
new->f->state = new->state;
hlist_del(&new->hlist);
netdev_hw_addr_refcnt(new->f, vsi->netdev, -1);
@@ -13087,12 +13095,13 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
* @addr: the MAC address entry being added
* @vid: VLAN ID
* @flags: instructions from stack about fdb operation
+ * @notified: whether notification was emitted
* @extack: netlink extended ack, unused currently
*/
static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
- u16 flags,
+ u16 flags, bool *notified,
struct netlink_ext_ack *extack)
{
struct i40e_netdev_priv *np = netdev_priv(dev);
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
index 928c8bdb6649..c6779d9dffff 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink_port.c
@@ -989,5 +989,11 @@ ice_devlink_port_new(struct devlink *devlink,
if (err)
return err;
+ if (!ice_is_eswitch_mode_switchdev(pf)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "SF ports are only supported in eswitch switchdev mode");
+ return -EOPNOTSUPP;
+ }
+
return ice_alloc_dynamic_port(pf, new_attr, extack, devlink_port);
}
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 680a81961ba1..2f5d6f974185 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -181,11 +181,9 @@
#define ice_for_each_chnl_tc(i) \
for ((i) = ICE_CHNL_START_TC; (i) < ICE_CHNL_MAX_TC; (i)++)
-#define ICE_UCAST_PROMISC_BITS (ICE_PROMISC_UCAST_TX | ICE_PROMISC_UCAST_RX)
+#define ICE_UCAST_PROMISC_BITS ICE_PROMISC_UCAST_RX
-#define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_TX | \
- ICE_PROMISC_UCAST_RX | \
- ICE_PROMISC_VLAN_TX | \
+#define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_RX | \
ICE_PROMISC_VLAN_RX)
#define ICE_MCAST_PROMISC_BITS (ICE_PROMISC_MCAST_TX | ICE_PROMISC_MCAST_RX)
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 1f01f3501d6b..1489a8ceec51 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1492,6 +1492,23 @@ struct ice_aqc_dnl_equa_param {
#define ICE_AQC_RX_EQU_BFLF (0x13 << ICE_AQC_RX_EQU_SHIFT)
#define ICE_AQC_RX_EQU_BFHF (0x14 << ICE_AQC_RX_EQU_SHIFT)
#define ICE_AQC_RX_EQU_DRATE (0x15 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_CTLE_GAINHF (0x20 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_CTLE_GAINLF (0x21 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_CTLE_GAINDC (0x22 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_CTLE_BW (0x23 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_GAIN (0x30 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_GAIN2 (0x31 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_2 (0x32 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_3 (0x33 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_4 (0x34 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_5 (0x35 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_6 (0x36 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_7 (0x37 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_8 (0x38 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_9 (0x39 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_10 (0x3A << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_11 (0x3B << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DFE_12 (0x3C << ICE_AQC_RX_EQU_SHIFT)
#define ICE_AQC_TX_EQU_PRE1 0x0
#define ICE_AQC_TX_EQU_PRE3 0x3
#define ICE_AQC_TX_EQU_ATTEN 0x4
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 3a8e156d7d86..82a9cd4ec7ae 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -156,7 +156,8 @@ skip_alloc:
* handler here (i.e. resume, reset/rebuild, etc.)
*/
if (vsi->netdev)
- netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll);
+ netif_napi_add_config(vsi->netdev, &q_vector->napi,
+ ice_napi_poll, v_idx);
out:
/* tie q_vector and VSI together */
diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c
index 272fd823a825..03988be03729 100644
--- a/drivers/net/ethernet/intel/ice/ice_ddp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ddp.c
@@ -1211,6 +1211,131 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
}
/**
+ * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
+ * @buf: pointer to buffer header
+ * Return: whether given @buf is a metadata one.
+ */
+static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
+{
+ return le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF;
+}
+
+/**
+ * struct ice_ddp_send_ctx - sending context of current DDP segment
+ * @hw: pointer to the hardware struct
+ *
+ * Keeps current sending state (header, error) for the purpose of proper "last"
+ * bit setting in ice_aq_download_pkg(). Use via calls to ice_ddp_send_hunk().
+ */
+struct ice_ddp_send_ctx {
+ struct ice_hw *hw;
+/* private: only for ice_ddp_send_hunk() */
+ struct ice_buf_hdr *hdr;
+ int err;
+};
+
+static void ice_ddp_send_ctx_set_err(struct ice_ddp_send_ctx *ctx, int err)
+{
+ ctx->err = err;
+}
+
+/**
+ * ice_ddp_send_hunk - send one hunk of data to FW
+ * @ctx: current segment sending context
+ * @hunk: next hunk to send, size is always ICE_PKG_BUF_SIZE
+ *
+ * Send the next hunk of data to FW, retrying if needed.
+ *
+ * Notice: must be called once more with a NULL @hunk to finish up; such call
+ * will set up the "last" bit of an AQ request. After such call @ctx.hdr is
+ * cleared, @hw is still valid.
+ *
+ * Return: %ICE_DDP_PKG_SUCCESS if there were no problems; a sticky @err
+ * otherwise.
+ */
+static enum ice_ddp_state ice_ddp_send_hunk(struct ice_ddp_send_ctx *ctx,
+ struct ice_buf_hdr *hunk)
+{
+ struct ice_buf_hdr *prev_hunk = ctx->hdr;
+ struct ice_hw *hw = ctx->hw;
+ bool prev_was_last = !hunk;
+ enum ice_aq_err aq_err;
+ u32 offset, info;
+ int attempt, err;
+
+ if (ctx->err)
+ return ctx->err;
+
+ ctx->hdr = hunk;
+ if (!prev_hunk)
+ return ICE_DDP_PKG_SUCCESS; /* no problem so far */
+
+ for (attempt = 0; attempt < 5; attempt++) {
+ if (attempt)
+ msleep(20);
+
+ err = ice_aq_download_pkg(hw, prev_hunk, ICE_PKG_BUF_SIZE,
+ prev_was_last, &offset, &info, NULL);
+
+ aq_err = hw->adminq.sq_last_status;
+ if (aq_err != ICE_AQ_RC_ENOSEC && aq_err != ICE_AQ_RC_EBADSIG)
+ break;
+ }
+
+ if (err) {
+ ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
+ err, offset, info);
+ ctx->err = ice_map_aq_err_to_ddp_state(aq_err);
+ } else if (attempt) {
+ dev_dbg(ice_hw_to_dev(hw),
+ "ice_aq_download_pkg number of retries: %d\n", attempt);
+ }
+
+ return ctx->err;
+}
+
+/**
+ * ice_dwnld_cfg_bufs_no_lock
+ * @ctx: context of the current buffers section to send
+ * @bufs: pointer to an array of buffers
+ * @start: buffer index of first buffer to download
+ * @count: the number of buffers to download
+ *
+ * Downloads package configuration buffers to the firmware. Metadata buffers
+ * are skipped, and the first metadata buffer found indicates that the rest
+ * of the buffers are all metadata buffers.
+ */
+static enum ice_ddp_state
+ice_dwnld_cfg_bufs_no_lock(struct ice_ddp_send_ctx *ctx, struct ice_buf *bufs,
+ u32 start, u32 count)
+{
+ struct ice_buf_hdr *bh;
+ enum ice_ddp_state err;
+
+ if (!bufs || !count) {
+ ice_ddp_send_ctx_set_err(ctx, ICE_DDP_PKG_ERR);
+ return ICE_DDP_PKG_ERR;
+ }
+
+ bufs += start;
+
+ for (int i = 0; i < count; i++, bufs++) {
+ bh = (struct ice_buf_hdr *)bufs;
+ /* Metadata buffers should not be sent to FW,
+ * their presence means "we are done here".
+ */
+ if (ice_is_buffer_metadata(bh))
+ break;
+
+ err = ice_ddp_send_hunk(ctx, bh);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
* ice_get_pkg_seg_by_idx
* @pkg_hdr: pointer to the package header to be searched
* @idx: index of segment
@@ -1270,136 +1395,20 @@ ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx,
}
/**
- * ice_is_buffer_metadata - determine if package buffer is a metadata buffer
- * @buf: pointer to buffer header
- */
-static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf)
-{
- if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF)
- return true;
-
- return false;
-}
-
-/**
- * ice_is_last_download_buffer
- * @buf: pointer to current buffer header
- * @idx: index of the buffer in the current sequence
- * @count: the buffer count in the current sequence
- *
- * Note: this routine should only be called if the buffer is not the last buffer
- */
-static bool
-ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count)
-{
- struct ice_buf *next_buf;
-
- if ((idx + 1) == count)
- return true;
-
- /* A set metadata flag in the next buffer will signal that the current
- * buffer will be the last buffer downloaded
- */
- next_buf = ((struct ice_buf *)buf) + 1;
-
- return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf);
-}
-
-/**
- * ice_dwnld_cfg_bufs_no_lock
- * @hw: pointer to the hardware structure
- * @bufs: pointer to an array of buffers
- * @start: buffer index of first buffer to download
- * @count: the number of buffers to download
- * @indicate_last: if true, then set last buffer flag on last buffer download
- *
- * Downloads package configuration buffers to the firmware. Metadata buffers
- * are skipped, and the first metadata buffer found indicates that the rest
- * of the buffers are all metadata buffers.
- */
-static enum ice_ddp_state
-ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start,
- u32 count, bool indicate_last)
-{
- enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS;
- struct ice_buf_hdr *bh;
- enum ice_aq_err err;
- u32 offset, info, i;
-
- if (!bufs || !count)
- return ICE_DDP_PKG_ERR;
-
- /* If the first buffer's first section has its metadata bit set
- * then there are no buffers to be downloaded, and the operation is
- * considered a success.
- */
- bh = (struct ice_buf_hdr *)(bufs + start);
- if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
- return ICE_DDP_PKG_SUCCESS;
-
- for (i = 0; i < count; i++) {
- bool last = false;
- int try_cnt = 0;
- int status;
-
- bh = (struct ice_buf_hdr *)(bufs + start + i);
-
- if (indicate_last)
- last = ice_is_last_download_buffer(bh, i, count);
-
- while (1) {
- status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE,
- last, &offset, &info,
- NULL);
- if (hw->adminq.sq_last_status != ICE_AQ_RC_ENOSEC &&
- hw->adminq.sq_last_status != ICE_AQ_RC_EBADSIG)
- break;
-
- try_cnt++;
-
- if (try_cnt == 5)
- break;
-
- msleep(20);
- }
-
- if (try_cnt)
- dev_dbg(ice_hw_to_dev(hw),
- "ice_aq_download_pkg number of retries: %d\n",
- try_cnt);
-
- /* Save AQ status from download package */
- if (status) {
- ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n",
- status, offset, info);
- err = hw->adminq.sq_last_status;
- state = ice_map_aq_err_to_ddp_state(err);
- break;
- }
-
- if (last)
- break;
- }
-
- return state;
-}
-
-/**
* ice_download_pkg_sig_seg - download a signature segment
- * @hw: pointer to the hardware structure
+ * @ctx: context of the current buffers section to send
* @seg: pointer to signature segment
*/
static enum ice_ddp_state
-ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
+ice_download_pkg_sig_seg(struct ice_ddp_send_ctx *ctx, struct ice_sign_seg *seg)
{
- return ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0,
- le32_to_cpu(seg->buf_tbl.buf_count),
- false);
+ return ice_dwnld_cfg_bufs_no_lock(ctx, seg->buf_tbl.buf_array, 0,
+ le32_to_cpu(seg->buf_tbl.buf_count));
}
/**
* ice_download_pkg_config_seg - download a config segment
- * @hw: pointer to the hardware structure
+ * @ctx: context of the current buffers section to send
* @pkg_hdr: pointer to package header
* @idx: segment index
* @start: starting buffer
@@ -1408,8 +1417,9 @@ ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg)
* Note: idx must reference a ICE segment
*/
static enum ice_ddp_state
-ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
- u32 idx, u32 start, u32 count)
+ice_download_pkg_config_seg(struct ice_ddp_send_ctx *ctx,
+ struct ice_pkg_hdr *pkg_hdr, u32 idx, u32 start,
+ u32 count)
{
struct ice_buf_table *bufs;
struct ice_seg *seg;
@@ -1425,46 +1435,56 @@ ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
if (start >= buf_count || start + count > buf_count)
return ICE_DDP_PKG_ERR;
- return ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count,
- true);
+ return ice_dwnld_cfg_bufs_no_lock(ctx, bufs->buf_array, start, count);
+}
+
+static bool ice_is_last_sign_seg(u32 flags)
+{
+ return !(flags & ICE_SIGN_SEG_FLAGS_VALID) || /* behavior prior to valid */
+ (flags & ICE_SIGN_SEG_FLAGS_LAST);
}
/**
* ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment
- * @hw: pointer to the hardware structure
+ * @ctx: context of the current buffers section to send
* @pkg_hdr: pointer to package header
* @idx: segment index (must be a signature segment)
*
* Note: idx must reference a signature segment
*/
static enum ice_ddp_state
-ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr,
- u32 idx)
+ice_dwnld_sign_and_cfg_segs(struct ice_ddp_send_ctx *ctx,
+ struct ice_pkg_hdr *pkg_hdr, u32 idx)
{
+ u32 conf_idx, start, count, flags;
enum ice_ddp_state state;
struct ice_sign_seg *seg;
- u32 conf_idx;
- u32 start;
- u32 count;
seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx);
if (!seg) {
state = ICE_DDP_PKG_ERR;
- goto exit;
+ ice_ddp_send_ctx_set_err(ctx, state);
+ return state;
}
count = le32_to_cpu(seg->signed_buf_count);
- state = ice_download_pkg_sig_seg(hw, seg);
+ state = ice_download_pkg_sig_seg(ctx, seg);
if (state || !count)
- goto exit;
+ return state;
conf_idx = le32_to_cpu(seg->signed_seg_idx);
start = le32_to_cpu(seg->signed_buf_start);
- state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start,
+ state = ice_download_pkg_config_seg(ctx, pkg_hdr, conf_idx, start,
count);
-exit:
+ /* finish up by sending last hunk with "last" flag set if requested by
+ * DDP content
+ */
+ flags = le32_to_cpu(seg->flags);
+ if (ice_is_last_sign_seg(flags))
+ state = ice_ddp_send_hunk(ctx, NULL);
+
return state;
}
@@ -1519,6 +1539,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
{
enum ice_aq_err aq_err = hw->adminq.sq_last_status;
enum ice_ddp_state state = ICE_DDP_PKG_ERR;
+ struct ice_ddp_send_ctx ctx = { .hw = hw };
int status;
u32 i;
@@ -1539,7 +1560,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
hw->pkg_sign_type))
continue;
- state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i);
+ state = ice_dwnld_sign_and_cfg_segs(&ctx, pkg_hdr, i);
if (state)
break;
}
@@ -1564,6 +1585,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
static enum ice_ddp_state
ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
{
+ struct ice_ddp_send_ctx ctx = { .hw = hw };
enum ice_ddp_state state;
struct ice_buf_hdr *bh;
int status;
@@ -1576,7 +1598,7 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
* considered a success.
*/
bh = (struct ice_buf_hdr *)bufs;
- if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF)
+ if (ice_is_buffer_metadata(bh))
return ICE_DDP_PKG_SUCCESS;
status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
@@ -1586,7 +1608,9 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status);
}
- state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true);
+ ice_dwnld_cfg_bufs_no_lock(&ctx, bufs, 0, count);
+ /* finish up by sending last hunk with "last" flag set */
+ state = ice_ddp_send_hunk(&ctx, NULL);
if (!state)
state = ice_post_dwnld_pkg_actions(hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.h b/drivers/net/ethernet/intel/ice/ice_ddp.h
index 79551da2a4b0..8a2d57fc5dae 100644
--- a/drivers/net/ethernet/intel/ice/ice_ddp.h
+++ b/drivers/net/ethernet/intel/ice/ice_ddp.h
@@ -181,7 +181,10 @@ struct ice_sign_seg {
__le32 signed_seg_idx;
__le32 signed_buf_start;
__le32 signed_buf_count;
-#define ICE_SIGN_SEG_RESERVED_COUNT 44
+#define ICE_SIGN_SEG_FLAGS_VALID 0x80000000
+#define ICE_SIGN_SEG_FLAGS_LAST 0x00000001
+ __le32 flags;
+#define ICE_SIGN_SEG_RESERVED_COUNT 40
u8 reserved[ICE_SIGN_SEG_RESERVED_COUNT];
struct ice_buf_table buf_tbl;
};
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 74c0e7319a4c..d5ad6d84007c 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -10,6 +10,7 @@
#define ICE_DPLL_PIN_IDX_INVALID 0xff
#define ICE_DPLL_RCLK_NUM_PER_PF 1
#define ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT 25
+#define ICE_DPLL_PIN_GEN_RCLK_FREQ 1953125
/**
* enum ice_dpll_pin_type - enumerate ice pin types:
@@ -2064,6 +2065,73 @@ static int ice_dpll_init_worker(struct ice_pf *pf)
}
/**
+ * ice_dpll_init_info_pins_generic - initializes generic pins info
+ * @pf: board private structure
+ * @input: if input pins initialized
+ *
+ * Init information for generic pins, cache them in PF's pins structures.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_init_info_pins_generic(struct ice_pf *pf, bool input)
+{
+ struct ice_dpll *de = &pf->dplls.eec, *dp = &pf->dplls.pps;
+ static const char labels[][sizeof("99")] = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15" };
+ u32 cap = DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ enum ice_dpll_pin_type pin_type;
+ int i, pin_num, ret = -EINVAL;
+ struct ice_dpll_pin *pins;
+ u32 phase_adj_max;
+
+ if (input) {
+ pin_num = pf->dplls.num_inputs;
+ pins = pf->dplls.inputs;
+ phase_adj_max = pf->dplls.input_phase_adj_max;
+ pin_type = ICE_DPLL_PIN_TYPE_INPUT;
+ cap |= DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE;
+ } else {
+ pin_num = pf->dplls.num_outputs;
+ pins = pf->dplls.outputs;
+ phase_adj_max = pf->dplls.output_phase_adj_max;
+ pin_type = ICE_DPLL_PIN_TYPE_OUTPUT;
+ }
+ if (pin_num > ARRAY_SIZE(labels))
+ return ret;
+
+ for (i = 0; i < pin_num; i++) {
+ pins[i].idx = i;
+ pins[i].prop.board_label = labels[i];
+ pins[i].prop.phase_range.min = phase_adj_max;
+ pins[i].prop.phase_range.max = -phase_adj_max;
+ pins[i].prop.capabilities = cap;
+ pins[i].pf = pf;
+ ret = ice_dpll_pin_state_update(pf, &pins[i], pin_type, NULL);
+ if (ret)
+ break;
+ if (input && pins[i].freq == ICE_DPLL_PIN_GEN_RCLK_FREQ)
+ pins[i].prop.type = DPLL_PIN_TYPE_MUX;
+ else
+ pins[i].prop.type = DPLL_PIN_TYPE_EXT;
+ if (!input)
+ continue;
+ ret = ice_aq_get_cgu_ref_prio(&pf->hw, de->dpll_idx, i,
+ &de->input_prio[i]);
+ if (ret)
+ break;
+ ret = ice_aq_get_cgu_ref_prio(&pf->hw, dp->dpll_idx, i,
+ &dp->input_prio[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/**
* ice_dpll_init_info_direct_pins - initializes direct pins info
* @pf: board private structure
* @pin_type: type of pins being initialized
@@ -2101,6 +2169,8 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
default:
return -EINVAL;
}
+ if (num_pins != ice_cgu_get_num_pins(hw, input))
+ return ice_dpll_init_info_pins_generic(pf, input);
for (i = 0; i < num_pins; i++) {
caps = 0;
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index c0b3e70a7ea3..fb527434b58b 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -552,13 +552,14 @@ int ice_eswitch_attach_sf(struct ice_pf *pf, struct ice_dynamic_port *sf)
static void ice_eswitch_detach(struct ice_pf *pf, struct ice_repr *repr)
{
ice_eswitch_stop_reprs(pf);
+ repr->ops.rem(repr);
+
xa_erase(&pf->eswitch.reprs, repr->id);
if (xa_empty(&pf->eswitch.reprs))
ice_eswitch_disable_switchdev(pf);
ice_eswitch_release_repr(pf, repr);
- repr->ops.rem(repr);
ice_repr_destroy(repr);
if (xa_empty(&pf->eswitch.reprs)) {
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 2924ac61300d..3072634bf049 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -693,75 +693,53 @@ static int ice_get_port_topology(struct ice_hw *hw, u8 lport,
static int ice_get_tx_rx_equa(struct ice_hw *hw, u8 serdes_num,
struct ice_serdes_equalization_to_ethtool *ptr)
{
+ static const int tx = ICE_AQC_OP_CODE_TX_EQU;
+ static const int rx = ICE_AQC_OP_CODE_RX_EQU;
+ struct {
+ int data_in;
+ int opcode;
+ int *out;
+ } aq_params[] = {
+ { ICE_AQC_TX_EQU_PRE1, tx, &ptr->tx_equ_pre1 },
+ { ICE_AQC_TX_EQU_PRE3, tx, &ptr->tx_equ_pre3 },
+ { ICE_AQC_TX_EQU_ATTEN, tx, &ptr->tx_equ_atten },
+ { ICE_AQC_TX_EQU_POST1, tx, &ptr->tx_equ_post1 },
+ { ICE_AQC_TX_EQU_PRE2, tx, &ptr->tx_equ_pre2 },
+ { ICE_AQC_RX_EQU_PRE2, rx, &ptr->rx_equ_pre2 },
+ { ICE_AQC_RX_EQU_PRE1, rx, &ptr->rx_equ_pre1 },
+ { ICE_AQC_RX_EQU_POST1, rx, &ptr->rx_equ_post1 },
+ { ICE_AQC_RX_EQU_BFLF, rx, &ptr->rx_equ_bflf },
+ { ICE_AQC_RX_EQU_BFHF, rx, &ptr->rx_equ_bfhf },
+ { ICE_AQC_RX_EQU_DRATE, rx, &ptr->rx_equ_drate },
+ { ICE_AQC_RX_EQU_CTLE_GAINHF, rx, &ptr->rx_equ_ctle_gainhf },
+ { ICE_AQC_RX_EQU_CTLE_GAINLF, rx, &ptr->rx_equ_ctle_gainlf },
+ { ICE_AQC_RX_EQU_CTLE_GAINDC, rx, &ptr->rx_equ_ctle_gaindc },
+ { ICE_AQC_RX_EQU_CTLE_BW, rx, &ptr->rx_equ_ctle_bw },
+ { ICE_AQC_RX_EQU_DFE_GAIN, rx, &ptr->rx_equ_dfe_gain },
+ { ICE_AQC_RX_EQU_DFE_GAIN2, rx, &ptr->rx_equ_dfe_gain_2 },
+ { ICE_AQC_RX_EQU_DFE_2, rx, &ptr->rx_equ_dfe_2 },
+ { ICE_AQC_RX_EQU_DFE_3, rx, &ptr->rx_equ_dfe_3 },
+ { ICE_AQC_RX_EQU_DFE_4, rx, &ptr->rx_equ_dfe_4 },
+ { ICE_AQC_RX_EQU_DFE_5, rx, &ptr->rx_equ_dfe_5 },
+ { ICE_AQC_RX_EQU_DFE_6, rx, &ptr->rx_equ_dfe_6 },
+ { ICE_AQC_RX_EQU_DFE_7, rx, &ptr->rx_equ_dfe_7 },
+ { ICE_AQC_RX_EQU_DFE_8, rx, &ptr->rx_equ_dfe_8 },
+ { ICE_AQC_RX_EQU_DFE_9, rx, &ptr->rx_equ_dfe_9 },
+ { ICE_AQC_RX_EQU_DFE_10, rx, &ptr->rx_equ_dfe_10 },
+ { ICE_AQC_RX_EQU_DFE_11, rx, &ptr->rx_equ_dfe_11 },
+ { ICE_AQC_RX_EQU_DFE_12, rx, &ptr->rx_equ_dfe_12 },
+ };
int err;
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE1,
- ICE_AQC_OP_CODE_TX_EQU, serdes_num,
- &ptr->tx_equalization_pre1);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE3,
- ICE_AQC_OP_CODE_TX_EQU, serdes_num,
- &ptr->tx_equalization_pre3);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_ATTEN,
- ICE_AQC_OP_CODE_TX_EQU, serdes_num,
- &ptr->tx_equalization_atten);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_POST1,
- ICE_AQC_OP_CODE_TX_EQU, serdes_num,
- &ptr->tx_equalization_post1);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE2,
- ICE_AQC_OP_CODE_TX_EQU, serdes_num,
- &ptr->tx_equalization_pre2);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE2,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_pre2);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE1,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_pre1);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_POST1,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_post1);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFLF,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_bflf);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFHF,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_bfhf);
- if (err)
- return err;
-
- err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_DRATE,
- ICE_AQC_OP_CODE_RX_EQU, serdes_num,
- &ptr->rx_equalization_drate);
- if (err)
- return err;
+ for (int i = 0; i < ARRAY_SIZE(aq_params); i++) {
+ err = ice_aq_get_phy_equalization(hw, aq_params[i].data_in,
+ aq_params[i].opcode,
+ serdes_num, aq_params[i].out);
+ if (err)
+ break;
+ }
- return 0;
+ return err;
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.h b/drivers/net/ethernet/intel/ice/ice_ethtool.h
index 9acccae38625..8f2ad1c172c0 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.h
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.h
@@ -10,17 +10,34 @@ struct ice_phy_type_to_ethtool {
};
struct ice_serdes_equalization_to_ethtool {
- int rx_equalization_pre2;
- int rx_equalization_pre1;
- int rx_equalization_post1;
- int rx_equalization_bflf;
- int rx_equalization_bfhf;
- int rx_equalization_drate;
- int tx_equalization_pre1;
- int tx_equalization_pre3;
- int tx_equalization_atten;
- int tx_equalization_post1;
- int tx_equalization_pre2;
+ int rx_equ_pre2;
+ int rx_equ_pre1;
+ int rx_equ_post1;
+ int rx_equ_bflf;
+ int rx_equ_bfhf;
+ int rx_equ_drate;
+ int rx_equ_ctle_gainhf;
+ int rx_equ_ctle_gainlf;
+ int rx_equ_ctle_gaindc;
+ int rx_equ_ctle_bw;
+ int rx_equ_dfe_gain;
+ int rx_equ_dfe_gain_2;
+ int rx_equ_dfe_2;
+ int rx_equ_dfe_3;
+ int rx_equ_dfe_4;
+ int rx_equ_dfe_5;
+ int rx_equ_dfe_6;
+ int rx_equ_dfe_7;
+ int rx_equ_dfe_8;
+ int rx_equ_dfe_9;
+ int rx_equ_dfe_10;
+ int rx_equ_dfe_11;
+ int rx_equ_dfe_12;
+ int tx_equ_pre1;
+ int tx_equ_pre3;
+ int tx_equ_atten;
+ int tx_equ_post1;
+ int tx_equ_pre2;
};
struct ice_regdump_to_ethtool {
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
index 5412eff8ef23..ee9862ddfe15 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
@@ -1830,11 +1830,12 @@ static int
ice_set_fdir_input_set(struct ice_vsi *vsi, struct ethtool_rx_flow_spec *fsp,
struct ice_fdir_fltr *input)
{
- u16 dest_vsi, q_index = 0;
+ s16 q_index = ICE_FDIR_NO_QUEUE_IDX;
u16 orig_q_index = 0;
struct ice_pf *pf;
struct ice_hw *hw;
int flow_type;
+ u16 dest_vsi;
u8 dest_ctl;
if (!vsi || !fsp || !input)
diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.h b/drivers/net/ethernet/intel/ice/ice_fdir.h
index ab5b118daa2d..820023c0271f 100644
--- a/drivers/net/ethernet/intel/ice/ice_fdir.h
+++ b/drivers/net/ethernet/intel/ice/ice_fdir.h
@@ -53,6 +53,8 @@
*/
#define ICE_FDIR_IPV4_PKT_FLAG_MF 0x20
+#define ICE_FDIR_NO_QUEUE_IDX -1
+
enum ice_fltr_prgm_desc_dest {
ICE_FLTR_PRGM_DESC_DEST_DROP_PKT,
ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX,
@@ -186,7 +188,7 @@ struct ice_fdir_fltr {
u16 flex_fltr;
/* filter control */
- u16 q_index;
+ s16 q_index;
u16 orig_q_index;
u16 dest_vsi;
u8 dest_ctl;
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index d4e74f96a8ad..a7d45a8ce7ac 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -2777,8 +2777,10 @@ void ice_napi_add(struct ice_vsi *vsi)
return;
ice_for_each_q_vector(vsi, v_idx)
- netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
- ice_napi_poll);
+ netif_napi_add_config(vsi->netdev,
+ &vsi->q_vectors[v_idx]->napi,
+ ice_napi_poll,
+ v_idx);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index a6f586f9bfd1..1eaa4428fd24 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4555,6 +4555,34 @@ ice_init_tx_topology(struct ice_hw *hw, const struct firmware *firmware)
}
/**
+ * ice_init_supported_rxdids - Initialize supported Rx descriptor IDs
+ * @hw: pointer to the hardware structure
+ * @pf: pointer to pf structure
+ *
+ * The pf->supported_rxdids bitmap is used to indicate to VFs which descriptor
+ * formats the PF hardware supports. The exact list of supported RXDIDs
+ * depends on the loaded DDP package. The IDs can be determined by reading the
+ * GLFLXP_RXDID_FLAGS register after the DDP package is loaded.
+ *
+ * Note that the legacy 32-byte RXDID 0 is always supported but is not listed
+ * in the DDP package. The 16-byte legacy descriptor is never supported by
+ * VFs.
+ */
+static void ice_init_supported_rxdids(struct ice_hw *hw, struct ice_pf *pf)
+{
+ pf->supported_rxdids = BIT(ICE_RXDID_LEGACY_1);
+
+ for (int i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) {
+ u32 regval;
+
+ regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0));
+ if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S)
+ & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M)
+ pf->supported_rxdids |= BIT(i);
+ }
+}
+
+/**
* ice_init_ddp_config - DDP related configuration
* @hw: pointer to the hardware structure
* @pf: pointer to pf structure
@@ -4588,6 +4616,9 @@ static int ice_init_ddp_config(struct ice_hw *hw, struct ice_pf *pf)
ice_load_pkg(firmware, pf);
release_firmware(firmware);
+ /* Initialize the supported Rx descriptor IDs after loading DDP */
+ ice_init_supported_rxdids(hw, pf);
+
return 0;
}
@@ -5900,7 +5931,7 @@ static int __init ice_module_init(void)
ice_adv_lnk_speed_maps_init();
- ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME);
+ ice_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, KBUILD_MODNAME);
if (!ice_wq) {
pr_err("Failed to create workqueue\n");
return status;
@@ -6125,12 +6156,14 @@ ice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate)
* @addr: the MAC address entry being added
* @vid: VLAN ID
* @flags: instructions from stack about fdb operation
+ * @notified: whether notification was emitted
* @extack: netlink extended ack
*/
static int
ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
struct net_device *dev, const unsigned char *addr, u16 vid,
- u16 flags, struct netlink_ext_ack __always_unused *extack)
+ u16 flags, bool *notified,
+ struct netlink_ext_ack __always_unused *extack)
{
int err;
@@ -6164,12 +6197,14 @@ ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
* @dev: the net device pointer
* @addr: the MAC address entry being added
* @vid: VLAN ID
+ * @notified: whether notification was emitted
* @extack: netlink extended ack
*/
static int
ice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[],
struct net_device *dev, const unsigned char *addr,
- __always_unused u16 vid, struct netlink_ext_ack *extack)
+ __always_unused u16 vid, bool *notified,
+ struct netlink_ext_ack *extack)
{
int err;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index da88c6ccfaeb..dfd49732bd5b 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -34,7 +34,6 @@ static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = {
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
{ "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS,
ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz },
- { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, 0, },
};
static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = {
@@ -52,7 +51,6 @@ static const struct ice_cgu_pin_desc ice_e810t_qsfp_cgu_inputs[] = {
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
{ "GNSS-1PPS", ZL_REF4P, DPLL_PIN_TYPE_GNSS,
ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz },
- { "OCXO", ZL_REF4N, DPLL_PIN_TYPE_INT_OSCILLATOR, },
};
static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_outputs[] = {
@@ -6048,6 +6046,25 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size)
}
/**
+ * ice_cgu_get_num_pins - get pin description array size
+ * @hw: pointer to the hw struct
+ * @input: if request is done against input or output pins
+ *
+ * Return: size of pin description array for given hw.
+ */
+int ice_cgu_get_num_pins(struct ice_hw *hw, bool input)
+{
+ const struct ice_cgu_pin_desc *t;
+ int size;
+
+ t = ice_cgu_get_pin_desc(hw, input, &size);
+ if (t)
+ return size;
+
+ return 0;
+}
+
+/**
* ice_cgu_get_pin_type - get pin's type
* @hw: pointer to the hw struct
* @pin: pin index
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 656daff3447e..47af7c5c79b8 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -406,6 +406,7 @@ int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl(struct ice_hw *hw, u8 data);
int ice_read_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data);
int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries);
+int ice_cgu_get_num_pins(struct ice_hw *hw, bool input);
enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input);
struct dpll_pin_frequency *
ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num);
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 8208055d6e7f..5d2d7736fd5f 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1352,14 +1352,14 @@ static void ice_net_dim(struct ice_q_vector *q_vector)
struct dim_sample dim_sample;
__ice_update_sample(q_vector, tx, &dim_sample, true);
- net_dim(&tx->dim, dim_sample);
+ net_dim(&tx->dim, &dim_sample);
}
if (ITR_IS_DYNAMIC(rx)) {
struct dim_sample dim_sample;
__ice_update_sample(q_vector, rx, &dim_sample, false);
- net_dim(&rx->dim, dim_sample);
+ net_dim(&rx->dim, &dim_sample);
}
}
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
index aa2080747714..f445e33b2028 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
@@ -2554,17 +2554,27 @@ static bool ice_is_vlan_promisc_allowed(struct ice_vf *vf)
/**
* ice_vf_ena_vlan_promisc - Enable Tx/Rx VLAN promiscuous for the VLAN
+ * @vf: VF to enable VLAN promisc on
* @vsi: VF's VSI used to enable VLAN promiscuous mode
* @vlan: VLAN used to enable VLAN promiscuous
*
* This function should only be called if VLAN promiscuous mode is allowed,
* which can be determined via ice_is_vlan_promisc_allowed().
*/
-static int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan)
+static int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi,
+ struct ice_vlan *vlan)
{
- u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX;
+ u8 promisc_m = 0;
int status;
+ if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states))
+ promisc_m |= ICE_UCAST_VLAN_PROMISC_BITS;
+ if (test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
+ promisc_m |= ICE_MCAST_VLAN_PROMISC_BITS;
+
+ if (!promisc_m)
+ return 0;
+
status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m,
vlan->vid);
if (status && status != -EEXIST)
@@ -2583,7 +2593,7 @@ static int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan)
*/
static int ice_vf_dis_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan)
{
- u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX;
+ u8 promisc_m = ICE_UCAST_VLAN_PROMISC_BITS | ICE_MCAST_VLAN_PROMISC_BITS;
int status;
status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m,
@@ -2738,7 +2748,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
goto error_param;
}
} else if (vlan_promisc) {
- status = ice_vf_ena_vlan_promisc(vsi, &vlan);
+ status = ice_vf_ena_vlan_promisc(vf, vsi, &vlan);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n",
@@ -3021,12 +3031,8 @@ err:
static int ice_vc_query_rxdid(struct ice_vf *vf)
{
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
- struct virtchnl_supported_rxdids *rxdid = NULL;
- struct ice_hw *hw = &vf->pf->hw;
+ struct virtchnl_supported_rxdids rxdid = {};
struct ice_pf *pf = vf->pf;
- int len = 0;
- int ret, i;
- u32 regval;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
@@ -3038,35 +3044,11 @@ static int ice_vc_query_rxdid(struct ice_vf *vf)
goto err;
}
- len = sizeof(struct virtchnl_supported_rxdids);
- rxdid = kzalloc(len, GFP_KERNEL);
- if (!rxdid) {
- v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
- len = 0;
- goto err;
- }
-
- /* RXDIDs supported by DDP package can be read from the register
- * to get the supported RXDID bitmap. But the legacy 32byte RXDID
- * is not listed in DDP package, add it in the bitmap manually.
- * Legacy 16byte descriptor is not supported.
- */
- rxdid->supported_rxdids |= BIT(ICE_RXDID_LEGACY_1);
-
- for (i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) {
- regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0));
- if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S)
- & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M)
- rxdid->supported_rxdids |= BIT(i);
- }
-
- pf->supported_rxdids = rxdid->supported_rxdids;
+ rxdid.supported_rxdids = pf->supported_rxdids;
err:
- ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS,
- v_ret, (u8 *)rxdid, len);
- kfree(rxdid);
- return ret;
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS,
+ v_ret, (u8 *)&rxdid, sizeof(rxdid));
}
/**
@@ -3575,7 +3557,7 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
return err;
if (vlan_promisc) {
- err = ice_vf_ena_vlan_promisc(vsi, &vlan);
+ err = ice_vf_ena_vlan_promisc(vf, vsi, &vlan);
if (err)
return err;
}
@@ -3603,7 +3585,8 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
*/
if (!ice_is_dvm_ena(&vsi->back->hw)) {
if (vlan_promisc) {
- err = ice_vf_ena_vlan_promisc(vsi, &vlan);
+ err = ice_vf_ena_vlan_promisc(vf, vsi,
+ &vlan);
if (err)
return err;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index 2c31ad87587a..66544faab710 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -141,6 +141,7 @@ enum idpf_vport_state {
* @adapter: Adapter back pointer
* @vport: Vport back pointer
* @vport_id: Vport identifier
+ * @link_speed_mbps: Link speed in mbps
* @vport_idx: Relative vport index
* @state: See enum idpf_vport_state
* @netstats: Packet and byte stats
@@ -150,6 +151,7 @@ struct idpf_netdev_priv {
struct idpf_adapter *adapter;
struct idpf_vport *vport;
u32 vport_id;
+ u32 link_speed_mbps;
u16 vport_idx;
enum idpf_vport_state state;
struct rtnl_link_stats64 netstats;
@@ -287,7 +289,6 @@ struct idpf_port_stats {
* @tx_itr_profile: TX profiles for Dynamic Interrupt Moderation
* @port_stats: per port csum, header split, and other offload stats
* @link_up: True if link is up
- * @link_speed_mbps: Link speed in mbps
* @sw_marker_wq: workqueue for marker packets
*/
struct idpf_vport {
@@ -331,7 +332,6 @@ struct idpf_vport {
struct idpf_port_stats port_stats;
bool link_up;
- u32 link_speed_mbps;
wait_queue_head_t sw_marker_wq;
};
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 3806ddd3ce4a..59b1a1a09996 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -1296,24 +1296,19 @@ static void idpf_set_msglevel(struct net_device *netdev, u32 data)
static int idpf_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings *cmd)
{
- struct idpf_vport *vport;
-
- idpf_vport_ctrl_lock(netdev);
- vport = idpf_netdev_to_vport(netdev);
+ struct idpf_netdev_priv *np = netdev_priv(netdev);
ethtool_link_ksettings_zero_link_mode(cmd, supported);
cmd->base.autoneg = AUTONEG_DISABLE;
cmd->base.port = PORT_NONE;
- if (vport->link_up) {
+ if (netif_carrier_ok(netdev)) {
cmd->base.duplex = DUPLEX_FULL;
- cmd->base.speed = vport->link_speed_mbps;
+ cmd->base.speed = np->link_speed_mbps;
} else {
cmd->base.duplex = DUPLEX_UNKNOWN;
cmd->base.speed = SPEED_UNKNOWN;
}
- idpf_vport_ctrl_unlock(netdev);
-
return 0;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 4f20343e49a9..b4fbb99bfad2 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1786,6 +1786,7 @@ static int idpf_init_hard_reset(struct idpf_adapter *adapter)
*/
err = idpf_vc_core_init(adapter);
if (err) {
+ cancel_delayed_work_sync(&adapter->mbx_task);
idpf_deinit_dflt_mbx(adapter);
goto unlock_mutex;
}
@@ -1860,7 +1861,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
* mess with. Nothing below should use those variables from new_vport
* and should instead always refer to them in vport if they need to.
*/
- memcpy(new_vport, vport, offsetof(struct idpf_vport, link_speed_mbps));
+ memcpy(new_vport, vport, offsetof(struct idpf_vport, link_up));
/* Adjust resource parameters prior to reallocating resources */
switch (reset_cause) {
@@ -1906,7 +1907,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
/* Same comment as above regarding avoiding copying the wait_queues and
* mutexes applies here. We do not want to mess with those if possible.
*/
- memcpy(vport, new_vport, offsetof(struct idpf_vport, link_speed_mbps));
+ memcpy(vport, new_vport, offsetof(struct idpf_vport, link_up));
if (reset_cause == IDPF_SR_Q_CHANGE)
idpf_vport_alloc_vec_indexes(vport);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index d4e6f0e10487..da2a5becf62f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3679,7 +3679,7 @@ static void idpf_net_dim(struct idpf_q_vector *q_vector)
idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->tx_dim,
packets, bytes);
- net_dim(&q_vector->tx_dim, dim_sample);
+ net_dim(&q_vector->tx_dim, &dim_sample);
check_rx_itr:
if (!IDPF_ITR_IS_DYNAMIC(q_vector->rx_intr_mode))
@@ -3698,7 +3698,7 @@ check_rx_itr:
idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->rx_dim,
packets, bytes);
- net_dim(&q_vector->rx_dim, dim_sample);
+ net_dim(&q_vector->rx_dim, &dim_sample);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 15c00a01f1c0..d46c95f91b0d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -141,7 +141,7 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter,
}
np = netdev_priv(vport->netdev);
- vport->link_speed_mbps = le32_to_cpu(v2e->link_speed);
+ np->link_speed_mbps = le32_to_cpu(v2e->link_speed);
if (vport->link_up == v2e->link_status)
return;
@@ -3063,7 +3063,6 @@ init_failed:
adapter->state = __IDPF_VER_CHECK;
if (adapter->vcxn_mngr)
idpf_vc_xn_shutdown(adapter->vcxn_mngr);
- idpf_deinit_dflt_mbx(adapter);
set_bit(IDPF_HR_DRV_LOAD, adapter->flags);
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
msecs_to_jiffies(task_delay));
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index f1d088168723..08578980b651 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1204,7 +1204,7 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
/* initialize pointer to rings */
ring = q_vector->ring;
- /* intialize ITR */
+ /* initialize ITR */
if (rxr_count) {
/* rx or rx/tx vector */
if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3)
@@ -2486,7 +2486,7 @@ static int igb_set_features(struct net_device *netdev,
static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
- u16 flags,
+ u16 flags, bool *notified,
struct netlink_ext_ack *extack)
{
/* guarantee we can provide a unique filter for the unicast address */
@@ -3906,7 +3906,7 @@ static void igb_remove(struct pci_dev *pdev)
*
* This function initializes the vf specific data storage and then attempts to
* allocate the VFs. The reason for ordering it this way is because it is much
- * mor expensive time wise to disable SR-IOV than it is to allocate and free
+ * more expensive time wise to disable SR-IOV than it is to allocate and free
* the memory for the VFs.
**/
static void igb_probe_vfs(struct igb_adapter *adapter)
diff --git a/drivers/net/ethernet/intel/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h
index 6ad35a00a287..ca6e44245a7b 100644
--- a/drivers/net/ethernet/intel/igbvf/igbvf.h
+++ b/drivers/net/ethernet/intel/igbvf/igbvf.h
@@ -169,8 +169,6 @@ struct igbvf_adapter {
u16 link_speed;
u16 link_duplex;
- spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
-
/* track device up/down/testing state */
unsigned long state;
@@ -220,7 +218,6 @@ struct igbvf_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
- spinlock_t stats_lock; /* prevent concurrent stats updates */
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 925d7286a8ee..02044aa2181b 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -1656,12 +1656,9 @@ static int igbvf_sw_init(struct igbvf_adapter *adapter)
if (igbvf_alloc_queues(adapter))
return -ENOMEM;
- spin_lock_init(&adapter->tx_queue_lock);
-
/* Explicitly disable IRQ since the NIC can be in any state. */
igbvf_irq_disable(adapter);
- spin_lock_init(&adapter->stats_lock);
spin_lock_init(&adapter->hw.mbx_lock);
set_bit(__IGBVF_DOWN, &adapter->state);
diff --git a/drivers/net/ethernet/intel/igc/igc_diag.c b/drivers/net/ethernet/intel/igc/igc_diag.c
index cc621970c0cd..a43d7244ee70 100644
--- a/drivers/net/ethernet/intel/igc/igc_diag.c
+++ b/drivers/net/ethernet/intel/igc/igc_diag.c
@@ -173,8 +173,7 @@ bool igc_link_test(struct igc_adapter *adapter, u64 *data)
*data = 0;
/* add delay to give enough time for autonegotioation to finish */
- if (adapter->hw.mac.autoneg)
- ssleep(5);
+ ssleep(5);
link_up = igc_has_link(adapter);
if (!link_up) {
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 5b0c6f433767..817838677817 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1821,11 +1821,8 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
/* set autoneg settings */
- if (hw->mac.autoneg == 1) {
- ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
- ethtool_link_ksettings_add_link_mode(cmd, advertising,
- Autoneg);
- }
+ ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
/* Set pause flow control settings */
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
@@ -1878,10 +1875,7 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
cmd->base.duplex = DUPLEX_UNKNOWN;
}
cmd->base.speed = speed;
- if (hw->mac.autoneg)
- cmd->base.autoneg = AUTONEG_ENABLE;
- else
- cmd->base.autoneg = AUTONEG_DISABLE;
+ cmd->base.autoneg = AUTONEG_ENABLE;
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if (hw->phy.media_type == igc_media_type_copper)
@@ -1955,7 +1949,6 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
advertised |= ADVERTISE_10_HALF;
if (cmd->base.autoneg == AUTONEG_ENABLE) {
- hw->mac.autoneg = 1;
hw->phy.autoneg_advertised = advertised;
if (adapter->fc_autoneg)
hw->fc.requested_mode = igc_fc_default;
diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h
index e1c572e0d4ef..d9d1a1a11daf 100644
--- a/drivers/net/ethernet/intel/igc/igc_hw.h
+++ b/drivers/net/ethernet/intel/igc/igc_hw.h
@@ -92,7 +92,6 @@ struct igc_mac_info {
bool asf_firmware_present;
bool arc_subsystem_valid;
- bool autoneg;
bool autoneg_failed;
bool get_link_status;
};
diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c
index a5c4b19d71a2..d344e0a1cd5e 100644
--- a/drivers/net/ethernet/intel/igc/igc_mac.c
+++ b/drivers/net/ethernet/intel/igc/igc_mac.c
@@ -386,14 +386,6 @@ s32 igc_check_for_copper_link(struct igc_hw *hw)
*/
igc_check_downshift(hw);
- /* If we are forcing speed/duplex, then we simply return since
- * we have already determined whether we have link or not.
- */
- if (!mac->autoneg) {
- ret_val = -IGC_ERR_CONFIG;
- goto out;
- }
-
/* Auto-Neg is enabled. Auto Speed Detection takes care
* of MAC speed/duplex configuration. So we only need to
* configure Collision Distance in the MAC.
@@ -468,173 +460,171 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
goto out;
}
- /* Check for the case where we have copper media and auto-neg is
- * enabled. In this case, we need to check and see if Auto-Neg
- * has completed, and if so, how the PHY and link partner has
- * flow control configured.
+ /* In auto-neg, we need to check and see if Auto-Neg has completed,
+ * and if so, how the PHY and link partner has flow control
+ * configured.
*/
- if (mac->autoneg) {
- /* Read the MII Status Register and check to see if AutoNeg
- * has completed. We read this twice because this reg has
- * some "sticky" (latched) bits.
- */
- ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
- &mii_status_reg);
- if (ret_val)
- goto out;
- ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
- &mii_status_reg);
- if (ret_val)
- goto out;
- if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
- hw_dbg("Copper PHY and Auto Neg has not completed.\n");
- goto out;
- }
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
+ &mii_status_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
+ &mii_status_reg);
+ if (ret_val)
+ goto out;
- /* The AutoNeg process has completed, so we now need to
- * read both the Auto Negotiation Advertisement
- * Register (Address 4) and the Auto_Negotiation Base
- * Page Ability Register (Address 5) to determine how
- * flow control was negotiated.
- */
- ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
- &mii_nway_adv_reg);
- if (ret_val)
- goto out;
- ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
- &mii_nway_lp_ability_reg);
- if (ret_val)
- goto out;
- /* Two bits in the Auto Negotiation Advertisement Register
- * (Address 4) and two bits in the Auto Negotiation Base
- * Page Ability Register (Address 5) determine flow control
- * for both the PHY and the link partner. The following
- * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
- * 1999, describes these PAUSE resolution bits and how flow
- * control is determined based upon these settings.
- * NOTE: DC = Don't Care
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
- *-------|---------|-------|---------|--------------------
- * 0 | 0 | DC | DC | igc_fc_none
- * 0 | 1 | 0 | DC | igc_fc_none
- * 0 | 1 | 1 | 0 | igc_fc_none
- * 0 | 1 | 1 | 1 | igc_fc_tx_pause
- * 1 | 0 | 0 | DC | igc_fc_none
- * 1 | DC | 1 | DC | igc_fc_full
- * 1 | 1 | 0 | 0 | igc_fc_none
- * 1 | 1 | 0 | 1 | igc_fc_rx_pause
- *
- * Are both PAUSE bits set to 1? If so, this implies
- * Symmetric Flow Control is enabled at both ends. The
- * ASM_DIR bits are irrelevant per the spec.
- *
- * For Symmetric Flow Control:
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | DC | 1 | DC | IGC_fc_full
- *
- */
- if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
- /* Now we need to check if the user selected RX ONLY
- * of pause frames. In this case, we had to advertise
- * FULL flow control because we could not advertise RX
- * ONLY. Hence, we must now check to see if we need to
- * turn OFF the TRANSMISSION of PAUSE frames.
- */
- if (hw->fc.requested_mode == igc_fc_full) {
- hw->fc.current_mode = igc_fc_full;
- hw_dbg("Flow Control = FULL.\n");
- } else {
- hw->fc.current_mode = igc_fc_rx_pause;
- hw_dbg("Flow Control = RX PAUSE frames only.\n");
- }
- }
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ hw_dbg("Copper PHY and Auto Neg has not completed.\n");
+ goto out;
+ }
- /* For receiving PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 0 | 1 | 1 | 1 | igc_fc_tx_pause
- */
- else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.current_mode = igc_fc_tx_pause;
- hw_dbg("Flow Control = TX PAUSE frames only.\n");
- }
- /* For transmitting PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | 1 | 0 | 1 | igc_fc_rx_pause
- */
- else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.current_mode = igc_fc_rx_pause;
- hw_dbg("Flow Control = RX PAUSE frames only.\n");
- }
- /* Per the IEEE spec, at this point flow control should be
- * disabled. However, we want to consider that we could
- * be connected to a legacy switch that doesn't advertise
- * desired flow control, but can be forced on the link
- * partner. So if we advertised no flow control, that is
- * what we will resolve to. If we advertised some kind of
- * receive capability (Rx Pause Only or Full Flow Control)
- * and the link partner advertised none, we will configure
- * ourselves to enable Rx Flow Control only. We can do
- * this safely for two reasons: If the link partner really
- * didn't want flow control enabled, and we enable Rx, no
- * harm done since we won't be receiving any PAUSE frames
- * anyway. If the intent on the link partner was to have
- * flow control enabled, then by us enabling RX only, we
- * can at least receive pause frames and process them.
- * This is a good idea because in most cases, since we are
- * predominantly a server NIC, more times than not we will
- * be asked to delay transmission of packets than asking
- * our link partner to pause transmission of frames.
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+ &mii_nway_adv_reg);
+ if (ret_val)
+ goto out;
+ ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
+ &mii_nway_lp_ability_reg);
+ if (ret_val)
+ goto out;
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | igc_fc_none
+ * 0 | 1 | 0 | DC | igc_fc_none
+ * 0 | 1 | 1 | 0 | igc_fc_none
+ * 0 | 1 | 1 | 1 | igc_fc_tx_pause
+ * 1 | 0 | 0 | DC | igc_fc_none
+ * 1 | DC | 1 | DC | igc_fc_full
+ * 1 | 1 | 0 | 0 | igc_fc_none
+ * 1 | 1 | 0 | 1 | igc_fc_rx_pause
+ *
+ * Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | IGC_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
*/
- else if ((hw->fc.requested_mode == igc_fc_none) ||
- (hw->fc.requested_mode == igc_fc_tx_pause) ||
- (hw->fc.strict_ieee)) {
- hw->fc.current_mode = igc_fc_none;
- hw_dbg("Flow Control = NONE.\n");
+ if (hw->fc.requested_mode == igc_fc_full) {
+ hw->fc.current_mode = igc_fc_full;
+ hw_dbg("Flow Control = FULL.\n");
} else {
hw->fc.current_mode = igc_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\n");
}
+ }
- /* Now we need to do one last check... If we auto-
- * negotiated to HALF DUPLEX, flow control should not be
- * enabled per IEEE 802.3 spec.
- */
- ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
- if (ret_val) {
- hw_dbg("Error getting link speed and duplex\n");
- goto out;
- }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | igc_fc_tx_pause
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = igc_fc_tx_pause;
+ hw_dbg("Flow Control = TX PAUSE frames only.\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | igc_fc_rx_pause
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc.current_mode = igc_fc_rx_pause;
+ hw_dbg("Flow Control = RX PAUSE frames only.\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if ((hw->fc.requested_mode == igc_fc_none) ||
+ (hw->fc.requested_mode == igc_fc_tx_pause) ||
+ (hw->fc.strict_ieee)) {
+ hw->fc.current_mode = igc_fc_none;
+ hw_dbg("Flow Control = NONE.\n");
+ } else {
+ hw->fc.current_mode = igc_fc_rx_pause;
+ hw_dbg("Flow Control = RX PAUSE frames only.\n");
+ }
- if (duplex == HALF_DUPLEX)
- hw->fc.current_mode = igc_fc_none;
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val) {
+ hw_dbg("Error getting link speed and duplex\n");
+ goto out;
+ }
- /* Now we call a subroutine to actually force the MAC
- * controller to use the correct flow control settings.
- */
- ret_val = igc_force_mac_fc(hw);
- if (ret_val) {
- hw_dbg("Error forcing flow control settings\n");
- goto out;
- }
+ if (duplex == HALF_DUPLEX)
+ hw->fc.current_mode = igc_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = igc_force_mac_fc(hw);
+ if (ret_val) {
+ hw_dbg("Error forcing flow control settings\n");
+ goto out;
}
out:
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 6e70bca15db1..27872bdea9bd 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7108,7 +7108,6 @@ static int igc_probe(struct pci_dev *pdev,
/* Initialize link properties that are user-changeable */
adapter->fc_autoneg = true;
- hw->mac.autoneg = true;
hw->phy.autoneg_advertised = 0xaf;
hw->fc.requested_mode = igc_fc_default;
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
index 2801e5f24df9..6c4d204aecfa 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.c
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -494,24 +494,12 @@ s32 igc_setup_copper_link(struct igc_hw *hw)
s32 ret_val = 0;
bool link;
- if (hw->mac.autoneg) {
- /* Setup autoneg and flow control advertisement and perform
- * autonegotiation.
- */
- ret_val = igc_copper_link_autoneg(hw);
- if (ret_val)
- goto out;
- } else {
- /* PHY will be set to 10H, 10F, 100H or 100F
- * depending on user settings.
- */
- hw_dbg("Forcing Speed and Duplex\n");
- ret_val = hw->phy.ops.force_speed_duplex(hw);
- if (ret_val) {
- hw_dbg("Error Forcing Speed and Duplex\n");
- goto out;
- }
- }
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = igc_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 283a23150a4d..4aaaea3b5f8f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include "ixgbe.h"
+#include "ixgbe_mbx.h"
#include "ixgbe_phy.h"
#define IXGBE_82598_MAX_TX_QUEUES 32
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 8b8404d8c946..2e38e8f6fac1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -43,6 +43,7 @@
#include "ixgbe.h"
#include "ixgbe_common.h"
#include "ixgbe_dcb_82599.h"
+#include "ixgbe_mbx.h"
#include "ixgbe_phy.h"
#include "ixgbe_sriov.h"
#include "ixgbe_model.h"
@@ -9954,7 +9955,7 @@ static int ixgbe_set_features(struct net_device *netdev,
static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
- u16 flags,
+ u16 flags, bool *notified,
struct netlink_ext_ack *extack)
{
/* guarantee we can provide a unique filter for the unicast address */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index bd205306934b..bf65e82b4c61 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -4,7 +4,7 @@
#ifndef _IXGBE_MBX_H_
#define _IXGBE_MBX_H_
-#include "ixgbe_type.h"
+#include <linux/types.h>
#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
@@ -96,6 +96,8 @@ enum ixgbe_pfvf_api_rev {
#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
#define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */
+struct ixgbe_hw;
+
int ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16);
int ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16);
int ixgbe_check_for_msg(struct ixgbe_hw *, u16);
@@ -105,6 +107,18 @@ int ixgbe_check_for_rst(struct ixgbe_hw *, u16);
void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
#endif /* CONFIG_PCI_IOV */
+struct ixgbe_mbx_operations {
+ int (*init_params)(struct ixgbe_hw *hw);
+ int (*read)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+ int (*write)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+ int (*read_posted)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+ int (*write_posted)(struct ixgbe_hw *hw, u32 *msg, u16 size,
+ u16 mbx_id);
+ int (*check_for_msg)(struct ixgbe_hw *hw, u16 vf_number);
+ int (*check_for_ack)(struct ixgbe_hw *hw, u16 vf_number);
+ int (*check_for_rst)(struct ixgbe_hw *hw, u16 vf_number);
+};
+
extern const struct ixgbe_mbx_operations mbx_ops_generic;
#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index e71715f5da22..9631559a5aea 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -18,6 +18,7 @@
#include "ixgbe.h"
#include "ixgbe_type.h"
+#include "ixgbe_mbx.h"
#include "ixgbe_sriov.h"
#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 346e3d9114a8..9baccacd02a1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -3601,19 +3601,6 @@ struct ixgbe_phy_info {
u32 nw_mng_if_sel;
};
-#include "ixgbe_mbx.h"
-
-struct ixgbe_mbx_operations {
- int (*init_params)(struct ixgbe_hw *hw);
- int (*read)(struct ixgbe_hw *, u32 *, u16, u16);
- int (*write)(struct ixgbe_hw *, u32 *, u16, u16);
- int (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16);
- int (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16);
- int (*check_for_msg)(struct ixgbe_hw *, u16);
- int (*check_for_ack)(struct ixgbe_hw *, u16);
- int (*check_for_rst)(struct ixgbe_hw *, u16);
-};
-
struct ixgbe_mbx_stats {
u32 msgs_tx;
u32 msgs_rx;
@@ -3623,6 +3610,8 @@ struct ixgbe_mbx_stats {
u32 rsts;
};
+struct ixgbe_mbx_operations;
+
struct ixgbe_mbx_info {
const struct ixgbe_mbx_operations *ops;
struct ixgbe_mbx_stats stats;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index f1ffa398f6df..81e1df83f136 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include "ixgbe.h"
+#include "ixgbe_mbx.h"
#include "ixgbe_phy.h"
#include "ixgbe_x540.h"
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index a5f644934445..d9a8cf018d3b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -4,6 +4,7 @@
#include "ixgbe_x540.h"
#include "ixgbe_type.h"
#include "ixgbe_common.h"
+#include "ixgbe_mbx.h"
#include "ixgbe_phy.h"
static int ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *, ixgbe_link_speed);
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 103632ba78a2..571631a30320 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -1985,45 +1985,32 @@ static void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset,
u8 *data)
{
struct mvpp2_port *port = netdev_priv(netdev);
+ const char *str;
int i, q;
if (sset != ETH_SS_STATS)
return;
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++) {
- strscpy(data, mvpp2_ethtool_mib_regs[i].string,
- ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++)
+ ethtool_puts(&data, mvpp2_ethtool_mib_regs[i].string);
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++) {
- strscpy(data, mvpp2_ethtool_port_regs[i].string,
- ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++)
+ ethtool_puts(&data, mvpp2_ethtool_port_regs[i].string);
- for (q = 0; q < port->ntxqs; q++) {
+ for (q = 0; q < port->ntxqs; q++)
for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++) {
- snprintf(data, ETH_GSTRING_LEN,
- mvpp2_ethtool_txq_regs[i].string, q);
- data += ETH_GSTRING_LEN;
+ str = mvpp2_ethtool_txq_regs[i].string;
+ ethtool_sprintf(&data, str, q);
}
- }
- for (q = 0; q < port->nrxqs; q++) {
+ for (q = 0; q < port->nrxqs; q++)
for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++) {
- snprintf(data, ETH_GSTRING_LEN,
- mvpp2_ethtool_rxq_regs[i].string,
- q);
- data += ETH_GSTRING_LEN;
+ str = mvpp2_ethtool_rxq_regs[i].string;
+ ethtool_sprintf(&data, str, q);
}
- }
- for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_xdp); i++) {
- strscpy(data, mvpp2_ethtool_xdp[i].string,
- ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_xdp); i++)
+ ethtool_puts(&data, mvpp2_ethtool_xdp[i].string);
}
static void
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c
index 7d0124b283da..4f4d58189118 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c
@@ -47,7 +47,7 @@ static const char octep_gstrings_global_stats[][ETH_GSTRING_LEN] = {
"rx_err_pkts",
};
-#define OCTEP_GLOBAL_STATS_CNT (sizeof(octep_gstrings_global_stats) / ETH_GSTRING_LEN)
+#define OCTEP_GLOBAL_STATS_CNT ARRAY_SIZE(octep_gstrings_global_stats)
static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
"tx_packets_posted[Q-%u]",
@@ -56,7 +56,7 @@ static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
"tx_busy[Q-%u]",
};
-#define OCTEP_TX_Q_STATS_CNT (sizeof(octep_gstrings_tx_q_stats) / ETH_GSTRING_LEN)
+#define OCTEP_TX_Q_STATS_CNT ARRAY_SIZE(octep_gstrings_tx_q_stats)
static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
"rx_packets[Q-%u]",
@@ -64,7 +64,7 @@ static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
"rx_alloc_errors[Q-%u]",
};
-#define OCTEP_RX_Q_STATS_CNT (sizeof(octep_gstrings_rx_q_stats) / ETH_GSTRING_LEN)
+#define OCTEP_RX_Q_STATS_CNT ARRAY_SIZE(octep_gstrings_rx_q_stats)
static void octep_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
@@ -80,32 +80,25 @@ static void octep_get_strings(struct net_device *netdev,
{
struct octep_device *oct = netdev_priv(netdev);
u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
- char *strings = (char *)data;
+ const char *str;
int i, j;
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_gstrings_global_stats[i]);
- strings += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++)
+ ethtool_puts(&data, octep_gstrings_global_stats[i]);
- for (i = 0; i < num_queues; i++) {
+ for (i = 0; i < num_queues; i++)
for (j = 0; j < OCTEP_TX_Q_STATS_CNT; j++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_gstrings_tx_q_stats[j], i);
- strings += ETH_GSTRING_LEN;
+ str = octep_gstrings_tx_q_stats[j];
+ ethtool_sprintf(&data, str, i);
}
- }
- for (i = 0; i < num_queues; i++) {
+ for (i = 0; i < num_queues; i++)
for (j = 0; j < OCTEP_RX_Q_STATS_CNT; j++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_gstrings_rx_q_stats[j], i);
- strings += ETH_GSTRING_LEN;
+ str = octep_gstrings_rx_q_stats[j];
+ ethtool_sprintf(&data, str, i);
}
- }
break;
default:
break;
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c
index a1979b45e355..7b21439a315f 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c
@@ -25,7 +25,7 @@ static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = {
"rx_dropped_bytes_fifo_full",
};
-#define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN)
+#define OCTEP_VF_GLOBAL_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_global_stats)
static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
"tx_packets_posted[Q-%u]",
@@ -34,7 +34,7 @@ static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
"tx_busy[Q-%u]",
};
-#define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN)
+#define OCTEP_VF_TX_Q_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_tx_q_stats)
static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
"rx_packets[Q-%u]",
@@ -42,7 +42,7 @@ static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
"rx_alloc_errors[Q-%u]",
};
-#define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN)
+#define OCTEP_VF_RX_Q_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_rx_q_stats)
static void octep_vf_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
@@ -58,32 +58,25 @@ static void octep_vf_get_strings(struct net_device *netdev,
{
struct octep_vf_device *oct = netdev_priv(netdev);
u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
- char *strings = (char *)data;
+ const char *str;
int i, j;
switch (stringset) {
case ETH_SS_STATS:
- for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_vf_gstrings_global_stats[i]);
- strings += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++)
+ ethtool_puts(&data, octep_vf_gstrings_global_stats[i]);
- for (i = 0; i < num_queues; i++) {
+ for (i = 0; i < num_queues; i++)
for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_vf_gstrings_tx_q_stats[j], i);
- strings += ETH_GSTRING_LEN;
+ str = octep_vf_gstrings_tx_q_stats[j];
+ ethtool_sprintf(&data, str, i);
}
- }
- for (i = 0; i < num_queues; i++) {
+ for (i = 0; i < num_queues; i++)
for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) {
- snprintf(strings, ETH_GSTRING_LEN,
- octep_vf_gstrings_rx_q_stats[j], i);
- strings += ETH_GSTRING_LEN;
+ str = octep_vf_gstrings_rx_q_stats[j];
+ ethtool_sprintf(&data, str, i);
}
- }
break;
default:
break;
diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig
index a32d85d6f599..35c4f5f64f58 100644
--- a/drivers/net/ethernet/marvell/octeontx2/Kconfig
+++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig
@@ -46,3 +46,11 @@ config OCTEONTX2_VF
depends on OCTEONTX2_PF
help
This driver supports Marvell's OcteonTX2 NIC virtual function.
+
+config RVU_ESWITCH
+ tristate "Marvell RVU E-Switch support"
+ depends on OCTEONTX2_PF
+ default m
+ help
+ This driver supports Marvell's RVU E-Switch that
+ provides internal SRIOV packet steering and switching.
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
index 3cf4c8285c90..ccea37847df8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
@@ -11,4 +11,5 @@ rvu_mbox-y := mbox.o rvu_trace.o
rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
rvu_reg.o rvu_npc.o rvu_debugfs.o ptp.o rvu_npc_fs.o \
rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \
- rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o
+ rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \
+ rvu_rep.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
index 2436c1ff9ba4..5d84386ed22d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -156,6 +156,7 @@ enum nix_scheduler {
#define NIC_HW_MIN_FRS 40
#define NIC_HW_MAX_FRS 9212
#define SDP_HW_MAX_FRS 65535
+#define SDP_HW_MIN_FRS 16
#define CN10K_LMAC_LINK_MAX_FRS 16380 /* 16k - FCS */
#define CN10K_LBK_LINK_MAX_FRS 65535 /* 64k */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 6ea2f3071fe8..62c07407eb94 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -144,6 +144,9 @@ M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \
msg_rsp) \
M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \
M(PTP_GET_CAP, 0x00c, ptp_get_cap, msg_req, ptp_get_cap_rsp) \
+M(GET_REP_CNT, 0x00d, get_rep_cnt, msg_req, get_rep_cnt_rsp) \
+M(ESW_CFG, 0x00e, esw_cfg, esw_cfg_req, msg_rsp) \
+M(REP_EVENT_NOTIFY, 0x00f, rep_event_notify, rep_event, msg_rsp) \
/* CGX mbox IDs (range 0x200 - 0x3FF) */ \
M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \
M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \
@@ -319,6 +322,7 @@ M(NIX_MCAST_GRP_DESTROY, 0x802c, nix_mcast_grp_destroy, nix_mcast_grp_destroy_re
M(NIX_MCAST_GRP_UPDATE, 0x802d, nix_mcast_grp_update, \
nix_mcast_grp_update_req, \
nix_mcast_grp_update_rsp) \
+M(NIX_LF_STATS, 0x802e, nix_lf_stats, nix_stats_req, nix_stats_rsp) \
/* MCS mbox IDs (range 0xA000 - 0xBFFF) */ \
M(MCS_ALLOC_RESOURCES, 0xa000, mcs_alloc_resources, mcs_alloc_rsrc_req, \
mcs_alloc_rsrc_rsp) \
@@ -380,12 +384,16 @@ M(CPT_INST_LMTST, 0xD00, cpt_inst_lmtst, cpt_inst_lmtst_req, msg_rsp)
#define MBOX_UP_MCS_MESSAGES \
M(MCS_INTR_NOTIFY, 0xE00, mcs_intr_notify, mcs_intr_info, msg_rsp)
+#define MBOX_UP_REP_MESSAGES \
+M(REP_EVENT_UP_NOTIFY, 0xEF0, rep_event_up_notify, rep_event, msg_rsp) \
+
enum {
#define M(_name, _id, _1, _2, _3) MBOX_MSG_ ## _name = _id,
MBOX_MESSAGES
MBOX_UP_CGX_MESSAGES
MBOX_UP_CPT_MESSAGES
MBOX_UP_MCS_MESSAGES
+MBOX_UP_REP_MESSAGES
#undef M
};
@@ -1364,6 +1372,37 @@ struct nix_bandprof_get_hwinfo_rsp {
u32 policer_timeunit;
};
+struct nix_stats_req {
+ struct mbox_msghdr hdr;
+ u8 reset;
+ u16 pcifunc;
+ u64 rsvd;
+};
+
+struct nix_stats_rsp {
+ struct mbox_msghdr hdr;
+ u16 pcifunc;
+ struct {
+ u64 octs;
+ u64 ucast;
+ u64 bcast;
+ u64 mcast;
+ u64 drop;
+ u64 drop_octs;
+ u64 drop_mcast;
+ u64 drop_bcast;
+ u64 err;
+ u64 rsvd[5];
+ } rx;
+ struct {
+ u64 ucast;
+ u64 bcast;
+ u64 mcast;
+ u64 drop;
+ u64 octs;
+ } tx;
+};
+
/* NPC mbox message structs */
#define NPC_MCAM_ENTRY_INVALID 0xFFFF
@@ -1525,6 +1564,41 @@ struct ptp_get_cap_rsp {
u64 cap;
};
+struct get_rep_cnt_rsp {
+ struct mbox_msghdr hdr;
+ u16 rep_cnt;
+ u16 rep_pf_map[64];
+ u64 rsvd;
+};
+
+struct esw_cfg_req {
+ struct mbox_msghdr hdr;
+ u8 ena;
+ u64 rsvd;
+};
+
+struct rep_evt_data {
+ u8 port_state;
+ u8 vf_state;
+ u16 rx_mode;
+ u16 rx_flags;
+ u16 mtu;
+ u8 mac[ETH_ALEN];
+ u64 rsvd[5];
+};
+
+struct rep_event {
+ struct mbox_msghdr hdr;
+ u16 pcifunc;
+#define RVU_EVENT_PORT_STATE BIT_ULL(0)
+#define RVU_EVENT_PFVF_STATE BIT_ULL(1)
+#define RVU_EVENT_MTU_CHANGE BIT_ULL(2)
+#define RVU_EVENT_RX_MODE_CHANGE BIT_ULL(3)
+#define RVU_EVENT_MAC_ADDR_CHANGE BIT_ULL(4)
+ u16 event;
+ struct rep_evt_data evt_data;
+};
+
struct flow_msg {
unsigned char dmac[6];
unsigned char smac[6];
@@ -1563,6 +1637,7 @@ struct flow_msg {
u8 icmp_type;
u8 icmp_code;
__be16 tcp_flags;
+ u16 sq_id;
};
struct npc_install_flow_req {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 5016ba82e142..b897845e25fd 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -513,6 +513,11 @@ struct rvu_switch {
u16 start_entry;
};
+struct rep_evtq_ent {
+ struct list_head node;
+ struct rep_event event;
+};
+
struct rvu {
void __iomem *afreg_base;
void __iomem *pfreg_base;
@@ -525,6 +530,7 @@ struct rvu {
struct mutex alias_lock; /* Serialize bar2 alias access */
int vfs; /* Number of VFs attached to RVU */
u16 vf_devid; /* VF devices id */
+ bool def_rule_cntr_en;
int nix_blkaddr[MAX_NIX_BLKS];
/* Mbox */
@@ -594,6 +600,15 @@ struct rvu {
spinlock_t cpt_intr_lock;
struct mutex mbox_lock; /* Serialize mbox up and down msgs */
+ u16 rep_pcifunc;
+ int rep_cnt;
+ u16 *rep2pfvf_map;
+ u8 rep_mode;
+ struct work_struct rep_evt_work;
+ struct workqueue_struct *rep_evt_wq;
+ struct list_head rep_evtq_head;
+ /* Representor event lock */
+ spinlock_t rep_evtq_lock;
};
static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
@@ -852,6 +867,14 @@ bool is_sdp_pfvf(u16 pcifunc);
bool is_sdp_pf(u16 pcifunc);
bool is_sdp_vf(struct rvu *rvu, u16 pcifunc);
+static inline bool is_rep_dev(struct rvu *rvu, u16 pcifunc)
+{
+ if (rvu->rep_pcifunc && rvu->rep_pcifunc == pcifunc)
+ return true;
+
+ return false;
+}
+
/* CGX APIs */
static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf)
{
@@ -960,7 +983,11 @@ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
void rvu_npc_enable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf);
void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
int group, int alg_idx, int mcam_index);
-
+void __rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc,
+ struct rvu_npc_mcam_rule *rule);
+void __rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc,
+ struct rvu_npc_mcam_rule *rule,
+ struct npc_install_flow_rsp *rsp);
void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc,
int blkaddr, int *alloc_cnt,
int *enable_cnt);
@@ -985,6 +1012,7 @@ void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 src, struct mcam_entry *entry,
u8 *intf, u8 *ena);
+int npc_config_cntr_default_entries(struct rvu *rvu, bool enable);
bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc);
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
@@ -1045,7 +1073,8 @@ int rvu_ndc_fix_locked_cacheline(struct rvu *rvu, int blkaddr);
/* RVU Switch */
void rvu_switch_enable(struct rvu *rvu);
void rvu_switch_disable(struct rvu *rvu);
-void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc);
+void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc, bool ena);
+void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool ena);
int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
u64 pkind, u8 var_len_off, u8 var_len_off_mask,
@@ -1058,4 +1087,9 @@ int rvu_mcs_flr_handler(struct rvu *rvu, u16 pcifunc);
void rvu_mcs_ptp_cfg(struct rvu *rvu, u8 rpm_id, u8 lmac_id, bool ena);
void rvu_mcs_exit(struct rvu *rvu);
+/* Representor APIs */
+int rvu_rep_pf_init(struct rvu *rvu);
+int rvu_rep_install_mcam_rules(struct rvu *rvu);
+void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena);
+int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable);
#endif /* RVU_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index 8c700ee4a82b..148144f5b61d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -45,33 +45,6 @@ enum {
CGX_STAT18,
};
-/* NIX TX stats */
-enum nix_stat_lf_tx {
- TX_UCAST = 0x0,
- TX_BCAST = 0x1,
- TX_MCAST = 0x2,
- TX_DROP = 0x3,
- TX_OCTS = 0x4,
- TX_STATS_ENUM_LAST,
-};
-
-/* NIX RX stats */
-enum nix_stat_lf_rx {
- RX_OCTS = 0x0,
- RX_UCAST = 0x1,
- RX_BCAST = 0x2,
- RX_MCAST = 0x3,
- RX_DROP = 0x4,
- RX_DROP_OCTS = 0x5,
- RX_FCS = 0x6,
- RX_ERR = 0x7,
- RX_DRP_BCAST = 0x8,
- RX_DRP_MCAST = 0x9,
- RX_DRP_L3BCAST = 0xa,
- RX_DRP_L3MCAST = 0xb,
- RX_STATS_ENUM_LAST,
-};
-
static char *cgx_rx_stats_fields[] = {
[CGX_STAT0] = "Received packets",
[CGX_STAT1] = "Octets of received packets",
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index 7498ab429963..dab4deca893f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -1238,6 +1238,7 @@ enum rvu_af_dl_param_id {
RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU,
RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT,
RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
+ RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE,
RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
};
@@ -1358,6 +1359,32 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink
return 0;
}
+static int rvu_af_dl_npc_def_rule_cntr_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.vbool = rvu->def_rule_cntr_en;
+
+ return 0;
+}
+
+static int rvu_af_dl_npc_def_rule_cntr_set(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx,
+ struct netlink_ext_ack *extack)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+ int err;
+
+ err = npc_config_cntr_default_entries(rvu, ctx->val.vbool);
+ if (!err)
+ rvu->def_rule_cntr_en = ctx->val.vbool;
+
+ return err;
+}
+
static int rvu_af_dl_nix_maxlf_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx)
{
@@ -1444,6 +1471,11 @@ static const struct devlink_param rvu_af_dl_params[] = {
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_NPC_DEF_RULE_CNTR_ENABLE,
+ "npc_def_rule_cntr", DEVLINK_PARAM_TYPE_BOOL,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+ rvu_af_dl_npc_def_rule_cntr_get,
+ rvu_af_dl_npc_def_rule_cntr_set, NULL),
DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
"nix_maxlf", DEVLINK_PARAM_TYPE_U16,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
@@ -1468,6 +1500,9 @@ static int rvu_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
struct rvu *rvu = rvu_dl->rvu;
struct rvu_switch *rswitch;
+ if (rvu->rep_mode)
+ return -EOPNOTSUPP;
+
rswitch = &rvu->rswitch;
*mode = rswitch->mode;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index da69350c6f76..5d5a01dbbca1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -31,6 +31,7 @@ static int nix_free_all_bandprof(struct rvu *rvu, u16 pcifunc);
static void nix_clear_ratelimit_aggr(struct rvu *rvu, struct nix_hw *nix_hw,
u32 leaf_prof);
static const char *nix_get_ctx_name(int ctype);
+static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc);
enum mc_tbl_sz {
MC_TBL_SZ_256,
@@ -312,7 +313,9 @@ static bool is_valid_txschq(struct rvu *rvu, int blkaddr,
/* TLs aggegating traffic are shared across PF and VFs */
if (lvl >= hw->cap.nix_tx_aggr_lvl) {
- if (rvu_get_pf(map_func) != rvu_get_pf(pcifunc))
+ if ((nix_get_tx_link(rvu, map_func) !=
+ nix_get_tx_link(rvu, pcifunc)) &&
+ (rvu_get_pf(map_func) != rvu_get_pf(pcifunc)))
return false;
else
return true;
@@ -360,7 +363,6 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf,
cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
rvu_npc_set_pkind(rvu, pkind, pfvf);
-
break;
case NIX_INTF_TYPE_LBK:
vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1;
@@ -584,6 +586,9 @@ int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu,
if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK)
return 0;
+ if (is_sdp_pfvf(pcifunc))
+ type = NIX_INTF_TYPE_SDP;
+
pfvf = rvu_get_pfvf(rvu, pcifunc);
err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr);
if (err)
@@ -1614,6 +1619,12 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
cfg = NPC_TX_DEF_PKIND;
rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ if (is_rep_dev(rvu, pcifunc)) {
+ pfvf->tx_chan_base = RVU_SWITCH_LBK_CHAN;
+ pfvf->tx_chan_cnt = 1;
+ goto exit;
+ }
+
intf = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX;
if (is_sdp_pfvf(pcifunc))
intf = NIX_INTF_TYPE_SDP;
@@ -1684,6 +1695,9 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req,
if (nixlf < 0)
return NIX_AF_ERR_AF_LF_INVALID;
+ if (is_rep_dev(rvu, pcifunc))
+ goto free_lf;
+
if (req->flags & NIX_LF_DISABLE_FLOWS)
rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
else
@@ -1695,6 +1709,7 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req,
nix_interface_deinit(rvu, pcifunc, nixlf);
+free_lf:
/* Reset this NIX LF */
err = rvu_lf_reset(rvu, block, nixlf);
if (err) {
@@ -2007,7 +2022,8 @@ static void nix_get_txschq_range(struct rvu *rvu, u16 pcifunc,
struct rvu_hwinfo *hw = rvu->hw;
int pf = rvu_get_pf(pcifunc);
- if (is_lbk_vf(rvu, pcifunc)) { /* LBK links */
+ /* LBK links */
+ if (is_lbk_vf(rvu, pcifunc) || is_rep_dev(rvu, pcifunc)) {
*start = hw->cap.nix_txsch_per_cgx_lmac * link;
*end = *start + hw->cap.nix_txsch_per_lbk_lmac;
} else if (is_pf_cgxmapped(rvu, pf)) { /* CGX links */
@@ -2760,7 +2776,7 @@ void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc,
int schq;
u64 cfg;
- if (!is_pf_cgxmapped(rvu, pf))
+ if (!is_pf_cgxmapped(rvu, pf) && !is_rep_dev(rvu, pcifunc))
return;
cfg = enable ? (BIT_ULL(12) | RVU_SWITCH_LBK_CHAN) : 0;
@@ -4393,8 +4409,6 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu,
if (test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) && from_vf)
ether_addr_copy(pfvf->default_mac, req->mac_addr);
- rvu_switch_update_rules(rvu, pcifunc);
-
return 0;
}
@@ -4555,7 +4569,7 @@ int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req,
if (!nix_hw)
return NIX_AF_ERR_INVALID_NIXBLK;
- if (is_lbk_vf(rvu, pcifunc))
+ if (is_lbk_vf(rvu, pcifunc) || is_rep_dev(rvu, pcifunc))
rvu_get_lbk_link_max_frs(rvu, &max_mtu);
else
rvu_get_lmac_link_max_frs(rvu, &max_mtu);
@@ -4583,6 +4597,8 @@ int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req,
/* For VFs of PF0 ingress is LBK port, so config LBK link */
pfvf = rvu_get_pfvf(rvu, pcifunc);
link = hw->cgx_links + pfvf->lbkid;
+ } else if (is_rep_dev(rvu, pcifunc)) {
+ link = hw->cgx_links + 0;
}
if (link < 0)
@@ -4674,7 +4690,7 @@ static void nix_link_config(struct rvu *rvu, int blkaddr,
if (hw->sdp_links) {
link = hw->cgx_links + hw->lbk_links;
rvu_write64(rvu, blkaddr, NIX_AF_RX_LINKX_CFG(link),
- SDP_HW_MAX_FRS << 16 | NIC_HW_MIN_FRS);
+ SDP_HW_MAX_FRS << 16 | SDP_HW_MIN_FRS);
}
/* Get MCS external bypass status for CN10K-B */
@@ -5166,7 +5182,7 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
{
u16 pcifunc = req->hdr.pcifunc;
struct rvu_pfvf *pfvf;
- int nixlf, err;
+ int nixlf, err, pf;
err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
if (err)
@@ -5182,7 +5198,11 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
pfvf = rvu_get_pfvf(rvu, pcifunc);
set_bit(NIXLF_INITIALIZED, &pfvf->flags);
- rvu_switch_update_rules(rvu, pcifunc);
+ rvu_switch_update_rules(rvu, pcifunc, true);
+
+ pf = rvu_get_pf(pcifunc);
+ if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
+ rvu_rep_notify_pfvf_state(rvu, pcifunc, true);
return rvu_cgx_start_stop_io(rvu, pcifunc, true);
}
@@ -5192,7 +5212,7 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
{
u16 pcifunc = req->hdr.pcifunc;
struct rvu_pfvf *pfvf;
- int nixlf, err;
+ int nixlf, err, pf;
err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
if (err)
@@ -5210,8 +5230,12 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
if (err)
return err;
+ rvu_switch_update_rules(rvu, pcifunc, false);
rvu_cgx_tx_enable(rvu, pcifunc, true);
+ pf = rvu_get_pf(pcifunc);
+ if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
+ rvu_rep_notify_pfvf_state(rvu, pcifunc, false);
return 0;
}
@@ -5239,6 +5263,9 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf)
clear_bit(NIXLF_INITIALIZED, &pfvf->flags);
+ if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode)
+ rvu_rep_notify_pfvf_state(rvu, pcifunc, false);
+
rvu_cgx_start_stop_io(rvu, pcifunc, false);
if (pfvf->sq_ctx) {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 97722ce8c4cb..821fe242f821 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -2691,6 +2691,49 @@ void npc_mcam_rsrcs_reserve(struct rvu *rvu, int blkaddr, int entry_idx)
npc_mcam_set_bit(mcam, entry_idx);
}
+int npc_config_cntr_default_entries(struct rvu *rvu, bool enable)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct npc_install_flow_rsp rsp;
+ struct rvu_npc_mcam_rule *rule;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return -EINVAL;
+
+ mutex_lock(&mcam->lock);
+ list_for_each_entry(rule, &mcam->mcam_rules, list) {
+ if (!is_mcam_entry_enabled(rvu, mcam, blkaddr, rule->entry))
+ continue;
+ if (!rule->default_rule)
+ continue;
+ if (enable && !rule->has_cntr) { /* Alloc and map new counter */
+ __rvu_mcam_add_counter_to_rule(rvu, rule->owner,
+ rule, &rsp);
+ if (rsp.counter < 0) {
+ dev_err(rvu->dev,
+ "%s: Failed to allocate cntr for default rule (err=%d)\n",
+ __func__, rsp.counter);
+ break;
+ }
+ npc_map_mcam_entry_and_cntr(rvu, mcam, blkaddr,
+ rule->entry, rsp.counter);
+ /* Reset counter before use */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_MATCH_STATX(rule->cntr), 0x0);
+ }
+
+ /* Free and unmap counter */
+ if (!enable && rule->has_cntr)
+ __rvu_mcam_remove_counter_from_rule(rvu, rule->owner,
+ rule);
+ }
+ mutex_unlock(&mcam->lock);
+
+ return 0;
+}
+
int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
struct npc_mcam_alloc_entry_req *req,
struct npc_mcam_alloc_entry_rsp *rsp)
@@ -2975,9 +3018,9 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu,
return rc;
}
-int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu,
- struct npc_mcam_alloc_counter_req *req,
- struct npc_mcam_alloc_counter_rsp *rsp)
+static int __npc_mcam_alloc_counter(struct rvu *rvu,
+ struct npc_mcam_alloc_counter_req *req,
+ struct npc_mcam_alloc_counter_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u16 pcifunc = req->hdr.pcifunc;
@@ -2998,11 +3041,9 @@ int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu,
if (!req->contig && req->count > NPC_MAX_NONCONTIG_COUNTERS)
return NPC_MCAM_INVALID_REQ;
- mutex_lock(&mcam->lock);
/* Check if unused counters are available or not */
if (!rvu_rsrc_free_count(&mcam->counters)) {
- mutex_unlock(&mcam->lock);
return NPC_MCAM_ALLOC_FAILED;
}
@@ -3035,12 +3076,27 @@ int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu,
}
}
- mutex_unlock(&mcam->lock);
return 0;
}
-int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu,
- struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp)
+int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu,
+ struct npc_mcam_alloc_counter_req *req,
+ struct npc_mcam_alloc_counter_rsp *rsp)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int err;
+
+ mutex_lock(&mcam->lock);
+
+ err = __npc_mcam_alloc_counter(rvu, req, rsp);
+
+ mutex_unlock(&mcam->lock);
+ return err;
+}
+
+static int __npc_mcam_free_counter(struct rvu *rvu,
+ struct npc_mcam_oper_counter_req *req,
+ struct msg_rsp *rsp)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u16 index, entry = 0;
@@ -3050,10 +3106,8 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu,
if (blkaddr < 0)
return NPC_MCAM_INVALID_REQ;
- mutex_lock(&mcam->lock);
err = npc_mcam_verify_counter(mcam, req->hdr.pcifunc, req->cntr);
if (err) {
- mutex_unlock(&mcam->lock);
return err;
}
@@ -3077,10 +3131,66 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu,
index, req->cntr);
}
- mutex_unlock(&mcam->lock);
return 0;
}
+int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu,
+ struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int err;
+
+ mutex_lock(&mcam->lock);
+
+ err = __npc_mcam_free_counter(rvu, req, rsp);
+
+ mutex_unlock(&mcam->lock);
+
+ return err;
+}
+
+void __rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc,
+ struct rvu_npc_mcam_rule *rule)
+{
+ struct npc_mcam_oper_counter_req free_req = { 0 };
+ struct msg_rsp free_rsp;
+
+ if (!rule->has_cntr)
+ return;
+
+ free_req.hdr.pcifunc = pcifunc;
+ free_req.cntr = rule->cntr;
+
+ __npc_mcam_free_counter(rvu, &free_req, &free_rsp);
+ rule->has_cntr = false;
+}
+
+void __rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc,
+ struct rvu_npc_mcam_rule *rule,
+ struct npc_install_flow_rsp *rsp)
+{
+ struct npc_mcam_alloc_counter_req cntr_req = { 0 };
+ struct npc_mcam_alloc_counter_rsp cntr_rsp = { 0 };
+ int err;
+
+ cntr_req.hdr.pcifunc = pcifunc;
+ cntr_req.contig = true;
+ cntr_req.count = 1;
+
+ /* we try to allocate a counter to track the stats of this
+ * rule. If counter could not be allocated then proceed
+ * without counter because counters are limited than entries.
+ */
+ err = __npc_mcam_alloc_counter(rvu, &cntr_req, &cntr_rsp);
+ if (!err && cntr_rsp.count) {
+ rule->cntr = cntr_rsp.cntr;
+ rule->has_cntr = true;
+ rsp->counter = rule->cntr;
+ } else {
+ rsp->counter = err;
+ }
+}
+
int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu,
struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp)
{
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 150635de2bd5..da69e454662a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -1081,44 +1081,26 @@ static void rvu_mcam_add_rule(struct npc_mcam *mcam,
static void rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc,
struct rvu_npc_mcam_rule *rule)
{
- struct npc_mcam_oper_counter_req free_req = { 0 };
- struct msg_rsp free_rsp;
+ struct npc_mcam *mcam = &rvu->hw->mcam;
- if (!rule->has_cntr)
- return;
+ mutex_lock(&mcam->lock);
- free_req.hdr.pcifunc = pcifunc;
- free_req.cntr = rule->cntr;
+ __rvu_mcam_remove_counter_from_rule(rvu, pcifunc, rule);
- rvu_mbox_handler_npc_mcam_free_counter(rvu, &free_req, &free_rsp);
- rule->has_cntr = false;
+ mutex_unlock(&mcam->lock);
}
static void rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc,
struct rvu_npc_mcam_rule *rule,
struct npc_install_flow_rsp *rsp)
{
- struct npc_mcam_alloc_counter_req cntr_req = { 0 };
- struct npc_mcam_alloc_counter_rsp cntr_rsp = { 0 };
- int err;
+ struct npc_mcam *mcam = &rvu->hw->mcam;
- cntr_req.hdr.pcifunc = pcifunc;
- cntr_req.contig = true;
- cntr_req.count = 1;
+ mutex_lock(&mcam->lock);
- /* we try to allocate a counter to track the stats of this
- * rule. If counter could not be allocated then proceed
- * without counter because counters are limited than entries.
- */
- err = rvu_mbox_handler_npc_mcam_alloc_counter(rvu, &cntr_req,
- &cntr_rsp);
- if (!err && cntr_rsp.count) {
- rule->cntr = cntr_rsp.cntr;
- rule->has_cntr = true;
- rsp->counter = rule->cntr;
- } else {
- rsp->counter = err;
- }
+ __rvu_mcam_add_counter_to_rule(rvu, pcifunc, rule, rsp);
+
+ mutex_unlock(&mcam->lock);
}
static int npc_mcast_update_action_index(struct rvu *rvu, struct npc_install_flow_req *req,
@@ -1416,6 +1398,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
struct npc_install_flow_rsp *rsp)
{
bool from_vf = !!(req->hdr.pcifunc & RVU_PFVF_FUNC_MASK);
+ bool from_rep_dev = !!is_rep_dev(rvu, req->hdr.pcifunc);
struct rvu_switch *rswitch = &rvu->rswitch;
int blkaddr, nixlf, err;
struct rvu_pfvf *pfvf;
@@ -1472,14 +1455,19 @@ process_flow:
/* AF installing for a PF/VF */
if (!req->hdr.pcifunc)
target = req->vf;
+
/* PF installing for its VF */
- else if (!from_vf && req->vf) {
+ if (!from_vf && req->vf && !from_rep_dev) {
target = (req->hdr.pcifunc & ~RVU_PFVF_FUNC_MASK) | req->vf;
pf_set_vfs_mac = req->default_rule &&
(req->features & BIT_ULL(NPC_DMAC));
}
- /* msg received from PF/VF */
+
+ /* Representor device installing for a representee */
+ if (from_rep_dev && req->vf)
+ target = req->vf;
else
+ /* msg received from PF/VF */
target = req->hdr.pcifunc;
/* ignore chan_mask in case pf func is not AF, revisit later */
@@ -1492,8 +1480,10 @@ process_flow:
pfvf = rvu_get_pfvf(rvu, target);
+ if (from_rep_dev)
+ req->channel = pfvf->rx_chan_base;
/* PF installing for its VF */
- if (req->hdr.pcifunc && !from_vf && req->vf)
+ if (req->hdr.pcifunc && !from_vf && req->vf && !from_rep_dev)
set_bit(PF_SET_VF_CFG, &pfvf->flags);
/* update req destination mac addr */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index 2b299fa85159..62cdc714ba57 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -445,6 +445,7 @@
#define NIX_CONST_MAX_BPIDS GENMASK_ULL(23, 12)
#define NIX_CONST_SDP_CHANS GENMASK_ULL(11, 0)
+#define NIX_VLAN_ETYPE_MASK GENMASK_ULL(63, 48)
#define NIX_AF_MDQ_PARENT_MASK GENMASK_ULL(24, 16)
#define NIX_AF_TL4_PARENT_MASK GENMASK_ULL(23, 16)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c
new file mode 100644
index 000000000000..052ae5923e3a
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell RVU Admin Function driver
+ *
+ * Copyright (C) 2024 Marvell.
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rvu.h"
+#include "rvu_reg.h"
+
+#define M(_name, _id, _fn_name, _req_type, _rsp_type) \
+static struct _req_type __maybe_unused \
+*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid) \
+{ \
+ struct _req_type *req; \
+ \
+ req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \
+ &rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \
+ sizeof(struct _rsp_type)); \
+ if (!req) \
+ return NULL; \
+ req->hdr.sig = OTX2_MBOX_REQ_SIG; \
+ req->hdr.id = _id; \
+ return req; \
+}
+
+MBOX_UP_REP_MESSAGES
+#undef M
+
+static int rvu_rep_up_notify(struct rvu *rvu, struct rep_event *event)
+{
+ struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, event->pcifunc);
+ struct rep_event *msg;
+ int pf;
+
+ pf = rvu_get_pf(event->pcifunc);
+
+ if (event->event & RVU_EVENT_MAC_ADDR_CHANGE)
+ ether_addr_copy(pfvf->mac_addr, event->evt_data.mac);
+
+ mutex_lock(&rvu->mbox_lock);
+ msg = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
+ if (!msg) {
+ mutex_unlock(&rvu->mbox_lock);
+ return -ENOMEM;
+ }
+
+ msg->hdr.pcifunc = event->pcifunc;
+ msg->event = event->event;
+
+ memcpy(&msg->evt_data, &event->evt_data, sizeof(struct rep_evt_data));
+
+ otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
+
+ otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);
+
+ mutex_unlock(&rvu->mbox_lock);
+ return 0;
+}
+
+static void rvu_rep_wq_handler(struct work_struct *work)
+{
+ struct rvu *rvu = container_of(work, struct rvu, rep_evt_work);
+ struct rep_evtq_ent *qentry;
+ struct rep_event *event;
+ unsigned long flags;
+
+ do {
+ spin_lock_irqsave(&rvu->rep_evtq_lock, flags);
+ qentry = list_first_entry_or_null(&rvu->rep_evtq_head,
+ struct rep_evtq_ent,
+ node);
+ if (qentry)
+ list_del(&qentry->node);
+
+ spin_unlock_irqrestore(&rvu->rep_evtq_lock, flags);
+ if (!qentry)
+ break; /* nothing more to process */
+
+ event = &qentry->event;
+
+ rvu_rep_up_notify(rvu, event);
+ kfree(qentry);
+ } while (1);
+}
+
+int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req,
+ struct msg_rsp *rsp)
+{
+ struct rep_evtq_ent *qentry;
+
+ qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC);
+ if (!qentry)
+ return -ENOMEM;
+
+ qentry->event = *req;
+ spin_lock(&rvu->rep_evtq_lock);
+ list_add_tail(&qentry->node, &rvu->rep_evtq_head);
+ spin_unlock(&rvu->rep_evtq_lock);
+ queue_work(rvu->rep_evt_wq, &rvu->rep_evt_work);
+ return 0;
+}
+
+int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable)
+{
+ struct rep_event *req;
+ int pf;
+
+ if (!is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc)))
+ return 0;
+
+ pf = rvu_get_pf(rvu->rep_pcifunc);
+
+ mutex_lock(&rvu->mbox_lock);
+ req = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf);
+ if (!req) {
+ mutex_unlock(&rvu->mbox_lock);
+ return -ENOMEM;
+ }
+
+ req->hdr.pcifunc = rvu->rep_pcifunc;
+ req->event |= RVU_EVENT_PFVF_STATE;
+ req->pcifunc = pcifunc;
+ req->evt_data.vf_state = enable;
+
+ otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
+ otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);
+
+ mutex_unlock(&rvu->mbox_lock);
+ return 0;
+}
+
+#define RVU_LF_RX_STATS(reg) \
+ rvu_read64(rvu, blkaddr, NIX_AF_LFX_RX_STATX(nixlf, reg))
+
+#define RVU_LF_TX_STATS(reg) \
+ rvu_read64(rvu, blkaddr, NIX_AF_LFX_TX_STATX(nixlf, reg))
+
+int rvu_mbox_handler_nix_lf_stats(struct rvu *rvu,
+ struct nix_stats_req *req,
+ struct nix_stats_rsp *rsp)
+{
+ u16 pcifunc = req->pcifunc;
+ int nixlf, blkaddr, err;
+ struct msg_req rst_req;
+ struct msg_rsp rst_rsp;
+
+ err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr);
+ if (err)
+ return 0;
+
+ if (req->reset) {
+ rst_req.hdr.pcifunc = pcifunc;
+ return rvu_mbox_handler_nix_stats_rst(rvu, &rst_req, &rst_rsp);
+ }
+ rsp->rx.octs = RVU_LF_RX_STATS(RX_OCTS);
+ rsp->rx.ucast = RVU_LF_RX_STATS(RX_UCAST);
+ rsp->rx.bcast = RVU_LF_RX_STATS(RX_BCAST);
+ rsp->rx.mcast = RVU_LF_RX_STATS(RX_MCAST);
+ rsp->rx.drop = RVU_LF_RX_STATS(RX_DROP);
+ rsp->rx.err = RVU_LF_RX_STATS(RX_ERR);
+ rsp->rx.drop_octs = RVU_LF_RX_STATS(RX_DROP_OCTS);
+ rsp->rx.drop_mcast = RVU_LF_RX_STATS(RX_DRP_MCAST);
+ rsp->rx.drop_bcast = RVU_LF_RX_STATS(RX_DRP_BCAST);
+
+ rsp->tx.octs = RVU_LF_TX_STATS(TX_OCTS);
+ rsp->tx.ucast = RVU_LF_TX_STATS(TX_UCAST);
+ rsp->tx.bcast = RVU_LF_TX_STATS(TX_BCAST);
+ rsp->tx.mcast = RVU_LF_TX_STATS(TX_MCAST);
+ rsp->tx.drop = RVU_LF_TX_STATS(TX_DROP);
+
+ rsp->pcifunc = req->pcifunc;
+ return 0;
+}
+
+static u16 rvu_rep_get_vlan_id(struct rvu *rvu, u16 pcifunc)
+{
+ int id;
+
+ for (id = 0; id < rvu->rep_cnt; id++)
+ if (rvu->rep2pfvf_map[id] == pcifunc)
+ return id;
+ return 0;
+}
+
+static int rvu_rep_tx_vlan_cfg(struct rvu *rvu, u16 pcifunc,
+ u16 vlan_tci, int *vidx)
+{
+ struct nix_vtag_config_rsp rsp = {};
+ struct nix_vtag_config req = {};
+ u64 etype = ETH_P_8021Q;
+ int err;
+
+ /* Insert vlan tag */
+ req.hdr.pcifunc = pcifunc;
+ req.vtag_size = VTAGSIZE_T4;
+ req.cfg_type = 0; /* tx vlan cfg */
+ req.tx.cfg_vtag0 = true;
+ req.tx.vtag0 = FIELD_PREP(NIX_VLAN_ETYPE_MASK, etype) | vlan_tci;
+
+ err = rvu_mbox_handler_nix_vtag_cfg(rvu, &req, &rsp);
+ if (err) {
+ dev_err(rvu->dev, "Tx vlan config failed\n");
+ return err;
+ }
+ *vidx = rsp.vtag0_idx;
+ return 0;
+}
+
+static int rvu_rep_rx_vlan_cfg(struct rvu *rvu, u16 pcifunc)
+{
+ struct nix_vtag_config req = {};
+ struct nix_vtag_config_rsp rsp;
+
+ /* config strip, capture and size */
+ req.hdr.pcifunc = pcifunc;
+ req.vtag_size = VTAGSIZE_T4;
+ req.cfg_type = 1; /* rx vlan cfg */
+ req.rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0;
+ req.rx.strip_vtag = true;
+ req.rx.capture_vtag = false;
+
+ return rvu_mbox_handler_nix_vtag_cfg(rvu, &req, &rsp);
+}
+
+static int rvu_rep_install_rx_rule(struct rvu *rvu, u16 pcifunc,
+ u16 entry, bool rte)
+{
+ struct npc_install_flow_req req = {};
+ struct npc_install_flow_rsp rsp = {};
+ struct rvu_pfvf *pfvf;
+ u16 vlan_tci, rep_id;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+
+ /* To steer the traffic from Representee to Representor */
+ rep_id = rvu_rep_get_vlan_id(rvu, pcifunc);
+ if (rte) {
+ vlan_tci = rep_id | BIT_ULL(8);
+ req.vf = rvu->rep_pcifunc;
+ req.op = NIX_RX_ACTIONOP_UCAST;
+ req.index = rep_id;
+ } else {
+ vlan_tci = rep_id;
+ req.vf = pcifunc;
+ req.op = NIX_RX_ACTION_DEFAULT;
+ }
+
+ rvu_rep_rx_vlan_cfg(rvu, req.vf);
+ req.entry = entry;
+ req.hdr.pcifunc = 0; /* AF is requester */
+ req.features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_VLAN_ETYPE_CTAG);
+ req.vtag0_valid = true;
+ req.vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0;
+ req.packet.vlan_etype = cpu_to_be16(ETH_P_8021Q);
+ req.mask.vlan_etype = cpu_to_be16(ETH_P_8021Q);
+ req.packet.vlan_tci = cpu_to_be16(vlan_tci);
+ req.mask.vlan_tci = cpu_to_be16(0xffff);
+
+ req.channel = RVU_SWITCH_LBK_CHAN;
+ req.chan_mask = 0xffff;
+ req.intf = pfvf->nix_rx_intf;
+
+ return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
+}
+
+static int rvu_rep_install_tx_rule(struct rvu *rvu, u16 pcifunc, u16 entry,
+ bool rte)
+{
+ struct npc_install_flow_req req = {};
+ struct npc_install_flow_rsp rsp = {};
+ struct rvu_pfvf *pfvf;
+ int vidx, err;
+ u16 vlan_tci;
+ u8 lbkid;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ vlan_tci = rvu_rep_get_vlan_id(rvu, pcifunc);
+ if (rte)
+ vlan_tci |= BIT_ULL(8);
+
+ err = rvu_rep_tx_vlan_cfg(rvu, pcifunc, vlan_tci, &vidx);
+ if (err)
+ return err;
+
+ lbkid = pfvf->nix_blkaddr == BLKADDR_NIX0 ? 0 : 1;
+ req.hdr.pcifunc = 0; /* AF is requester */
+ if (rte) {
+ req.vf = pcifunc;
+ } else {
+ req.vf = rvu->rep_pcifunc;
+ req.packet.sq_id = vlan_tci;
+ req.mask.sq_id = 0xffff;
+ }
+
+ req.entry = entry;
+ req.intf = pfvf->nix_tx_intf;
+ req.op = NIX_TX_ACTIONOP_UCAST_CHAN;
+ req.index = (lbkid << 8) | RVU_SWITCH_LBK_CHAN;
+ req.set_cntr = 1;
+ req.vtag0_def = vidx;
+ req.vtag0_op = 1;
+ return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
+}
+
+int rvu_rep_install_mcam_rules(struct rvu *rvu)
+{
+ struct rvu_switch *rswitch = &rvu->rswitch;
+ u16 start = rswitch->start_entry;
+ struct rvu_hwinfo *hw = rvu->hw;
+ u16 pcifunc, entry = 0;
+ int pf, vf, numvfs;
+ int err, nixlf, i;
+ u8 rep;
+
+ for (pf = 1; pf < hw->total_pfs; pf++) {
+ if (!is_pf_cgxmapped(rvu, pf))
+ continue;
+
+ pcifunc = pf << RVU_PFVF_PF_SHIFT;
+ rvu_get_nix_blkaddr(rvu, pcifunc);
+ rep = true;
+ for (i = 0; i < 2; i++) {
+ err = rvu_rep_install_rx_rule(rvu, pcifunc,
+ start + entry, rep);
+ if (err)
+ return err;
+ rswitch->entry2pcifunc[entry++] = pcifunc;
+
+ err = rvu_rep_install_tx_rule(rvu, pcifunc,
+ start + entry, rep);
+ if (err)
+ return err;
+ rswitch->entry2pcifunc[entry++] = pcifunc;
+ rep = false;
+ }
+
+ rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL);
+ for (vf = 0; vf < numvfs; vf++) {
+ pcifunc = pf << RVU_PFVF_PF_SHIFT |
+ ((vf + 1) & RVU_PFVF_FUNC_MASK);
+ rvu_get_nix_blkaddr(rvu, pcifunc);
+
+ /* Skip installimg rules if nixlf is not attached */
+ err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL);
+ if (err)
+ continue;
+ rep = true;
+ for (i = 0; i < 2; i++) {
+ err = rvu_rep_install_rx_rule(rvu, pcifunc,
+ start + entry,
+ rep);
+ if (err)
+ return err;
+ rswitch->entry2pcifunc[entry++] = pcifunc;
+
+ err = rvu_rep_install_tx_rule(rvu, pcifunc,
+ start + entry,
+ rep);
+ if (err)
+ return err;
+ rswitch->entry2pcifunc[entry++] = pcifunc;
+ rep = false;
+ }
+ }
+ }
+
+ /* Initialize the wq for handling REP events */
+ spin_lock_init(&rvu->rep_evtq_lock);
+ INIT_LIST_HEAD(&rvu->rep_evtq_head);
+ INIT_WORK(&rvu->rep_evt_work, rvu_rep_wq_handler);
+ rvu->rep_evt_wq = alloc_workqueue("rep_evt_wq", 0, 0);
+ if (!rvu->rep_evt_wq) {
+ dev_err(rvu->dev, "REP workqueue allocation failed\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena)
+{
+ struct rvu_switch *rswitch = &rvu->rswitch;
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u32 max = rswitch->used_entries;
+ int blkaddr;
+ u16 entry;
+
+ if (!rswitch->used_entries)
+ return;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+
+ if (blkaddr < 0)
+ return;
+
+ rvu_switch_enable_lbk_link(rvu, pcifunc, ena);
+ mutex_lock(&mcam->lock);
+ for (entry = 0; entry < max; entry++) {
+ if (rswitch->entry2pcifunc[entry] == pcifunc)
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, entry, ena);
+ }
+ mutex_unlock(&mcam->lock);
+}
+
+int rvu_rep_pf_init(struct rvu *rvu)
+{
+ u16 pcifunc = rvu->rep_pcifunc;
+ struct rvu_pfvf *pfvf;
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ set_bit(NIXLF_INITIALIZED, &pfvf->flags);
+ rvu_switch_enable_lbk_link(rvu, pcifunc, true);
+ rvu_rep_rx_vlan_cfg(rvu, pcifunc);
+ return 0;
+}
+
+int rvu_mbox_handler_esw_cfg(struct rvu *rvu, struct esw_cfg_req *req,
+ struct msg_rsp *rsp)
+{
+ if (req->hdr.pcifunc != rvu->rep_pcifunc)
+ return 0;
+
+ rvu->rep_mode = req->ena;
+
+ if (!rvu->rep_mode)
+ rvu_npc_free_mcam_entries(rvu, req->hdr.pcifunc, -1);
+
+ return 0;
+}
+
+int rvu_mbox_handler_get_rep_cnt(struct rvu *rvu, struct msg_req *req,
+ struct get_rep_cnt_rsp *rsp)
+{
+ int pf, vf, numvfs, hwvf, rep = 0;
+ u16 pcifunc;
+
+ rvu->rep_pcifunc = req->hdr.pcifunc;
+ rsp->rep_cnt = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs;
+ rvu->rep_cnt = rsp->rep_cnt;
+
+ rvu->rep2pfvf_map = devm_kzalloc(rvu->dev, rvu->rep_cnt *
+ sizeof(u16), GFP_KERNEL);
+ if (!rvu->rep2pfvf_map)
+ return -ENOMEM;
+
+ for (pf = 0; pf < rvu->hw->total_pfs; pf++) {
+ if (!is_pf_cgxmapped(rvu, pf))
+ continue;
+ pcifunc = pf << RVU_PFVF_PF_SHIFT;
+ rvu->rep2pfvf_map[rep] = pcifunc;
+ rsp->rep_pf_map[rep] = pcifunc;
+ rep++;
+ rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf);
+ for (vf = 0; vf < numvfs; vf++) {
+ rvu->rep2pfvf_map[rep] = pcifunc |
+ ((vf + 1) & RVU_PFVF_FUNC_MASK);
+ rsp->rep_pf_map[rep] = rvu->rep2pfvf_map[rep];
+ rep++;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index fc8da2090657..77ac94cb2ec4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -823,4 +823,30 @@ enum nix_tx_vtag_op {
#define VTAG_STRIP BIT_ULL(4)
#define VTAG_CAPTURE BIT_ULL(5)
+/* NIX TX stats */
+enum nix_stat_lf_tx {
+ TX_UCAST = 0x0,
+ TX_BCAST = 0x1,
+ TX_MCAST = 0x2,
+ TX_DROP = 0x3,
+ TX_OCTS = 0x4,
+ TX_STATS_ENUM_LAST,
+};
+
+/* NIX RX stats */
+enum nix_stat_lf_rx {
+ RX_OCTS = 0x0,
+ RX_UCAST = 0x1,
+ RX_BCAST = 0x2,
+ RX_MCAST = 0x3,
+ RX_DROP = 0x4,
+ RX_DROP_OCTS = 0x5,
+ RX_FCS = 0x6,
+ RX_ERR = 0x7,
+ RX_DRP_BCAST = 0x8,
+ RX_DRP_MCAST = 0x9,
+ RX_DRP_L3BCAST = 0xa,
+ RX_DRP_L3MCAST = 0xb,
+ RX_STATS_ENUM_LAST,
+};
#endif /* RVU_STRUCT_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
index 854045ed3b06..268efb7c1c15 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c
@@ -8,7 +8,7 @@
#include <linux/bitfield.h>
#include "rvu.h"
-static void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable)
+void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable)
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
struct nix_hw *nix_hw;
@@ -166,6 +166,8 @@ void rvu_switch_enable(struct rvu *rvu)
alloc_req.contig = true;
alloc_req.count = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs;
+ if (rvu->rep_mode)
+ alloc_req.count = alloc_req.count * 4;
ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &alloc_req,
&alloc_rsp);
if (ret) {
@@ -189,7 +191,12 @@ void rvu_switch_enable(struct rvu *rvu)
rswitch->used_entries = alloc_rsp.count;
rswitch->start_entry = alloc_rsp.entry;
- ret = rvu_switch_install_rules(rvu);
+ if (rvu->rep_mode) {
+ rvu_rep_pf_init(rvu);
+ ret = rvu_rep_install_mcam_rules(rvu);
+ } else {
+ ret = rvu_switch_install_rules(rvu);
+ }
if (ret)
goto uninstall_rules;
@@ -222,6 +229,9 @@ void rvu_switch_disable(struct rvu *rvu)
if (!rswitch->used_entries)
return;
+ if (rvu->rep_mode)
+ goto free_ents;
+
for (pf = 1; pf < hw->total_pfs; pf++) {
if (!is_pf_cgxmapped(rvu, pf))
continue;
@@ -249,6 +259,7 @@ void rvu_switch_disable(struct rvu *rvu)
}
}
+free_ents:
uninstall_req.start = rswitch->start_entry;
uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1;
free_req.all = 1;
@@ -258,12 +269,15 @@ void rvu_switch_disable(struct rvu *rvu)
kfree(rswitch->entry2pcifunc);
}
-void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc)
+void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc, bool ena)
{
struct rvu_switch *rswitch = &rvu->rswitch;
u32 max = rswitch->used_entries;
u16 entry;
+ if (rvu->rep_mode)
+ return rvu_rep_update_rules(rvu, pcifunc, ena);
+
if (!rswitch->used_entries)
return;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
index 64a97a0a10ed..dbc971266865 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile
@@ -5,11 +5,13 @@
obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o otx2_ptp.o
obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o otx2_ptp.o
+obj-$(CONFIG_RVU_ESWITCH) += rvu_rep.o
rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o \
otx2_devlink.o qos_sq.o qos.o
rvu_nicvf-y := otx2_vf.o
+rvu_rep-y := rep.o
rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o
rvu_nicpf-$(CONFIG_MACSEC) += cn10k_macsec.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
index 7417087b6db5..a15cc86635d6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c
@@ -72,7 +72,7 @@ int cn10k_lmtst_init(struct otx2_nic *pfvf)
}
EXPORT_SYMBOL(cn10k_lmtst_init);
-int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
+int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura)
{
struct nix_cn10k_aq_enq_req *aq;
struct otx2_nic *pfvf = dev;
@@ -88,7 +88,7 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
aq->sq.ena = 1;
aq->sq.smq = otx2_get_smq_idx(pfvf, qidx);
aq->sq.smq_rr_weight = mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen);
- aq->sq.default_chan = pfvf->hw.tx_chan_base;
+ aq->sq.default_chan = pfvf->hw.tx_chan_base + chan_offset;
aq->sq.sqe_stype = NIX_STYPE_STF; /* Cache SQB */
aq->sq.sqb_aura = sqb_aura;
aq->sq.sq_int_ena = NIX_SQINT_BITS;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
index c1861f7de254..e3f0bce9908f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h
@@ -26,7 +26,7 @@ static inline int mtu_to_dwrr_weight(struct otx2_nic *pfvf, int mtu)
int cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq);
void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx);
-int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
+int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura);
int cn10k_lmtst_init(struct otx2_nic *pfvf);
int cn10k_free_all_ipolicers(struct otx2_nic *pfvf);
int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index 7510a918d942..523ecb798a7a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -83,6 +83,7 @@ int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx)
otx2_nix_rq_op_stats(&rq->stats, pfvf, qidx);
return 1;
}
+EXPORT_SYMBOL(otx2_update_rq_stats);
int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx)
{
@@ -99,6 +100,7 @@ int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx)
otx2_nix_sq_op_stats(&sq->stats, pfvf, qidx);
return 1;
}
+EXPORT_SYMBOL(otx2_update_sq_stats);
void otx2_get_dev_stats(struct otx2_nic *pfvf)
{
@@ -227,7 +229,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
u16 maxlen;
int err;
- maxlen = otx2_get_max_mtu(pfvf) + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN;
+ maxlen = pfvf->hw.max_mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN;
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_nix_set_hw_frs(&pfvf->mbox);
@@ -236,7 +238,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
return -ENOMEM;
}
- req->maxlen = pfvf->netdev->mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN;
+ req->maxlen = mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN;
/* Use max receive length supported by hardware for loopback devices */
if (is_otx2_lbkvf(pfvf->pdev))
@@ -246,13 +248,14 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
mutex_unlock(&pfvf->mbox.lock);
return err;
}
+EXPORT_SYMBOL(otx2_hw_set_mtu);
int otx2_config_pause_frm(struct otx2_nic *pfvf)
{
struct cgx_pause_frm_cfg *req;
int err;
- if (is_otx2_lbkvf(pfvf->pdev))
+ if (is_otx2_lbkvf(pfvf->pdev) || is_otx2_sdp_rep(pfvf->pdev))
return 0;
mutex_lock(&pfvf->mbox.lock);
@@ -646,12 +649,22 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for
req->reg[2] = NIX_AF_MDQX_SCHEDULE(schq);
req->regval[2] = dwrr_val;
} else if (lvl == NIX_TXSCH_LVL_TL4) {
+ int sdp_chan = hw->tx_chan_base + prio;
+
+ if (is_otx2_sdp_rep(pfvf->pdev))
+ prio = 0;
parent = schq_list[NIX_TXSCH_LVL_TL3][prio];
req->reg[0] = NIX_AF_TL4X_PARENT(schq);
req->regval[0] = (u64)parent << 16;
req->num_regs++;
req->reg[1] = NIX_AF_TL4X_SCHEDULE(schq);
req->regval[1] = dwrr_val;
+ if (is_otx2_sdp_rep(pfvf->pdev)) {
+ req->num_regs++;
+ req->reg[2] = NIX_AF_TL4X_SDP_LINK_CFG(schq);
+ req->regval[2] = BIT_ULL(12) | BIT_ULL(13) |
+ (sdp_chan & 0xff);
+ }
} else if (lvl == NIX_TXSCH_LVL_TL3) {
parent = schq_list[NIX_TXSCH_LVL_TL2][prio];
req->reg[0] = NIX_AF_TL3X_PARENT(schq);
@@ -659,7 +672,8 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for
req->num_regs++;
req->reg[1] = NIX_AF_TL3X_SCHEDULE(schq);
req->regval[1] = dwrr_val;
- if (lvl == hw->txschq_link_cfg_lvl) {
+ if (lvl == hw->txschq_link_cfg_lvl &&
+ !is_otx2_sdp_rep(pfvf->pdev)) {
req->num_regs++;
req->reg[2] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, hw->tx_link);
/* Enable this queue and backpressure
@@ -676,7 +690,8 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for
req->reg[1] = NIX_AF_TL2X_SCHEDULE(schq);
req->regval[1] = (u64)hw->txschq_aggr_lvl_rr_prio << 24 | dwrr_val;
- if (lvl == hw->txschq_link_cfg_lvl) {
+ if (lvl == hw->txschq_link_cfg_lvl &&
+ !is_otx2_sdp_rep(pfvf->pdev)) {
req->num_regs++;
req->reg[2] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, hw->tx_link);
/* Enable this queue and backpressure
@@ -735,6 +750,7 @@ EXPORT_SYMBOL(otx2_smq_flush);
int otx2_txsch_alloc(struct otx2_nic *pfvf)
{
+ int chan_cnt = pfvf->hw.tx_chan_cnt;
struct nix_txsch_alloc_req *req;
struct nix_txsch_alloc_rsp *rsp;
int lvl, schq, rc;
@@ -747,6 +763,12 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf)
/* Request one schq per level */
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++)
req->schq[lvl] = 1;
+
+ if (is_otx2_sdp_rep(pfvf->pdev) && chan_cnt > 1) {
+ req->schq[NIX_TXSCH_LVL_SMQ] = chan_cnt;
+ req->schq[NIX_TXSCH_LVL_TL4] = chan_cnt;
+ }
+
rc = otx2_sync_mbox_msg(&pfvf->mbox);
if (rc)
return rc;
@@ -757,10 +779,12 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf)
return PTR_ERR(rsp);
/* Setup transmit scheduler list */
- for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++)
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ pfvf->hw.txschq_cnt[lvl] = rsp->schq[lvl];
for (schq = 0; schq < rsp->schq[lvl]; schq++)
pfvf->hw.txschq_list[lvl][schq] =
rsp->schq_list[lvl][schq];
+ }
pfvf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl;
pfvf->hw.txschq_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio;
@@ -798,12 +822,15 @@ EXPORT_SYMBOL(otx2_txschq_free_one);
void otx2_txschq_stop(struct otx2_nic *pfvf)
{
- int lvl, schq;
+ int lvl, schq, idx;
/* free non QOS TLx nodes */
- for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++)
- otx2_txschq_free_one(pfvf, lvl,
- pfvf->hw.txschq_list[lvl][0]);
+ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
+ for (idx = 0; idx < pfvf->hw.txschq_cnt[lvl]; idx++) {
+ otx2_txschq_free_one(pfvf, lvl,
+ pfvf->hw.txschq_list[lvl][idx]);
+ }
+ }
/* Clear the txschq list */
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
@@ -883,7 +910,7 @@ static int otx2_rq_init(struct otx2_nic *pfvf, u16 qidx, u16 lpb_aura)
return otx2_sync_mbox_msg(&pfvf->mbox);
}
-int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
+int otx2_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura)
{
struct otx2_nic *pfvf = dev;
struct otx2_snd_queue *sq;
@@ -902,7 +929,7 @@ int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura)
aq->sq.ena = 1;
aq->sq.smq = otx2_get_smq_idx(pfvf, qidx);
aq->sq.smq_rr_quantum = mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen);
- aq->sq.default_chan = pfvf->hw.tx_chan_base;
+ aq->sq.default_chan = pfvf->hw.tx_chan_base + chan_offset;
aq->sq.sqe_stype = NIX_STYPE_STF; /* Cache SQB */
aq->sq.sqb_aura = sqb_aura;
aq->sq.sq_int_ena = NIX_SQINT_BITS;
@@ -925,6 +952,7 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
struct otx2_qset *qset = &pfvf->qset;
struct otx2_snd_queue *sq;
struct otx2_pool *pool;
+ u8 chan_offset;
int err;
pool = &pfvf->qset.pool[sqb_aura];
@@ -971,7 +999,8 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
sq->stats.bytes = 0;
sq->stats.pkts = 0;
- err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura);
+ chan_offset = qidx % pfvf->hw.tx_chan_cnt;
+ err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, chan_offset, sqb_aura);
if (err) {
kfree(sq->sg);
sq->sg = NULL;
@@ -1738,6 +1767,8 @@ void mbox_handler_nix_lf_alloc(struct otx2_nic *pfvf,
pfvf->hw.sqb_size = rsp->sqb_size;
pfvf->hw.rx_chan_base = rsp->rx_chan_base;
pfvf->hw.tx_chan_base = rsp->tx_chan_base;
+ pfvf->hw.rx_chan_cnt = rsp->rx_chan_cnt;
+ pfvf->hw.tx_chan_cnt = rsp->tx_chan_cnt;
pfvf->hw.lso_tsov4_idx = rsp->lso_tsov4_idx;
pfvf->hw.lso_tsov6_idx = rsp->lso_tsov6_idx;
pfvf->hw.cgx_links = rsp->cgx_links;
@@ -1782,6 +1813,7 @@ void otx2_free_cints(struct otx2_nic *pfvf, int n)
free_irq(vector, &qset->napi[qidx]);
}
}
+EXPORT_SYMBOL(otx2_free_cints);
void otx2_set_cints_affinity(struct otx2_nic *pfvf)
{
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index f27a3456ae64..566848663fea 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -29,6 +29,7 @@
#include "otx2_devlink.h"
#include <rvu_trace.h>
#include "qos.h"
+#include "rep.h"
/* IPv4 flag more fragment bit */
#define IPV4_FLAG_MORE 0x20
@@ -41,6 +42,8 @@
#define PCI_SUBSYS_DEVID_96XX_RVU_PFVF 0xB200
#define PCI_SUBSYS_DEVID_CN10K_B_RVU_PFVF 0xBD00
+#define PCI_DEVID_OCTEONTX2_SDP_REP 0xA0F7
+
/* PCI BAR nos */
#define PCI_CFG_REG_BAR_NUM 2
#define PCI_MBOX_BAR_NUM 4
@@ -120,33 +123,6 @@ enum otx2_errcodes_re {
ERRCODE_IL4_CSUM = 0x22,
};
-/* NIX TX stats */
-enum nix_stat_lf_tx {
- TX_UCAST = 0x0,
- TX_BCAST = 0x1,
- TX_MCAST = 0x2,
- TX_DROP = 0x3,
- TX_OCTS = 0x4,
- TX_STATS_ENUM_LAST,
-};
-
-/* NIX RX stats */
-enum nix_stat_lf_rx {
- RX_OCTS = 0x0,
- RX_UCAST = 0x1,
- RX_BCAST = 0x2,
- RX_MCAST = 0x3,
- RX_DROP = 0x4,
- RX_DROP_OCTS = 0x5,
- RX_FCS = 0x6,
- RX_ERR = 0x7,
- RX_DRP_BCAST = 0x8,
- RX_DRP_MCAST = 0x9,
- RX_DRP_L3BCAST = 0xa,
- RX_DRP_L3MCAST = 0xb,
- RX_STATS_ENUM_LAST,
-};
-
struct otx2_dev_stats {
u64 rx_bytes;
u64 rx_frames;
@@ -224,15 +200,19 @@ struct otx2_hw {
/* NIX */
u8 txschq_link_cfg_lvl;
+ u8 txschq_cnt[NIX_TXSCH_LVL_CNT];
u8 txschq_aggr_lvl_rr_prio;
u16 txschq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
u16 matchall_ipolicer;
u32 dwrr_mtu;
+ u32 max_mtu;
u8 smq_link_type;
/* HW settings, coalescing etc */
u16 rx_chan_base;
u16 tx_chan_base;
+ u8 rx_chan_cnt;
+ u8 tx_chan_cnt;
u16 cq_qcount_wait;
u16 cq_ecount_wait;
u16 rq_skid;
@@ -367,7 +347,8 @@ struct otx2_flow_config {
};
struct dev_hw_ops {
- int (*sq_aq_init)(void *dev, u16 qidx, u16 sqb_aura);
+ int (*sq_aq_init)(void *dev, u16 qidx, u8 chan_offset,
+ u16 sqb_aura);
void (*sqe_flush)(void *dev, struct otx2_snd_queue *sq,
int size, int qidx);
int (*refill_pool_ptrs)(void *dev, struct otx2_cq_queue *cq);
@@ -465,6 +446,8 @@ struct otx2_nic {
#define OTX2_FLAG_PTP_ONESTEP_SYNC BIT_ULL(15)
#define OTX2_FLAG_ADPTV_INT_COAL_ENABLED BIT_ULL(16)
#define OTX2_FLAG_TC_MARK_ENABLED BIT_ULL(17)
+#define OTX2_FLAG_REP_MODE_ENABLED BIT_ULL(18)
+#define OTX2_FLAG_PORT_UP BIT_ULL(19)
u64 flags;
u64 *cq_op_addr;
@@ -532,11 +515,19 @@ struct otx2_nic {
#if IS_ENABLED(CONFIG_MACSEC)
struct cn10k_mcs_cfg *macsec_cfg;
#endif
+
+#if IS_ENABLED(CONFIG_RVU_ESWITCH)
+ struct rep_dev **reps;
+ int rep_cnt;
+ u16 rep_pf_map[RVU_MAX_REP];
+ u16 esw_mode;
+#endif
};
static inline bool is_otx2_lbkvf(struct pci_dev *pdev)
{
- return pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF;
+ return (pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF) ||
+ (pdev->device == PCI_DEVID_RVU_REP);
}
static inline bool is_96xx_A0(struct pci_dev *pdev)
@@ -551,6 +542,11 @@ static inline bool is_96xx_B0(struct pci_dev *pdev)
(pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX_RVU_PFVF);
}
+static inline bool is_otx2_sdp_rep(struct pci_dev *pdev)
+{
+ return pdev->device == PCI_DEVID_OCTEONTX2_SDP_REP;
+}
+
/* REVID for PCIe devices.
* Bits 0..1: minor pass, bit 3..2: major pass
* bits 7..4: midr id
@@ -913,15 +909,19 @@ static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf,
static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx)
{
u16 smq;
+ int idx;
+
#ifdef CONFIG_DCB
if (qidx < NIX_PF_PFC_PRIO_MAX && pfvf->pfc_alloc_status[qidx])
return pfvf->pfc_schq_list[NIX_TXSCH_LVL_SMQ][qidx];
#endif
/* check if qidx falls under QOS queues */
- if (qidx >= pfvf->hw.non_qos_queues)
+ if (qidx >= pfvf->hw.non_qos_queues) {
smq = pfvf->qos.qid_to_sqmap[qidx - pfvf->hw.non_qos_queues];
- else
- smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][0];
+ } else {
+ idx = qidx % pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ];
+ smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][idx];
+ }
return smq;
}
@@ -988,14 +988,28 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable);
void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx);
void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura);
-int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
-int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
+int otx2_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura);
+int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura);
int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq,
dma_addr_t *dma);
int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
int stack_pages, int numptrs, int buf_size, int type);
int otx2_aura_init(struct otx2_nic *pfvf, int aura_id,
int pool_id, int numptrs);
+int otx2_init_rsrc(struct pci_dev *pdev, struct otx2_nic *pf);
+void otx2_free_queue_mem(struct otx2_qset *qset);
+int otx2_alloc_queue_mem(struct otx2_nic *pf);
+int otx2_init_hw_resources(struct otx2_nic *pfvf);
+void otx2_free_hw_resources(struct otx2_nic *pf);
+int otx2_wq_init(struct otx2_nic *pf);
+int otx2_check_pf_usable(struct otx2_nic *pf);
+int otx2_pfaf_mbox_init(struct otx2_nic *pf);
+int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af);
+int otx2_realloc_msix_vectors(struct otx2_nic *pf);
+void otx2_pfaf_mbox_destroy(struct otx2_nic *pf);
+void otx2_disable_mbox_intr(struct otx2_nic *pf);
+void otx2_disable_napi(struct otx2_nic *pf);
+irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq);
/* RSS configuration APIs*/
int otx2_rss_init(struct otx2_nic *pfvf);
@@ -1127,4 +1141,12 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid);
void otx2_qos_config_txschq(struct otx2_nic *pfvf);
void otx2_clean_qos_queues(struct otx2_nic *pfvf);
+int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info);
+int otx2_setup_tc_cls_flower(struct otx2_nic *nic,
+ struct flow_cls_offload *cls_flower);
+
+static inline int mcam_entry_cmp(const void *a, const void *b)
+{
+ return *(u16 *)a - *(u16 *)b;
+}
#endif /* OTX2_COMMON_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
index 53f14aa944bd..33ec9a7f7c03 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
@@ -141,7 +141,56 @@ static const struct devlink_param otx2_dl_params[] = {
otx2_dl_ucast_flt_cnt_validate),
};
+#ifdef CONFIG_RVU_ESWITCH
+static int otx2_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
+{
+ struct otx2_devlink *otx2_dl = devlink_priv(devlink);
+ struct otx2_nic *pfvf = otx2_dl->pfvf;
+
+ if (!otx2_rep_dev(pfvf->pdev))
+ return -EOPNOTSUPP;
+
+ *mode = pfvf->esw_mode;
+
+ return 0;
+}
+
+static int otx2_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+ struct netlink_ext_ack *extack)
+{
+ struct otx2_devlink *otx2_dl = devlink_priv(devlink);
+ struct otx2_nic *pfvf = otx2_dl->pfvf;
+ int ret = 0;
+
+ if (!otx2_rep_dev(pfvf->pdev))
+ return -EOPNOTSUPP;
+
+ if (pfvf->esw_mode == mode)
+ return 0;
+
+ switch (mode) {
+ case DEVLINK_ESWITCH_MODE_LEGACY:
+ rvu_rep_destroy(pfvf);
+ break;
+ case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+ ret = rvu_rep_create(pfvf, extack);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!ret)
+ pfvf->esw_mode = mode;
+
+ return ret;
+}
+#endif
+
static const struct devlink_ops otx2_devlink_ops = {
+#ifdef CONFIG_RVU_ESWITCH
+ .eswitch_mode_get = otx2_devlink_eswitch_mode_get,
+ .eswitch_mode_set = otx2_devlink_eswitch_mode_set,
+#endif
};
int otx2_register_dl(struct otx2_nic *pfvf)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index 5197ce816581..2d53dc77ef1e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -85,26 +85,22 @@ static void otx2_get_qset_strings(struct otx2_nic *pfvf, u8 **data, int qset)
int start_qidx = qset * pfvf->hw.rx_queues;
int qidx, stats;
- for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) {
- for (stats = 0; stats < otx2_n_queue_stats; stats++) {
- sprintf(*data, "rxq%d: %s", qidx + start_qidx,
- otx2_queue_stats[stats].name);
- *data += ETH_GSTRING_LEN;
- }
- }
+ for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++)
+ for (stats = 0; stats < otx2_n_queue_stats; stats++)
+ ethtool_sprintf(data, "rxq%d: %s", qidx + start_qidx,
+ otx2_queue_stats[stats].name);
- for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) {
- for (stats = 0; stats < otx2_n_queue_stats; stats++) {
+ for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++)
+ for (stats = 0; stats < otx2_n_queue_stats; stats++)
if (qidx >= pfvf->hw.non_qos_queues)
- sprintf(*data, "txq_qos%d: %s",
- qidx + start_qidx - pfvf->hw.non_qos_queues,
- otx2_queue_stats[stats].name);
+ ethtool_sprintf(data, "txq_qos%d: %s",
+ qidx + start_qidx -
+ pfvf->hw.non_qos_queues,
+ otx2_queue_stats[stats].name);
else
- sprintf(*data, "txq%d: %s", qidx + start_qidx,
- otx2_queue_stats[stats].name);
- *data += ETH_GSTRING_LEN;
- }
- }
+ ethtool_sprintf(data, "txq%d: %s",
+ qidx + start_qidx,
+ otx2_queue_stats[stats].name);
}
static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
@@ -115,36 +111,25 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data)
if (sset != ETH_SS_STATS)
return;
- for (stats = 0; stats < otx2_n_dev_stats; stats++) {
- memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < otx2_n_dev_stats; stats++)
+ ethtool_puts(&data, otx2_dev_stats[stats].name);
- for (stats = 0; stats < otx2_n_drv_stats; stats++) {
- memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < otx2_n_drv_stats; stats++)
+ ethtool_puts(&data, otx2_drv_stats[stats].name);
otx2_get_qset_strings(pfvf, &data, 0);
if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) {
- for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) {
- sprintf(data, "cgx_rxstat%d: ", stats);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++)
+ ethtool_sprintf(&data, "cgx_rxstat%d: ", stats);
- for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) {
- sprintf(data, "cgx_txstat%d: ", stats);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++)
+ ethtool_sprintf(&data, "cgx_txstat%d: ", stats);
}
- strcpy(data, "reset_count");
- data += ETH_GSTRING_LEN;
- sprintf(data, "Fec Corrected Errors: ");
- data += ETH_GSTRING_LEN;
- sprintf(data, "Fec Uncorrected Errors: ");
- data += ETH_GSTRING_LEN;
+ ethtool_puts(&data, "reset_count");
+ ethtool_puts(&data, "Fec Corrected Errors: ");
+ ethtool_puts(&data, "Fec Uncorrected Errors: ");
}
static void otx2_get_qset_stats(struct otx2_nic *pfvf,
@@ -1375,20 +1360,15 @@ static void otx2vf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
if (sset != ETH_SS_STATS)
return;
- for (stats = 0; stats < otx2_n_dev_stats; stats++) {
- memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < otx2_n_dev_stats; stats++)
+ ethtool_puts(&data, otx2_dev_stats[stats].name);
- for (stats = 0; stats < otx2_n_drv_stats; stats++) {
- memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN);
- data += ETH_GSTRING_LEN;
- }
+ for (stats = 0; stats < otx2_n_drv_stats; stats++)
+ ethtool_puts(&data, otx2_drv_stats[stats].name);
otx2_get_qset_strings(vf, &data, 0);
- strcpy(data, "reset_count");
- data += ETH_GSTRING_LEN;
+ ethtool_puts(&data, "reset_count");
}
static void otx2vf_get_ethtool_stats(struct net_device *netdev,
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 58720a161ee2..47bfd1fb37d4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -64,11 +64,6 @@ static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf)
return 0;
}
-static int mcam_entry_cmp(const void *a, const void *b)
-{
- return *(u16 *)a - *(u16 *)b;
-}
-
int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 5492dea547a1..e310f99b1736 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -519,6 +519,7 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work)
switch (msg->id) {
case MBOX_MSG_CGX_LINK_EVENT:
+ case MBOX_MSG_REP_EVENT_UP_NOTIFY:
break;
default:
if (msg->rc)
@@ -832,6 +833,9 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
struct cgx_link_user_info *linfo = &pf->linfo;
struct net_device *netdev = pf->netdev;
+ if (pf->flags & OTX2_FLAG_PORT_UP)
+ return;
+
pr_info("%s NIC Link is %s %d Mbps %s duplex\n", netdev->name,
linfo->link_up ? "UP" : "DOWN", linfo->speed,
linfo->full_duplex ? "Full" : "Half");
@@ -844,6 +848,35 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
}
}
+static int otx2_mbox_up_handler_rep_event_up_notify(struct otx2_nic *pf,
+ struct rep_event *info,
+ struct msg_rsp *rsp)
+{
+ struct net_device *netdev = pf->netdev;
+
+ if (info->event == RVU_EVENT_MTU_CHANGE) {
+ netdev->mtu = info->evt_data.mtu;
+ return 0;
+ }
+
+ if (info->event == RVU_EVENT_PORT_STATE) {
+ if (info->evt_data.port_state) {
+ pf->flags |= OTX2_FLAG_PORT_UP;
+ netif_carrier_on(netdev);
+ netif_tx_start_all_queues(netdev);
+ } else {
+ pf->flags &= ~OTX2_FLAG_PORT_UP;
+ netif_tx_stop_all_queues(netdev);
+ netif_carrier_off(netdev);
+ }
+ return 0;
+ }
+#ifdef CONFIG_RVU_ESWITCH
+ rvu_event_up_notify(pf, info);
+#endif
+ return 0;
+}
+
int otx2_mbox_up_handler_mcs_intr_notify(struct otx2_nic *pf,
struct mcs_intr_info *event,
struct msg_rsp *rsp)
@@ -913,6 +946,7 @@ static int otx2_process_mbox_msg_up(struct otx2_nic *pf,
}
MBOX_UP_CGX_MESSAGES
MBOX_UP_MCS_MESSAGES
+MBOX_UP_REP_MESSAGES
#undef M
break;
default:
@@ -1008,7 +1042,7 @@ static irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq)
return IRQ_HANDLED;
}
-static void otx2_disable_mbox_intr(struct otx2_nic *pf)
+void otx2_disable_mbox_intr(struct otx2_nic *pf)
{
int vector = pci_irq_vector(pf->pdev, RVU_PF_INT_VEC_AFPF_MBOX);
@@ -1016,8 +1050,9 @@ static void otx2_disable_mbox_intr(struct otx2_nic *pf)
otx2_write64(pf, RVU_PF_INT_ENA_W1C, BIT_ULL(0));
free_irq(vector, pf);
}
+EXPORT_SYMBOL(otx2_disable_mbox_intr);
-static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
+int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
{
struct otx2_hw *hw = &pf->hw;
struct msg_req *req;
@@ -1061,7 +1096,7 @@ static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
return 0;
}
-static void otx2_pfaf_mbox_destroy(struct otx2_nic *pf)
+void otx2_pfaf_mbox_destroy(struct otx2_nic *pf)
{
struct mbox *mbox = &pf->mbox;
@@ -1076,8 +1111,9 @@ static void otx2_pfaf_mbox_destroy(struct otx2_nic *pf)
otx2_mbox_destroy(&mbox->mbox);
otx2_mbox_destroy(&mbox->mbox_up);
}
+EXPORT_SYMBOL(otx2_pfaf_mbox_destroy);
-static int otx2_pfaf_mbox_init(struct otx2_nic *pf)
+int otx2_pfaf_mbox_init(struct otx2_nic *pf)
{
struct mbox *mbox = &pf->mbox;
void __iomem *hwbase;
@@ -1379,7 +1415,7 @@ done:
return IRQ_HANDLED;
}
-static irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq)
+irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq)
{
struct otx2_cq_poll *cq_poll = (struct otx2_cq_poll *)cq_irq;
struct otx2_nic *pf = (struct otx2_nic *)cq_poll->dev;
@@ -1398,20 +1434,25 @@ static irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL(otx2_cq_intr_handler);
-static void otx2_disable_napi(struct otx2_nic *pf)
+void otx2_disable_napi(struct otx2_nic *pf)
{
struct otx2_qset *qset = &pf->qset;
struct otx2_cq_poll *cq_poll;
+ struct work_struct *work;
int qidx;
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
cq_poll = &qset->napi[qidx];
- cancel_work_sync(&cq_poll->dim.work);
+ work = &cq_poll->dim.work;
+ if (work->func)
+ cancel_work_sync(work);
napi_disable(&cq_poll->napi);
netif_napi_del(&cq_poll->napi);
}
}
+EXPORT_SYMBOL(otx2_disable_napi);
static void otx2_free_cq_res(struct otx2_nic *pf)
{
@@ -1477,7 +1518,7 @@ static int otx2_get_rbuf_size(struct otx2_nic *pf, int mtu)
return ALIGN(rbuf_size, 2048);
}
-static int otx2_init_hw_resources(struct otx2_nic *pf)
+int otx2_init_hw_resources(struct otx2_nic *pf)
{
struct nix_lf_free_req *free_req;
struct mbox *mbox = &pf->mbox;
@@ -1493,10 +1534,11 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
hw->sqpool_cnt = otx2_get_total_tx_queues(pf);
hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt;
- /* Maximum hardware supported transmit length */
- pf->tx_max_pktlen = pf->netdev->max_mtu + OTX2_ETH_HLEN;
-
- pf->rbsize = otx2_get_rbuf_size(pf, pf->netdev->mtu);
+ if (!otx2_rep_dev(pf->pdev)) {
+ /* Maximum hardware supported transmit length */
+ pf->tx_max_pktlen = pf->netdev->max_mtu + OTX2_ETH_HLEN;
+ pf->rbsize = otx2_get_rbuf_size(pf, pf->netdev->mtu);
+ }
mutex_lock(&mbox->lock);
/* NPA init */
@@ -1549,10 +1591,15 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
}
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
- err = otx2_txschq_config(pf, lvl, 0, false);
- if (err) {
- mutex_unlock(&mbox->lock);
- goto err_free_nix_queues;
+ int idx;
+
+ for (idx = 0; idx < pf->hw.txschq_cnt[lvl]; idx++) {
+ err = otx2_txschq_config(pf, lvl, idx, false);
+ if (err) {
+ dev_err(pf->dev, "Failed to config TXSCH\n");
+ mutex_unlock(&mbox->lock);
+ goto err_free_nix_queues;
+ }
}
}
@@ -1601,8 +1648,9 @@ exit:
mutex_unlock(&mbox->lock);
return err;
}
+EXPORT_SYMBOL(otx2_init_hw_resources);
-static void otx2_free_hw_resources(struct otx2_nic *pf)
+void otx2_free_hw_resources(struct otx2_nic *pf)
{
struct otx2_qset *qset = &pf->qset;
struct nix_lf_free_req *free_req;
@@ -1624,11 +1672,12 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
otx2_pfc_txschq_stop(pf);
#endif
- otx2_clean_qos_queues(pf);
+ if (!otx2_rep_dev(pf->pdev))
+ otx2_clean_qos_queues(pf);
mutex_lock(&mbox->lock);
/* Disable backpressure */
- if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK))
+ if (!is_otx2_lbkvf(pf->pdev))
otx2_nix_config_bp(pf, false);
mutex_unlock(&mbox->lock);
@@ -1660,7 +1709,8 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
otx2_free_cq_res(pf);
/* Free all ingress bandwidth profiles allocated */
- cn10k_free_all_ipolicers(pf);
+ if (!otx2_rep_dev(pf->pdev))
+ cn10k_free_all_ipolicers(pf);
mutex_lock(&mbox->lock);
/* Reset NIX LF */
@@ -1688,6 +1738,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
}
mutex_unlock(&mbox->lock);
}
+EXPORT_SYMBOL(otx2_free_hw_resources);
static bool otx2_promisc_use_mce_list(struct otx2_nic *pfvf)
{
@@ -1770,15 +1821,24 @@ static void otx2_dim_work(struct work_struct *w)
dim->state = DIM_START_MEASURE;
}
-int otx2_open(struct net_device *netdev)
+void otx2_free_queue_mem(struct otx2_qset *qset)
+{
+ kfree(qset->sq);
+ qset->sq = NULL;
+ kfree(qset->cq);
+ qset->cq = NULL;
+ kfree(qset->rq);
+ qset->rq = NULL;
+ kfree(qset->napi);
+ qset->napi = NULL;
+}
+EXPORT_SYMBOL(otx2_free_queue_mem);
+
+int otx2_alloc_queue_mem(struct otx2_nic *pf)
{
- struct otx2_nic *pf = netdev_priv(netdev);
- struct otx2_cq_poll *cq_poll = NULL;
struct otx2_qset *qset = &pf->qset;
- int err = 0, qidx, vec;
- char *irq_name;
+ struct otx2_cq_poll *cq_poll;
- netif_carrier_off(netdev);
/* RQ and SQs are mapped to different CQs,
* so find out max CQ IRQs (i.e CINTs) needed.
@@ -1798,7 +1858,6 @@ int otx2_open(struct net_device *netdev)
/* CQ size of SQ */
qset->sqe_cnt = qset->sqe_cnt ? qset->sqe_cnt : Q_COUNT(Q_SIZE_4K);
- err = -ENOMEM;
qset->cq = kcalloc(pf->qset.cq_cnt,
sizeof(struct otx2_cq_queue), GFP_KERNEL);
if (!qset->cq)
@@ -1814,6 +1873,28 @@ int otx2_open(struct net_device *netdev)
if (!qset->rq)
goto err_free_mem;
+ return 0;
+
+err_free_mem:
+ otx2_free_queue_mem(qset);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(otx2_alloc_queue_mem);
+
+int otx2_open(struct net_device *netdev)
+{
+ struct otx2_nic *pf = netdev_priv(netdev);
+ struct otx2_cq_poll *cq_poll = NULL;
+ struct otx2_qset *qset = &pf->qset;
+ int err = 0, qidx, vec;
+ char *irq_name;
+
+ netif_carrier_off(netdev);
+
+ err = otx2_alloc_queue_mem(pf);
+ if (err)
+ return err;
+
err = otx2_init_hw_resources(pf);
if (err)
goto err_free_mem;
@@ -1932,6 +2013,7 @@ int otx2_open(struct net_device *netdev)
}
pf->flags &= ~OTX2_FLAG_INTF_DOWN;
+ pf->flags &= ~OTX2_FLAG_PORT_UP;
/* 'intf_down' may be checked on any cpu */
smp_wmb();
@@ -1979,10 +2061,7 @@ err_disable_napi:
otx2_disable_napi(pf);
otx2_free_hw_resources(pf);
err_free_mem:
- kfree(qset->sq);
- kfree(qset->cq);
- kfree(qset->rq);
- kfree(qset->napi);
+ otx2_free_queue_mem(qset);
return err;
}
EXPORT_SYMBOL(otx2_open);
@@ -2047,11 +2126,7 @@ int otx2_stop(struct net_device *netdev)
for (qidx = 0; qidx < netdev->num_tx_queues; qidx++)
netdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx));
-
- kfree(qset->sq);
- kfree(qset->cq);
- kfree(qset->rq);
- kfree(qset->napi);
+ otx2_free_queue_mem(qset);
/* Do not clear RQ/SQ ringsize settings */
memset_startat(qset, 0, sqe_cnt);
return 0;
@@ -2081,7 +2156,7 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev)
sq = &pf->qset.sq[sq_idx];
txq = netdev_get_tx_queue(netdev, qidx);
- if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) {
+ if (!otx2_sq_append_skb(pf, txq, sq, skb, qidx)) {
netif_tx_stop_queue(txq);
/* Check again, incase SQBs got freed up */
@@ -2786,7 +2861,7 @@ static const struct net_device_ops otx2_netdev_ops = {
.ndo_set_vf_trust = otx2_ndo_set_vf_trust,
};
-static int otx2_wq_init(struct otx2_nic *pf)
+int otx2_wq_init(struct otx2_nic *pf)
{
pf->otx2_wq = create_singlethread_workqueue("otx2_wq");
if (!pf->otx2_wq)
@@ -2797,7 +2872,7 @@ static int otx2_wq_init(struct otx2_nic *pf)
return 0;
}
-static int otx2_check_pf_usable(struct otx2_nic *nic)
+int otx2_check_pf_usable(struct otx2_nic *nic)
{
u64 rev;
@@ -2815,7 +2890,7 @@ static int otx2_check_pf_usable(struct otx2_nic *nic)
return 0;
}
-static int otx2_realloc_msix_vectors(struct otx2_nic *pf)
+int otx2_realloc_msix_vectors(struct otx2_nic *pf)
{
struct otx2_hw *hw = &pf->hw;
int num_vec, err;
@@ -2837,6 +2912,7 @@ static int otx2_realloc_msix_vectors(struct otx2_nic *pf)
return otx2_register_mbox_intr(pf, false);
}
+EXPORT_SYMBOL(otx2_realloc_msix_vectors);
static int otx2_sriov_vfcfg_init(struct otx2_nic *pf)
{
@@ -2872,6 +2948,88 @@ static void otx2_sriov_vfcfg_cleanup(struct otx2_nic *pf)
}
}
+int otx2_init_rsrc(struct pci_dev *pdev, struct otx2_nic *pf)
+{
+ struct device *dev = &pdev->dev;
+ struct otx2_hw *hw = &pf->hw;
+ int num_vec, err;
+
+ num_vec = pci_msix_vec_count(pdev);
+ hw->irq_name = devm_kmalloc_array(&hw->pdev->dev, num_vec, NAME_SIZE,
+ GFP_KERNEL);
+ if (!hw->irq_name)
+ return -ENOMEM;
+
+ hw->affinity_mask = devm_kcalloc(&hw->pdev->dev, num_vec,
+ sizeof(cpumask_var_t), GFP_KERNEL);
+ if (!hw->affinity_mask)
+ return -ENOMEM;
+
+ /* Map CSRs */
+ pf->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
+ if (!pf->reg_base) {
+ dev_err(dev, "Unable to map physical function CSRs, aborting\n");
+ return -ENOMEM;
+ }
+
+ err = otx2_check_pf_usable(pf);
+ if (err)
+ return err;
+
+ err = pci_alloc_irq_vectors(hw->pdev, RVU_PF_INT_VEC_CNT,
+ RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX);
+ if (err < 0) {
+ dev_err(dev, "%s: Failed to alloc %d IRQ vectors\n",
+ __func__, num_vec);
+ return err;
+ }
+
+ otx2_setup_dev_hw_settings(pf);
+
+ /* Init PF <=> AF mailbox stuff */
+ err = otx2_pfaf_mbox_init(pf);
+ if (err)
+ goto err_free_irq_vectors;
+
+ /* Register mailbox interrupt */
+ err = otx2_register_mbox_intr(pf, true);
+ if (err)
+ goto err_mbox_destroy;
+
+ /* Request AF to attach NPA and NIX LFs to this PF.
+ * NIX and NPA LFs are needed for this PF to function as a NIC.
+ */
+ err = otx2_attach_npa_nix(pf);
+ if (err)
+ goto err_disable_mbox_intr;
+
+ err = otx2_realloc_msix_vectors(pf);
+ if (err)
+ goto err_detach_rsrc;
+
+ err = cn10k_lmtst_init(pf);
+ if (err)
+ goto err_detach_rsrc;
+
+ return 0;
+
+err_detach_rsrc:
+ if (pf->hw.lmt_info)
+ free_percpu(pf->hw.lmt_info);
+ if (test_bit(CN10K_LMTST, &pf->hw.cap_flag))
+ qmem_free(pf->dev, pf->dync_lmt);
+ otx2_detach_resources(&pf->mbox);
+err_disable_mbox_intr:
+ otx2_disable_mbox_intr(pf);
+err_mbox_destroy:
+ otx2_pfaf_mbox_destroy(pf);
+err_free_irq_vectors:
+ pci_free_irq_vectors(hw->pdev);
+
+ return err;
+}
+EXPORT_SYMBOL(otx2_init_rsrc);
+
static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
@@ -2879,7 +3037,6 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct net_device *netdev;
struct otx2_nic *pf;
struct otx2_hw *hw;
- int num_vec;
err = pcim_enable_device(pdev);
if (err) {
@@ -2930,72 +3087,14 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Use CQE of 128 byte descriptor size by default */
hw->xqe_size = 128;
- num_vec = pci_msix_vec_count(pdev);
- hw->irq_name = devm_kmalloc_array(&hw->pdev->dev, num_vec, NAME_SIZE,
- GFP_KERNEL);
- if (!hw->irq_name) {
- err = -ENOMEM;
- goto err_free_netdev;
- }
-
- hw->affinity_mask = devm_kcalloc(&hw->pdev->dev, num_vec,
- sizeof(cpumask_var_t), GFP_KERNEL);
- if (!hw->affinity_mask) {
- err = -ENOMEM;
- goto err_free_netdev;
- }
-
- /* Map CSRs */
- pf->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
- if (!pf->reg_base) {
- dev_err(dev, "Unable to map physical function CSRs, aborting\n");
- err = -ENOMEM;
- goto err_free_netdev;
- }
-
- err = otx2_check_pf_usable(pf);
+ err = otx2_init_rsrc(pdev, pf);
if (err)
goto err_free_netdev;
- err = pci_alloc_irq_vectors(hw->pdev, RVU_PF_INT_VEC_CNT,
- RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX);
- if (err < 0) {
- dev_err(dev, "%s: Failed to alloc %d IRQ vectors\n",
- __func__, num_vec);
- goto err_free_netdev;
- }
-
- otx2_setup_dev_hw_settings(pf);
-
- /* Init PF <=> AF mailbox stuff */
- err = otx2_pfaf_mbox_init(pf);
- if (err)
- goto err_free_irq_vectors;
-
- /* Register mailbox interrupt */
- err = otx2_register_mbox_intr(pf, true);
- if (err)
- goto err_mbox_destroy;
-
- /* Request AF to attach NPA and NIX LFs to this PF.
- * NIX and NPA LFs are needed for this PF to function as a NIC.
- */
- err = otx2_attach_npa_nix(pf);
- if (err)
- goto err_disable_mbox_intr;
-
- err = otx2_realloc_msix_vectors(pf);
- if (err)
- goto err_detach_rsrc;
-
err = otx2_set_real_num_queues(netdev, hw->tx_queues, hw->rx_queues);
if (err)
goto err_detach_rsrc;
- err = cn10k_lmtst_init(pf);
- if (err)
- goto err_detach_rsrc;
-
/* Assign default mac address */
otx2_get_mac_from_af(netdev);
@@ -3058,6 +3157,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
netdev->min_mtu = OTX2_MIN_MTU;
netdev->max_mtu = otx2_get_max_mtu(pf);
+ hw->max_mtu = netdev->max_mtu;
/* reset CGX/RPM MAC stats */
otx2_reset_mac_stats(pf);
@@ -3118,11 +3218,8 @@ err_detach_rsrc:
if (test_bit(CN10K_LMTST, &pf->hw.cap_flag))
qmem_free(pf->dev, pf->dync_lmt);
otx2_detach_resources(&pf->mbox);
-err_disable_mbox_intr:
otx2_disable_mbox_intr(pf);
-err_mbox_destroy:
otx2_pfaf_mbox_destroy(pf);
-err_free_irq_vectors:
pci_free_irq_vectors(hw->pdev);
err_free_netdev:
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index e63cc1eb6d89..9a226ca74425 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -443,6 +443,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
struct flow_action_entry *act;
struct net_device *target;
struct otx2_nic *priv;
+ struct rep_dev *rdev;
u32 burst, mark = 0;
u8 nr_police = 0;
u8 num_intf = 1;
@@ -464,14 +465,18 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
return 0;
case FLOW_ACTION_REDIRECT_INGRESS:
target = act->dev;
- priv = netdev_priv(target);
- /* npc_install_flow_req doesn't support passing a target pcifunc */
- if (rvu_get_pf(nic->pcifunc) != rvu_get_pf(priv->pcifunc)) {
- NL_SET_ERR_MSG_MOD(extack,
- "can't redirect to other pf/vf");
- return -EOPNOTSUPP;
+ if (target->dev.parent) {
+ priv = netdev_priv(target);
+ if (rvu_get_pf(nic->pcifunc) != rvu_get_pf(priv->pcifunc)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "can't redirect to other pf/vf");
+ return -EOPNOTSUPP;
+ }
+ req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK;
+ } else {
+ rdev = netdev_priv(target);
+ req->vf = rdev->pcifunc & RVU_PFVF_FUNC_MASK;
}
- req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK;
/* if op is already set; avoid overwriting the same */
if (!req->op)
@@ -1300,6 +1305,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
req->channel = nic->hw.rx_chan_base;
req->entry = flow_cfg->flow_ent[mcam_idx];
req->intf = NIX_INTF_RX;
+ req->vf = nic->pcifunc;
req->set_cntr = 1;
new_node->entry = req->entry;
@@ -1400,8 +1406,8 @@ static int otx2_tc_get_flow_stats(struct otx2_nic *nic,
return 0;
}
-static int otx2_setup_tc_cls_flower(struct otx2_nic *nic,
- struct flow_cls_offload *cls_flower)
+int otx2_setup_tc_cls_flower(struct otx2_nic *nic,
+ struct flow_cls_offload *cls_flower)
{
switch (cls_flower->command) {
case FLOW_CLS_REPLACE:
@@ -1414,6 +1420,7 @@ static int otx2_setup_tc_cls_flower(struct otx2_nic *nic,
return -EOPNOTSUPP;
}
}
+EXPORT_SYMBOL(otx2_setup_tc_cls_flower);
static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic,
struct tc_cls_matchall_offload *cls)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 933e18ba2fb2..04bc06a80e23 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -376,9 +376,11 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
}
otx2_set_rxhash(pfvf, cqe, skb);
- skb_record_rx_queue(skb, cq->cq_idx);
- if (pfvf->netdev->features & NETIF_F_RXCSUM)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (!(pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)) {
+ skb_record_rx_queue(skb, cq->cq_idx);
+ if (pfvf->netdev->features & NETIF_F_RXCSUM)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
if (pfvf->flags & OTX2_FLAG_TC_MARK_ENABLED)
skb->mark = parse->match_id;
@@ -453,6 +455,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf,
int tx_pkts = 0, tx_bytes = 0, qidx;
struct otx2_snd_queue *sq;
struct nix_cqe_tx_s *cqe;
+ struct net_device *ndev;
int processed_cqe = 0;
if (cq->pend_cqe >= budget)
@@ -493,6 +496,13 @@ process_cqe:
otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR,
((u64)cq->cq_idx << 32) | processed_cqe);
+#if IS_ENABLED(CONFIG_RVU_ESWITCH)
+ if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)
+ ndev = pfvf->reps[qidx]->netdev;
+ else
+#endif
+ ndev = pfvf->netdev;
+
if (likely(tx_pkts)) {
struct netdev_queue *txq;
@@ -500,12 +510,14 @@ process_cqe:
if (qidx >= pfvf->hw.tx_queues)
qidx -= pfvf->hw.xdp_queues;
- txq = netdev_get_tx_queue(pfvf->netdev, qidx);
+ if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)
+ qidx = 0;
+ txq = netdev_get_tx_queue(ndev, qidx);
netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
/* Check if queue was stopped earlier due to ring full */
smp_mb();
if (netif_tx_queue_stopped(txq) &&
- netif_carrier_ok(pfvf->netdev))
+ netif_carrier_ok(ndev))
netif_tx_wake_queue(txq);
}
return 0;
@@ -527,7 +539,7 @@ static void otx2_adjust_adaptive_coalese(struct otx2_nic *pfvf, struct otx2_cq_p
rx_frames + tx_frames,
rx_bytes + tx_bytes,
&dim_sample);
- net_dim(&cq_poll->dim, dim_sample);
+ net_dim(&cq_poll->dim, &dim_sample);
}
int otx2_napi_handler(struct napi_struct *napi, int budget)
@@ -594,6 +606,7 @@ int otx2_napi_handler(struct napi_struct *napi, int budget)
}
return workdone;
}
+EXPORT_SYMBOL(otx2_napi_handler);
void otx2_sqe_flush(void *dev, struct otx2_snd_queue *sq,
int size, int qidx)
@@ -1141,13 +1154,13 @@ static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb,
}
}
-bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq,
+bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq,
+ struct otx2_snd_queue *sq,
struct sk_buff *skb, u16 qidx)
{
- struct netdev_queue *txq = netdev_get_tx_queue(netdev, qidx);
- struct otx2_nic *pfvf = netdev_priv(netdev);
int offset, num_segs, free_desc;
struct nix_sqe_hdr_s *sqe_hdr;
+ struct otx2_nic *pfvf = dev;
/* Check if there is enough room between producer
* and consumer index.
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
index 3f1d2655ff77..e1db5f961877 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h
@@ -167,7 +167,8 @@ static inline u64 otx2_iova_to_phys(void *iommu_domain, dma_addr_t dma_addr)
}
int otx2_napi_handler(struct napi_struct *napi, int budget);
-bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq,
+bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq,
+ struct otx2_snd_queue *sq,
struct sk_buff *skb, u16 qidx);
void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq,
int size, int qidx);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index 99fcc5661674..839fc77c11b2 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -21,6 +21,7 @@
static const struct pci_device_id otx2_vf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AFVF) },
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_VF) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_SDP_REP) },
{ }
};
@@ -371,7 +372,7 @@ static int otx2vf_open(struct net_device *netdev)
/* LBKs do not receive link events so tell everyone we are up here */
vf = netdev_priv(netdev);
- if (is_otx2_lbkvf(vf->pdev)) {
+ if (is_otx2_lbkvf(vf->pdev) || is_otx2_sdp_rep(vf->pdev)) {
pr_info("%s NIC Link is UP\n", netdev->name);
netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);
@@ -395,7 +396,7 @@ static netdev_tx_t otx2vf_xmit(struct sk_buff *skb, struct net_device *netdev)
sq = &vf->qset.sq[qidx];
txq = netdev_get_tx_queue(netdev, qidx);
- if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) {
+ if (!otx2_sq_append_skb(vf, txq, sq, skb, qidx)) {
netif_tx_stop_queue(txq);
/* Check again, incase SQBs got freed up */
@@ -500,7 +501,7 @@ static const struct net_device_ops otx2vf_netdev_ops = {
.ndo_setup_tc = otx2_setup_tc,
};
-static int otx2_wq_init(struct otx2_nic *vf)
+static int otx2_vf_wq_init(struct otx2_nic *vf)
{
vf->otx2_wq = create_singlethread_workqueue("otx2vf_wq");
if (!vf->otx2_wq)
@@ -671,6 +672,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
netdev->min_mtu = OTX2_MIN_MTU;
netdev->max_mtu = otx2_get_max_mtu(vf);
+ hw->max_mtu = netdev->max_mtu;
/* To distinguish, for LBK VFs set netdev name explicitly */
if (is_otx2_lbkvf(vf->pdev)) {
@@ -682,13 +684,22 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
snprintf(netdev->name, sizeof(netdev->name), "lbk%d", n);
}
+ if (is_otx2_sdp_rep(vf->pdev)) {
+ int n;
+
+ n = vf->pcifunc & RVU_PFVF_FUNC_MASK;
+ n -= 1;
+ snprintf(netdev->name, sizeof(netdev->name), "sdp%d-%d",
+ pdev->bus->number, n);
+ }
+
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Failed to register netdevice\n");
goto err_ptp_destroy;
}
- err = otx2_wq_init(vf);
+ err = otx2_vf_wq_init(vf);
if (err)
goto err_unreg_netdev;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
new file mode 100644
index 000000000000..232b10740c13
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
@@ -0,0 +1,864 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell RVU representor driver
+ *
+ * Copyright (C) 2024 Marvell.
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/net_tstamp.h>
+#include <linux/sort.h>
+
+#include "otx2_common.h"
+#include "cn10k.h"
+#include "otx2_reg.h"
+#include "rep.h"
+
+#define DRV_NAME "rvu_rep"
+#define DRV_STRING "Marvell RVU Representor Driver"
+
+static const struct pci_device_id rvu_rep_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_RVU_REP) },
+ { }
+};
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION(DRV_STRING);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, rvu_rep_id_table);
+
+static int rvu_rep_notify_pfvf(struct otx2_nic *priv, u16 event,
+ struct rep_event *data);
+
+static int rvu_rep_mcam_flow_init(struct rep_dev *rep)
+{
+ struct npc_mcam_alloc_entry_req *req;
+ struct npc_mcam_alloc_entry_rsp *rsp;
+ struct otx2_nic *priv = rep->mdev;
+ int ent, allocated = 0;
+ int count;
+
+ rep->flow_cfg = kcalloc(1, sizeof(struct otx2_flow_config), GFP_KERNEL);
+
+ if (!rep->flow_cfg)
+ return -ENOMEM;
+
+ count = OTX2_DEFAULT_FLOWCOUNT;
+
+ rep->flow_cfg->flow_ent = kcalloc(count, sizeof(u16), GFP_KERNEL);
+ if (!rep->flow_cfg->flow_ent)
+ return -ENOMEM;
+
+ while (allocated < count) {
+ req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&priv->mbox);
+ if (!req)
+ goto exit;
+
+ req->hdr.pcifunc = rep->pcifunc;
+ req->contig = false;
+ req->ref_entry = 0;
+ req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ?
+ NPC_MAX_NONCONTIG_ENTRIES : count - allocated;
+
+ if (otx2_sync_mbox_msg(&priv->mbox))
+ goto exit;
+
+ rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp
+ (&priv->mbox.mbox, 0, &req->hdr);
+
+ for (ent = 0; ent < rsp->count; ent++)
+ rep->flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent];
+
+ allocated += rsp->count;
+
+ if (rsp->count != req->count)
+ break;
+ }
+exit:
+ /* Multiple MCAM entry alloc requests could result in non-sequential
+ * MCAM entries in the flow_ent[] array. Sort them in an ascending
+ * order, otherwise user installed ntuple filter index and MCAM entry
+ * index will not be in sync.
+ */
+ if (allocated)
+ sort(&rep->flow_cfg->flow_ent[0], allocated,
+ sizeof(rep->flow_cfg->flow_ent[0]), mcam_entry_cmp, NULL);
+
+ mutex_unlock(&priv->mbox.lock);
+
+ rep->flow_cfg->max_flows = allocated;
+
+ if (allocated) {
+ rep->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
+ rep->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
+ rep->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+ }
+
+ INIT_LIST_HEAD(&rep->flow_cfg->flow_list);
+ INIT_LIST_HEAD(&rep->flow_cfg->flow_list_tc);
+ return 0;
+}
+
+static int rvu_rep_setup_tc_cb(enum tc_setup_type type,
+ void *type_data, void *cb_priv)
+{
+ struct rep_dev *rep = cb_priv;
+ struct otx2_nic *priv = rep->mdev;
+
+ if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ return -EINVAL;
+
+ if (!(rep->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
+ rvu_rep_mcam_flow_init(rep);
+
+ priv->netdev = rep->netdev;
+ priv->flags = rep->flags;
+ priv->pcifunc = rep->pcifunc;
+ priv->flow_cfg = rep->flow_cfg;
+
+ switch (type) {
+ case TC_SETUP_CLSFLOWER:
+ return otx2_setup_tc_cls_flower(priv, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static LIST_HEAD(rvu_rep_block_cb_list);
+static int rvu_rep_setup_tc(struct net_device *netdev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct rvu_rep *rep = netdev_priv(netdev);
+
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ return flow_block_cb_setup_simple(type_data,
+ &rvu_rep_block_cb_list,
+ rvu_rep_setup_tc_cb,
+ rep, rep, true);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+rvu_rep_sp_stats64(const struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+ struct otx2_nic *priv = rep->mdev;
+ struct otx2_rcv_queue *rq;
+ struct otx2_snd_queue *sq;
+ u16 qidx = rep->rep_id;
+
+ otx2_update_rq_stats(priv, qidx);
+ rq = &priv->qset.rq[qidx];
+
+ otx2_update_sq_stats(priv, qidx);
+ sq = &priv->qset.sq[qidx];
+
+ stats->tx_bytes = sq->stats.bytes;
+ stats->tx_packets = sq->stats.pkts;
+ stats->rx_bytes = rq->stats.bytes;
+ stats->rx_packets = rq->stats.pkts;
+ return 0;
+}
+
+static bool
+rvu_rep_has_offload_stats(const struct net_device *dev, int attr_id)
+{
+ return attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT;
+}
+
+static int
+rvu_rep_get_offload_stats(int attr_id, const struct net_device *dev,
+ void *sp)
+{
+ if (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT)
+ return rvu_rep_sp_stats64(dev, (struct rtnl_link_stats64 *)sp);
+
+ return -EINVAL;
+}
+
+static int rvu_rep_dl_port_fn_hw_addr_get(struct devlink_port *port,
+ u8 *hw_addr, int *hw_addr_len,
+ struct netlink_ext_ack *extack)
+{
+ struct rep_dev *rep = container_of(port, struct rep_dev, dl_port);
+
+ ether_addr_copy(hw_addr, rep->mac);
+ *hw_addr_len = ETH_ALEN;
+ return 0;
+}
+
+static int rvu_rep_dl_port_fn_hw_addr_set(struct devlink_port *port,
+ const u8 *hw_addr, int hw_addr_len,
+ struct netlink_ext_ack *extack)
+{
+ struct rep_dev *rep = container_of(port, struct rep_dev, dl_port);
+ struct otx2_nic *priv = rep->mdev;
+ struct rep_event evt = {0};
+
+ eth_hw_addr_set(rep->netdev, hw_addr);
+ ether_addr_copy(rep->mac, hw_addr);
+
+ ether_addr_copy(evt.evt_data.mac, hw_addr);
+ evt.pcifunc = rep->pcifunc;
+ rvu_rep_notify_pfvf(priv, RVU_EVENT_MAC_ADDR_CHANGE, &evt);
+ return 0;
+}
+
+static const struct devlink_port_ops rvu_rep_dl_port_ops = {
+ .port_fn_hw_addr_get = rvu_rep_dl_port_fn_hw_addr_get,
+ .port_fn_hw_addr_set = rvu_rep_dl_port_fn_hw_addr_set,
+};
+
+static void
+rvu_rep_devlink_set_switch_id(struct otx2_nic *priv,
+ struct netdev_phys_item_id *ppid)
+{
+ struct pci_dev *pdev = priv->pdev;
+ u64 id;
+
+ id = pci_get_dsn(pdev);
+
+ ppid->id_len = sizeof(id);
+ put_unaligned_be64(id, &ppid->id);
+}
+
+static void rvu_rep_devlink_port_unregister(struct rep_dev *rep)
+{
+ devlink_port_unregister(&rep->dl_port);
+}
+
+static int rvu_rep_devlink_port_register(struct rep_dev *rep)
+{
+ struct devlink_port_attrs attrs = {};
+ struct otx2_nic *priv = rep->mdev;
+ struct devlink *dl = priv->dl->dl;
+ int err;
+
+ if (!(rep->pcifunc & RVU_PFVF_FUNC_MASK)) {
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+ attrs.phys.port_number = rvu_get_pf(rep->pcifunc);
+ } else {
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
+ attrs.pci_vf.pf = rvu_get_pf(rep->pcifunc);
+ attrs.pci_vf.vf = rep->pcifunc & RVU_PFVF_FUNC_MASK;
+ }
+
+ rvu_rep_devlink_set_switch_id(priv, &attrs.switch_id);
+ devlink_port_attrs_set(&rep->dl_port, &attrs);
+
+ err = devl_port_register_with_ops(dl, &rep->dl_port, rep->rep_id,
+ &rvu_rep_dl_port_ops);
+ if (err) {
+ dev_err(rep->mdev->dev, "devlink_port_register failed: %d\n",
+ err);
+ return err;
+ }
+ return 0;
+}
+
+static int rvu_rep_get_repid(struct otx2_nic *priv, u16 pcifunc)
+{
+ int rep_id;
+
+ for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++)
+ if (priv->rep_pf_map[rep_id] == pcifunc)
+ return rep_id;
+ return -EINVAL;
+}
+
+static int rvu_rep_notify_pfvf(struct otx2_nic *priv, u16 event,
+ struct rep_event *data)
+{
+ struct rep_event *req;
+
+ mutex_lock(&priv->mbox.lock);
+ req = otx2_mbox_alloc_msg_rep_event_notify(&priv->mbox);
+ if (!req) {
+ mutex_unlock(&priv->mbox.lock);
+ return -ENOMEM;
+ }
+ req->event = event;
+ req->pcifunc = data->pcifunc;
+
+ memcpy(&req->evt_data, &data->evt_data, sizeof(struct rep_evt_data));
+ otx2_sync_mbox_msg(&priv->mbox);
+ mutex_unlock(&priv->mbox.lock);
+ return 0;
+}
+
+static void rvu_rep_state_evt_handler(struct otx2_nic *priv,
+ struct rep_event *info)
+{
+ struct rep_dev *rep;
+ int rep_id;
+
+ rep_id = rvu_rep_get_repid(priv, info->pcifunc);
+ rep = priv->reps[rep_id];
+ if (info->evt_data.vf_state)
+ rep->flags |= RVU_REP_VF_INITIALIZED;
+ else
+ rep->flags &= ~RVU_REP_VF_INITIALIZED;
+}
+
+int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info)
+{
+ if (info->event & RVU_EVENT_PFVF_STATE)
+ rvu_rep_state_evt_handler(pf, info);
+ return 0;
+}
+
+static int rvu_rep_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+ struct otx2_nic *priv = rep->mdev;
+ struct rep_event evt = {0};
+
+ netdev_info(dev, "Changing MTU from %d to %d\n",
+ dev->mtu, new_mtu);
+ dev->mtu = new_mtu;
+
+ evt.evt_data.mtu = new_mtu;
+ evt.pcifunc = rep->pcifunc;
+ rvu_rep_notify_pfvf(priv, RVU_EVENT_MTU_CHANGE, &evt);
+ return 0;
+}
+
+static void rvu_rep_get_stats(struct work_struct *work)
+{
+ struct delayed_work *del_work = to_delayed_work(work);
+ struct nix_stats_req *req;
+ struct nix_stats_rsp *rsp;
+ struct rep_stats *stats;
+ struct otx2_nic *priv;
+ struct rep_dev *rep;
+ int err;
+
+ rep = container_of(del_work, struct rep_dev, stats_wrk);
+ priv = rep->mdev;
+
+ mutex_lock(&priv->mbox.lock);
+ req = otx2_mbox_alloc_msg_nix_lf_stats(&priv->mbox);
+ if (!req) {
+ mutex_unlock(&priv->mbox.lock);
+ return;
+ }
+ req->pcifunc = rep->pcifunc;
+ err = otx2_sync_mbox_msg_busy_poll(&priv->mbox);
+ if (err)
+ goto exit;
+
+ rsp = (struct nix_stats_rsp *)
+ otx2_mbox_get_rsp(&priv->mbox.mbox, 0, &req->hdr);
+
+ if (IS_ERR(rsp)) {
+ err = PTR_ERR(rsp);
+ goto exit;
+ }
+
+ stats = &rep->stats;
+ stats->rx_bytes = rsp->rx.octs;
+ stats->rx_frames = rsp->rx.ucast + rsp->rx.bcast +
+ rsp->rx.mcast;
+ stats->rx_drops = rsp->rx.drop;
+ stats->rx_mcast_frames = rsp->rx.mcast;
+ stats->tx_bytes = rsp->tx.octs;
+ stats->tx_frames = rsp->tx.ucast + rsp->tx.bcast + rsp->tx.mcast;
+ stats->tx_drops = rsp->tx.drop;
+exit:
+ mutex_unlock(&priv->mbox.lock);
+}
+
+static void rvu_rep_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+
+ if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ return;
+
+ stats->rx_packets = rep->stats.rx_frames;
+ stats->rx_bytes = rep->stats.rx_bytes;
+ stats->rx_dropped = rep->stats.rx_drops;
+ stats->multicast = rep->stats.rx_mcast_frames;
+
+ stats->tx_packets = rep->stats.tx_frames;
+ stats->tx_bytes = rep->stats.tx_bytes;
+ stats->tx_dropped = rep->stats.tx_drops;
+
+ schedule_delayed_work(&rep->stats_wrk, msecs_to_jiffies(100));
+}
+
+static int rvu_eswitch_config(struct otx2_nic *priv, u8 ena)
+{
+ struct esw_cfg_req *req;
+
+ mutex_lock(&priv->mbox.lock);
+ req = otx2_mbox_alloc_msg_esw_cfg(&priv->mbox);
+ if (!req) {
+ mutex_unlock(&priv->mbox.lock);
+ return -ENOMEM;
+ }
+ req->ena = ena;
+ otx2_sync_mbox_msg(&priv->mbox);
+ mutex_unlock(&priv->mbox.lock);
+ return 0;
+}
+
+static netdev_tx_t rvu_rep_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+ struct otx2_nic *pf = rep->mdev;
+ struct otx2_snd_queue *sq;
+ struct netdev_queue *txq;
+
+ sq = &pf->qset.sq[rep->rep_id];
+ txq = netdev_get_tx_queue(dev, 0);
+
+ if (!otx2_sq_append_skb(pf, txq, sq, skb, rep->rep_id)) {
+ netif_tx_stop_queue(txq);
+
+ /* Check again, in case SQBs got freed up */
+ smp_mb();
+ if (((sq->num_sqbs - *sq->aura_fc_addr) * sq->sqe_per_sqb)
+ > sq->sqe_thresh)
+ netif_tx_wake_queue(txq);
+
+ return NETDEV_TX_BUSY;
+ }
+ return NETDEV_TX_OK;
+}
+
+static int rvu_rep_open(struct net_device *dev)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+ struct otx2_nic *priv = rep->mdev;
+ struct rep_event evt = {0};
+
+ if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ return 0;
+
+ netif_carrier_on(dev);
+ netif_tx_start_all_queues(dev);
+
+ evt.event = RVU_EVENT_PORT_STATE;
+ evt.evt_data.port_state = 1;
+ evt.pcifunc = rep->pcifunc;
+ rvu_rep_notify_pfvf(priv, RVU_EVENT_PORT_STATE, &evt);
+ return 0;
+}
+
+static int rvu_rep_stop(struct net_device *dev)
+{
+ struct rep_dev *rep = netdev_priv(dev);
+ struct otx2_nic *priv = rep->mdev;
+ struct rep_event evt = {0};
+
+ if (!(rep->flags & RVU_REP_VF_INITIALIZED))
+ return 0;
+
+ netif_carrier_off(dev);
+ netif_tx_disable(dev);
+
+ evt.event = RVU_EVENT_PORT_STATE;
+ evt.pcifunc = rep->pcifunc;
+ rvu_rep_notify_pfvf(priv, RVU_EVENT_PORT_STATE, &evt);
+ return 0;
+}
+
+static const struct net_device_ops rvu_rep_netdev_ops = {
+ .ndo_open = rvu_rep_open,
+ .ndo_stop = rvu_rep_stop,
+ .ndo_start_xmit = rvu_rep_xmit,
+ .ndo_get_stats64 = rvu_rep_get_stats64,
+ .ndo_change_mtu = rvu_rep_change_mtu,
+ .ndo_has_offload_stats = rvu_rep_has_offload_stats,
+ .ndo_get_offload_stats = rvu_rep_get_offload_stats,
+ .ndo_setup_tc = rvu_rep_setup_tc,
+};
+
+static int rvu_rep_napi_init(struct otx2_nic *priv,
+ struct netlink_ext_ack *extack)
+{
+ struct otx2_qset *qset = &priv->qset;
+ struct otx2_cq_poll *cq_poll = NULL;
+ struct otx2_hw *hw = &priv->hw;
+ int err = 0, qidx, vec;
+ char *irq_name;
+
+ qset->napi = kcalloc(hw->cint_cnt, sizeof(*cq_poll), GFP_KERNEL);
+ if (!qset->napi)
+ return -ENOMEM;
+
+ /* Register NAPI handler */
+ for (qidx = 0; qidx < hw->cint_cnt; qidx++) {
+ cq_poll = &qset->napi[qidx];
+ cq_poll->cint_idx = qidx;
+ cq_poll->cq_ids[CQ_RX] =
+ (qidx < hw->rx_queues) ? qidx : CINT_INVALID_CQ;
+ cq_poll->cq_ids[CQ_TX] = (qidx < hw->tx_queues) ?
+ qidx + hw->rx_queues :
+ CINT_INVALID_CQ;
+ cq_poll->cq_ids[CQ_XDP] = CINT_INVALID_CQ;
+ cq_poll->cq_ids[CQ_QOS] = CINT_INVALID_CQ;
+
+ cq_poll->dev = (void *)priv;
+ netif_napi_add(priv->reps[qidx]->netdev, &cq_poll->napi,
+ otx2_napi_handler);
+ napi_enable(&cq_poll->napi);
+ }
+ /* Register CQ IRQ handlers */
+ vec = hw->nix_msixoff + NIX_LF_CINT_VEC_START;
+ for (qidx = 0; qidx < hw->cint_cnt; qidx++) {
+ irq_name = &hw->irq_name[vec * NAME_SIZE];
+
+ snprintf(irq_name, NAME_SIZE, "rep%d-rxtx-%d", qidx, qidx);
+
+ err = request_irq(pci_irq_vector(priv->pdev, vec),
+ otx2_cq_intr_handler, 0, irq_name,
+ &qset->napi[qidx]);
+ if (err) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "RVU REP IRQ registration failed for CQ%d",
+ qidx);
+ goto err_free_cints;
+ }
+ vec++;
+
+ /* Enable CQ IRQ */
+ otx2_write64(priv, NIX_LF_CINTX_INT(qidx), BIT_ULL(0));
+ otx2_write64(priv, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0));
+ }
+ priv->flags &= ~OTX2_FLAG_INTF_DOWN;
+ return 0;
+
+err_free_cints:
+ otx2_free_cints(priv, qidx);
+ otx2_disable_napi(priv);
+ return err;
+}
+
+static void rvu_rep_free_cq_rsrc(struct otx2_nic *priv)
+{
+ struct otx2_qset *qset = &priv->qset;
+ struct otx2_cq_poll *cq_poll = NULL;
+ int qidx, vec;
+
+ /* Cleanup CQ NAPI and IRQ */
+ vec = priv->hw.nix_msixoff + NIX_LF_CINT_VEC_START;
+ for (qidx = 0; qidx < priv->hw.cint_cnt; qidx++) {
+ /* Disable interrupt */
+ otx2_write64(priv, NIX_LF_CINTX_ENA_W1C(qidx), BIT_ULL(0));
+
+ synchronize_irq(pci_irq_vector(priv->pdev, vec));
+
+ cq_poll = &qset->napi[qidx];
+ napi_synchronize(&cq_poll->napi);
+ vec++;
+ }
+ otx2_free_cints(priv, priv->hw.cint_cnt);
+ otx2_disable_napi(priv);
+}
+
+static void rvu_rep_rsrc_free(struct otx2_nic *priv)
+{
+ struct otx2_qset *qset = &priv->qset;
+ struct delayed_work *work;
+ int wrk;
+
+ for (wrk = 0; wrk < priv->qset.cq_cnt; wrk++) {
+ work = &priv->refill_wrk[wrk].pool_refill_work;
+ cancel_delayed_work_sync(work);
+ }
+ devm_kfree(priv->dev, priv->refill_wrk);
+
+ otx2_free_hw_resources(priv);
+ otx2_free_queue_mem(qset);
+}
+
+static int rvu_rep_rsrc_init(struct otx2_nic *priv)
+{
+ struct otx2_qset *qset = &priv->qset;
+ int err;
+
+ err = otx2_alloc_queue_mem(priv);
+ if (err)
+ return err;
+
+ priv->hw.max_mtu = otx2_get_max_mtu(priv);
+ priv->tx_max_pktlen = priv->hw.max_mtu + OTX2_ETH_HLEN;
+ priv->rbsize = ALIGN(priv->hw.rbuf_len, OTX2_ALIGN) + OTX2_HEAD_ROOM;
+
+ err = otx2_init_hw_resources(priv);
+ if (err)
+ goto err_free_rsrc;
+
+ /* Set maximum frame size allowed in HW */
+ err = otx2_hw_set_mtu(priv, priv->hw.max_mtu);
+ if (err) {
+ dev_err(priv->dev, "Failed to set HW MTU\n");
+ goto err_free_rsrc;
+ }
+ return 0;
+
+err_free_rsrc:
+ otx2_free_hw_resources(priv);
+ otx2_free_queue_mem(qset);
+ return err;
+}
+
+void rvu_rep_destroy(struct otx2_nic *priv)
+{
+ struct rep_dev *rep;
+ int rep_id;
+
+ rvu_eswitch_config(priv, false);
+ priv->flags |= OTX2_FLAG_INTF_DOWN;
+ rvu_rep_free_cq_rsrc(priv);
+ for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
+ rep = priv->reps[rep_id];
+ unregister_netdev(rep->netdev);
+ rvu_rep_devlink_port_unregister(rep);
+ free_netdev(rep->netdev);
+ kfree(rep->flow_cfg);
+ }
+ kfree(priv->reps);
+ rvu_rep_rsrc_free(priv);
+}
+
+int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack)
+{
+ int rep_cnt = priv->rep_cnt;
+ struct net_device *ndev;
+ struct rep_dev *rep;
+ int rep_id, err;
+ u16 pcifunc;
+
+ err = rvu_rep_rsrc_init(priv);
+ if (err)
+ return -ENOMEM;
+
+ priv->reps = kcalloc(rep_cnt, sizeof(struct rep_dev *), GFP_KERNEL);
+ if (!priv->reps)
+ return -ENOMEM;
+
+ for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
+ ndev = alloc_etherdev(sizeof(*rep));
+ if (!ndev) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "PFVF representor:%d creation failed",
+ rep_id);
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ rep = netdev_priv(ndev);
+ priv->reps[rep_id] = rep;
+ rep->mdev = priv;
+ rep->netdev = ndev;
+ rep->rep_id = rep_id;
+
+ ndev->min_mtu = OTX2_MIN_MTU;
+ ndev->max_mtu = priv->hw.max_mtu;
+ ndev->netdev_ops = &rvu_rep_netdev_ops;
+ pcifunc = priv->rep_pf_map[rep_id];
+ rep->pcifunc = pcifunc;
+
+ snprintf(ndev->name, sizeof(ndev->name), "Rpf%dvf%d",
+ rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
+
+ ndev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_RXHASH |
+ NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6);
+
+ ndev->hw_features |= NETIF_F_HW_TC;
+ ndev->features |= ndev->hw_features;
+ eth_hw_addr_random(ndev);
+ err = rvu_rep_devlink_port_register(rep);
+ if (err)
+ goto exit;
+
+ SET_NETDEV_DEVLINK_PORT(ndev, &rep->dl_port);
+ err = register_netdev(ndev);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "PFVF representor registration failed");
+ free_netdev(ndev);
+ goto exit;
+ }
+
+ INIT_DELAYED_WORK(&rep->stats_wrk, rvu_rep_get_stats);
+ }
+ err = rvu_rep_napi_init(priv, extack);
+ if (err)
+ goto exit;
+
+ rvu_eswitch_config(priv, true);
+ return 0;
+exit:
+ while (--rep_id >= 0) {
+ rep = priv->reps[rep_id];
+ unregister_netdev(rep->netdev);
+ rvu_rep_devlink_port_unregister(rep);
+ free_netdev(rep->netdev);
+ }
+ kfree(priv->reps);
+ rvu_rep_rsrc_free(priv);
+ return err;
+}
+
+static int rvu_get_rep_cnt(struct otx2_nic *priv)
+{
+ struct get_rep_cnt_rsp *rsp;
+ struct mbox_msghdr *msghdr;
+ struct msg_req *req;
+ int err, rep;
+
+ mutex_lock(&priv->mbox.lock);
+ req = otx2_mbox_alloc_msg_get_rep_cnt(&priv->mbox);
+ if (!req) {
+ mutex_unlock(&priv->mbox.lock);
+ return -ENOMEM;
+ }
+ err = otx2_sync_mbox_msg(&priv->mbox);
+ if (err)
+ goto exit;
+
+ msghdr = otx2_mbox_get_rsp(&priv->mbox.mbox, 0, &req->hdr);
+ if (IS_ERR(msghdr)) {
+ err = PTR_ERR(msghdr);
+ goto exit;
+ }
+
+ rsp = (struct get_rep_cnt_rsp *)msghdr;
+ priv->hw.tx_queues = rsp->rep_cnt;
+ priv->hw.rx_queues = rsp->rep_cnt;
+ priv->rep_cnt = rsp->rep_cnt;
+ for (rep = 0; rep < priv->rep_cnt; rep++)
+ priv->rep_pf_map[rep] = rsp->rep_pf_map[rep];
+
+exit:
+ mutex_unlock(&priv->mbox.lock);
+ return err;
+}
+
+static int rvu_rep_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct otx2_nic *priv;
+ struct otx2_hw *hw;
+ int err;
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ dev_err(dev, "PCI request regions failed 0x%x\n", err);
+ return err;
+ }
+
+ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+ if (err) {
+ dev_err(dev, "DMA mask config failed, abort\n");
+ goto err_release_regions;
+ }
+
+ pci_set_master(pdev);
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ err = -ENOMEM;
+ goto err_release_regions;
+ }
+
+ pci_set_drvdata(pdev, priv);
+ priv->pdev = pdev;
+ priv->dev = dev;
+ priv->flags |= OTX2_FLAG_INTF_DOWN;
+ priv->flags |= OTX2_FLAG_REP_MODE_ENABLED;
+
+ hw = &priv->hw;
+ hw->pdev = pdev;
+ hw->max_queues = OTX2_MAX_CQ_CNT;
+ hw->rbuf_len = OTX2_DEFAULT_RBUF_LEN;
+ hw->xqe_size = 128;
+
+ err = otx2_init_rsrc(pdev, priv);
+ if (err)
+ goto err_release_regions;
+
+ priv->iommu_domain = iommu_get_domain_for_dev(dev);
+
+ err = rvu_get_rep_cnt(priv);
+ if (err)
+ goto err_detach_rsrc;
+
+ err = otx2_register_dl(priv);
+ if (err)
+ goto err_detach_rsrc;
+
+ return 0;
+
+err_detach_rsrc:
+ if (priv->hw.lmt_info)
+ free_percpu(priv->hw.lmt_info);
+ if (test_bit(CN10K_LMTST, &priv->hw.cap_flag))
+ qmem_free(priv->dev, priv->dync_lmt);
+ otx2_detach_resources(&priv->mbox);
+ otx2_disable_mbox_intr(priv);
+ otx2_pfaf_mbox_destroy(priv);
+ pci_free_irq_vectors(pdev);
+err_release_regions:
+ pci_set_drvdata(pdev, NULL);
+ pci_release_regions(pdev);
+ return err;
+}
+
+static void rvu_rep_remove(struct pci_dev *pdev)
+{
+ struct otx2_nic *priv = pci_get_drvdata(pdev);
+
+ otx2_unregister_dl(priv);
+ if (!(priv->flags & OTX2_FLAG_INTF_DOWN))
+ rvu_rep_destroy(priv);
+ otx2_detach_resources(&priv->mbox);
+ if (priv->hw.lmt_info)
+ free_percpu(priv->hw.lmt_info);
+ if (test_bit(CN10K_LMTST, &priv->hw.cap_flag))
+ qmem_free(priv->dev, priv->dync_lmt);
+ otx2_disable_mbox_intr(priv);
+ otx2_pfaf_mbox_destroy(priv);
+ pci_free_irq_vectors(priv->pdev);
+ pci_set_drvdata(pdev, NULL);
+ pci_release_regions(pdev);
+}
+
+static struct pci_driver rvu_rep_driver = {
+ .name = DRV_NAME,
+ .id_table = rvu_rep_id_table,
+ .probe = rvu_rep_probe,
+ .remove = rvu_rep_remove,
+ .shutdown = rvu_rep_remove,
+};
+
+static int __init rvu_rep_init_module(void)
+{
+ return pci_register_driver(&rvu_rep_driver);
+}
+
+static void __exit rvu_rep_cleanup_module(void)
+{
+ pci_unregister_driver(&rvu_rep_driver);
+}
+
+module_init(rvu_rep_init_module);
+module_exit(rvu_rep_cleanup_module);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
new file mode 100644
index 000000000000..38446b3e4f13
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell RVU REPRESENTOR driver
+ *
+ * Copyright (C) 2024 Marvell.
+ *
+ */
+
+#ifndef REP_H
+#define REP_H
+
+#include <linux/pci.h>
+
+#include "otx2_reg.h"
+#include "otx2_txrx.h"
+#include "otx2_common.h"
+
+#define PCI_DEVID_RVU_REP 0xA0E0
+
+#define RVU_MAX_REP OTX2_MAX_CQ_CNT
+
+struct rep_stats {
+ u64 rx_bytes;
+ u64 rx_frames;
+ u64 rx_drops;
+ u64 rx_mcast_frames;
+
+ u64 tx_bytes;
+ u64 tx_frames;
+ u64 tx_drops;
+};
+
+struct rep_dev {
+ struct otx2_nic *mdev;
+ struct net_device *netdev;
+ struct rep_stats stats;
+ struct delayed_work stats_wrk;
+ struct devlink_port dl_port;
+ struct otx2_flow_config *flow_cfg;
+#define RVU_REP_VF_INITIALIZED BIT_ULL(0)
+ u64 flags;
+ u16 rep_id;
+ u16 pcifunc;
+ u8 mac[ETH_ALEN];
+};
+
+static inline bool otx2_rep_dev(struct pci_dev *pdev)
+{
+ return pdev->device == PCI_DEVID_RVU_REP;
+}
+
+int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack);
+void rvu_rep_destroy(struct otx2_nic *priv);
+int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info);
+#endif /* REP_H */
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index fcfb34561882..25bf6ec44289 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -484,8 +484,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(skge_stats); i++)
- memcpy(data + i * ETH_GSTRING_LEN,
- skge_stats[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, skge_stats[i].name);
break;
}
}
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index a7a16eac1891..3914cd9210d4 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -3800,8 +3800,7 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(sky2_stats); i++)
- memcpy(data + i * ETH_GSTRING_LEN,
- sky2_stats[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, sky2_stats[i].name);
break;
}
}
diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c
index f463a505f5ba..6c683a12d5aa 100644
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
@@ -752,11 +752,9 @@ struct airoha_tx_irq_queue {
struct airoha_qdma *qdma;
struct napi_struct napi;
- u32 *q;
int size;
- int queued;
- u16 head;
+ u32 *q;
};
struct airoha_hw_stats {
@@ -1656,30 +1654,38 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
+ int id, done = 0, irq_queued;
struct airoha_qdma *qdma;
struct airoha_eth *eth;
- int id, done = 0;
+ u32 status, head;
irq_q = container_of(napi, struct airoha_tx_irq_queue, napi);
qdma = irq_q->qdma;
id = irq_q - &qdma->q_tx_irq[0];
eth = qdma->eth;
- while (irq_q->queued > 0 && done < budget) {
- u32 qid, last, val = irq_q->q[irq_q->head];
+ status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(id));
+ head = FIELD_GET(IRQ_HEAD_IDX_MASK, status);
+ head = head % irq_q->size;
+ irq_queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status);
+
+ while (irq_queued > 0 && done < budget) {
+ u32 qid, val = irq_q->q[head];
+ struct airoha_qdma_desc *desc;
+ struct airoha_queue_entry *e;
struct airoha_queue *q;
+ u32 index, desc_ctrl;
+ struct sk_buff *skb;
if (val == 0xff)
break;
- irq_q->q[irq_q->head] = 0xff; /* mark as done */
- irq_q->head = (irq_q->head + 1) % irq_q->size;
- irq_q->queued--;
+ irq_q->q[head] = 0xff; /* mark as done */
+ head = (head + 1) % irq_q->size;
+ irq_queued--;
done++;
- last = FIELD_GET(IRQ_DESC_IDX_MASK, val);
qid = FIELD_GET(IRQ_RING_IDX_MASK, val);
-
if (qid >= ARRAY_SIZE(qdma->q_tx))
continue;
@@ -1687,46 +1693,53 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
if (!q->ndesc)
continue;
+ index = FIELD_GET(IRQ_DESC_IDX_MASK, val);
+ if (index >= q->ndesc)
+ continue;
+
spin_lock_bh(&q->lock);
- while (q->queued > 0) {
- struct airoha_qdma_desc *desc = &q->desc[q->tail];
- struct airoha_queue_entry *e = &q->entry[q->tail];
- u32 desc_ctrl = le32_to_cpu(desc->ctrl);
- struct sk_buff *skb = e->skb;
- u16 index = q->tail;
+ if (!q->queued)
+ goto unlock;
- if (!(desc_ctrl & QDMA_DESC_DONE_MASK) &&
- !(desc_ctrl & QDMA_DESC_DROP_MASK))
- break;
+ desc = &q->desc[index];
+ desc_ctrl = le32_to_cpu(desc->ctrl);
- q->tail = (q->tail + 1) % q->ndesc;
- q->queued--;
+ if (!(desc_ctrl & QDMA_DESC_DONE_MASK) &&
+ !(desc_ctrl & QDMA_DESC_DROP_MASK))
+ goto unlock;
- dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
- DMA_TO_DEVICE);
+ e = &q->entry[index];
+ skb = e->skb;
- WRITE_ONCE(desc->msg0, 0);
- WRITE_ONCE(desc->msg1, 0);
+ dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ memset(e, 0, sizeof(*e));
+ WRITE_ONCE(desc->msg0, 0);
+ WRITE_ONCE(desc->msg1, 0);
+ q->queued--;
- if (skb) {
- u16 queue = skb_get_queue_mapping(skb);
- struct netdev_queue *txq;
+ /* completion ring can report out-of-order indexes if hw QoS
+ * is enabled and packets with different priority are queued
+ * to same DMA ring. Take into account possible out-of-order
+ * reports incrementing DMA ring tail pointer
+ */
+ while (q->tail != q->head && !q->entry[q->tail].dma_addr)
+ q->tail = (q->tail + 1) % q->ndesc;
- txq = netdev_get_tx_queue(skb->dev, queue);
- netdev_tx_completed_queue(txq, 1, skb->len);
- if (netif_tx_queue_stopped(txq) &&
- q->ndesc - q->queued >= q->free_thr)
- netif_tx_wake_queue(txq);
+ if (skb) {
+ u16 queue = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq;
- dev_kfree_skb_any(skb);
- e->skb = NULL;
- }
+ txq = netdev_get_tx_queue(skb->dev, queue);
+ netdev_tx_completed_queue(txq, 1, skb->len);
+ if (netif_tx_queue_stopped(txq) &&
+ q->ndesc - q->queued >= q->free_thr)
+ netif_tx_wake_queue(txq);
- if (index == last)
- break;
+ dev_kfree_skb_any(skb);
}
-
+unlock:
spin_unlock_bh(&q->lock);
}
@@ -2026,20 +2039,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *dev_instance)
if (intr[0] & INT_TX_MASK) {
for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) {
- struct airoha_tx_irq_queue *irq_q = &qdma->q_tx_irq[i];
- u32 status, head;
-
if (!(intr[0] & TX_DONE_INT_MASK(i)))
continue;
airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX0,
TX_DONE_INT_MASK(i));
-
- status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(i));
- head = FIELD_GET(IRQ_HEAD_IDX_MASK, status);
- irq_q->head = head % irq_q->size;
- irq_q->queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status);
-
napi_schedule(&qdma->q_tx_irq[i].napi);
}
}
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index f01ceee5f02d..53485142938c 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2227,7 +2227,7 @@ rx_done:
eth->rx_bytes += bytes;
dim_update_sample(eth->rx_events, eth->rx_packets, eth->rx_bytes,
&dim_sample);
- net_dim(&eth->rx_dim, dim_sample);
+ net_dim(&eth->rx_dim, &dim_sample);
if (xdp_flush)
xdp_do_flush();
@@ -2377,7 +2377,7 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)
dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes,
&dim_sample);
- net_dim(&eth->tx_dim, dim_sample);
+ net_dim(&eth->tx_dim, &dim_sample);
if (mtk_queue_stopped(eth) &&
(atomic_read(&ring->free_count) > ring->thresh))
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
index 87a67fa3868d..c01b1e8428f6 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
@@ -91,8 +91,8 @@ enum mtk_wed_dummy_cr_idx {
#define MT7981_FIRMWARE_WO "mediatek/mt7981_wo.bin"
#define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin"
#define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin"
-#define MT7988_FIRMWARE_WO0 "mediatek/mt7988_wo_0.bin"
-#define MT7988_FIRMWARE_WO1 "mediatek/mt7988_wo_1.bin"
+#define MT7988_FIRMWARE_WO0 "mediatek/mt7988/mt7988_wo_0.bin"
+#define MT7988_FIRMWARE_WO1 "mediatek/mt7988/mt7988_wo_1.bin"
#define MTK_WO_MCU_CFG_LS_BASE 0
#define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 5912f7e614f9..be3d0876c521 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -109,35 +109,48 @@ mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/ktls_stats.o \
en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \
en_accel/ktls_tx.o en_accel/ktls_rx.o
-mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \
- steering/dr_matcher.o steering/dr_rule.o \
- steering/dr_icm_pool.o steering/dr_buddy.o \
- steering/dr_ste.o steering/dr_send.o \
- steering/dr_ste_v0.o steering/dr_ste_v1.o \
- steering/dr_ste_v2.o \
- steering/dr_cmd.o steering/dr_fw.o \
- steering/dr_action.o steering/fs_dr.o \
- steering/dr_definer.o steering/dr_ptrn.o \
- steering/dr_arg.o steering/dr_dbg.o lib/smfs.o
+#
+# SW Steering
+#
+mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/sws/dr_domain.o \
+ steering/sws/dr_table.o \
+ steering/sws/dr_matcher.o \
+ steering/sws/dr_rule.o \
+ steering/sws/dr_icm_pool.o \
+ steering/sws/dr_buddy.o \
+ steering/sws/dr_ste.o \
+ steering/sws/dr_send.o \
+ steering/sws/dr_ste_v0.o \
+ steering/sws/dr_ste_v1.o \
+ steering/sws/dr_ste_v2.o \
+ steering/sws/dr_cmd.o \
+ steering/sws/dr_fw.o \
+ steering/sws/dr_action.o \
+ steering/sws/dr_definer.o \
+ steering/sws/dr_ptrn.o \
+ steering/sws/dr_arg.o \
+ steering/sws/dr_dbg.o \
+ steering/sws/fs_dr.o \
+ lib/smfs.o
#
# HW Steering
#
-mlx5_core-$(CONFIG_MLX5_HW_STEERING) += steering/hws/mlx5hws_cmd.o \
- steering/hws/mlx5hws_context.o \
- steering/hws/mlx5hws_pat_arg.o \
- steering/hws/mlx5hws_buddy.o \
- steering/hws/mlx5hws_pool.o \
- steering/hws/mlx5hws_table.o \
- steering/hws/mlx5hws_action.o \
- steering/hws/mlx5hws_rule.o \
- steering/hws/mlx5hws_matcher.o \
- steering/hws/mlx5hws_send.o \
- steering/hws/mlx5hws_definer.o \
- steering/hws/mlx5hws_bwc.o \
- steering/hws/mlx5hws_debug.o \
- steering/hws/mlx5hws_vport.o \
- steering/hws/mlx5hws_bwc_complex.o
+mlx5_core-$(CONFIG_MLX5_HW_STEERING) += steering/hws/cmd.o \
+ steering/hws/context.o \
+ steering/hws/pat_arg.o \
+ steering/hws/buddy.o \
+ steering/hws/pool.o \
+ steering/hws/table.o \
+ steering/hws/action.o \
+ steering/hws/rule.o \
+ steering/hws/matcher.o \
+ steering/hws/send.o \
+ steering/hws/definer.o \
+ steering/hws/bwc.o \
+ steering/hws/debug.o \
+ steering/hws/vport.o \
+ steering/hws/bwc_complex.o
#
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
index 4caa1b6f40ba..1fd403713baf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c
@@ -71,6 +71,7 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
{
unsigned long flags;
struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
+ bool schedule_tasklet = false;
spin_lock_irqsave(&tasklet_ctx->lock, flags);
/* When migrating CQs between EQs will be implemented, please note
@@ -80,9 +81,19 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq,
*/
if (list_empty_careful(&cq->tasklet_ctx.list)) {
mlx5_cq_hold(cq);
+ /* If the tasklet CQ work list isn't empty, mlx5_cq_tasklet_cb()
+ * is scheduled/running and hasn't processed the list yet, so it
+ * will see this added CQ when it runs. If the list is empty,
+ * the tasklet needs to be scheduled to pick up the CQ. The
+ * spinlock avoids any race with the tasklet accessing the list.
+ */
+ schedule_tasklet = list_empty(&tasklet_ctx->list);
list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
}
spin_unlock_irqrestore(&tasklet_ctx->lock, flags);
+
+ if (schedule_tasklet)
+ tasklet_schedule(&tasklet_ctx->task);
}
/* Callers must verify outbox status in case of err */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
index 904e08de852e..31142f6cc372 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
@@ -166,9 +166,90 @@ static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll,
return 0;
}
+enum {
+ MLX5_DPLL_SSM_CODE_PRC = 0b0010,
+ MLX5_DPLL_SSM_CODE_SSU_A = 0b0100,
+ MLX5_DPLL_SSM_CODE_SSU_B = 0b1000,
+ MLX5_DPLL_SSM_CODE_EEC1 = 0b1011,
+ MLX5_DPLL_SSM_CODE_PRTC = 0b0010,
+ MLX5_DPLL_SSM_CODE_EPRTC = 0b0010,
+ MLX5_DPLL_SSM_CODE_EEEC = 0b1011,
+ MLX5_DPLL_SSM_CODE_EPRC = 0b0010,
+};
+
+enum {
+ MLX5_DPLL_ENHANCED_SSM_CODE_PRC = 0xff,
+ MLX5_DPLL_ENHANCED_SSM_CODE_SSU_A = 0xff,
+ MLX5_DPLL_ENHANCED_SSM_CODE_SSU_B = 0xff,
+ MLX5_DPLL_ENHANCED_SSM_CODE_EEC1 = 0xff,
+ MLX5_DPLL_ENHANCED_SSM_CODE_PRTC = 0x20,
+ MLX5_DPLL_ENHANCED_SSM_CODE_EPRTC = 0x21,
+ MLX5_DPLL_ENHANCED_SSM_CODE_EEEC = 0x22,
+ MLX5_DPLL_ENHANCED_SSM_CODE_EPRC = 0x23,
+};
+
+#define __MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code) \
+ ((ssm_code) | ((enhanced_ssm_code) << 8))
+
+#define MLX5_DPLL_SSM_COMBINED_CODE(type) \
+ __MLX5_DPLL_SSM_COMBINED_CODE(MLX5_DPLL_SSM_CODE_##type, \
+ MLX5_DPLL_ENHANCED_SSM_CODE_##type)
+
+static int mlx5_dpll_clock_quality_level_get(const struct dpll_device *dpll,
+ void *priv, unsigned long *qls,
+ struct netlink_ext_ack *extack)
+{
+ u8 network_option, ssm_code, enhanced_ssm_code;
+ u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {};
+ u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {};
+ struct mlx5_dpll *mdpll = priv;
+ int err;
+
+ err = mlx5_core_access_reg(mdpll->mdev, in, sizeof(in),
+ out, sizeof(out), MLX5_REG_MSECQ, 0, 0);
+ if (err)
+ return err;
+ network_option = MLX5_GET(msecq_reg, out, network_option);
+ if (network_option != 1)
+ goto errout;
+ ssm_code = MLX5_GET(msecq_reg, out, local_ssm_code);
+ enhanced_ssm_code = MLX5_GET(msecq_reg, out, local_enhanced_ssm_code);
+
+ switch (__MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code)) {
+ case MLX5_DPLL_SSM_COMBINED_CODE(PRC):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(SSU_A):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(SSU_B):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(EEC1):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(PRTC):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(EPRTC):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(EEEC):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC, qls);
+ return 0;
+ case MLX5_DPLL_SSM_COMBINED_CODE(EPRC):
+ __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC, qls);
+ return 0;
+ }
+errout:
+ NL_SET_ERR_MSG_MOD(extack, "Invalid clock quality level obtained from firmware\n");
+ return -EINVAL;
+}
+
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,
+ .clock_quality_level_get = mlx5_dpll_clock_quality_level_get,
};
static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 57b7298a0e79..979fc56205e1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -83,6 +83,7 @@ struct page_pool;
#define MLX5E_SHAMPO_LOG_HEADER_ENTRY_SIZE (8)
#define MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE (9)
#define MLX5E_SHAMPO_WQ_HEADER_PER_PAGE (PAGE_SIZE >> MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE)
+#define MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE (PAGE_SHIFT - MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE)
#define MLX5E_SHAMPO_WQ_BASE_HEAD_ENTRY_SIZE (64)
#define MLX5E_SHAMPO_WQ_RESRV_SIZE (64 * 1024)
#define MLX5E_SHAMPO_WQ_BASE_RESRV_SIZE (4096)
@@ -624,16 +625,14 @@ struct mlx5e_dma_info {
struct mlx5e_shampo_hd {
u32 mkey;
- struct mlx5e_dma_info *info;
struct mlx5e_frag_page *pages;
- u16 curr_page_index;
u32 hd_per_wq;
u16 hd_per_wqe;
+ u16 pages_per_wq;
unsigned long *bitmap;
u16 pi;
u16 ci;
__be32 key;
- u64 last_addr;
};
struct mlx5e_hw_gro_data {
@@ -755,7 +754,7 @@ struct mlx5e_channel {
u8 lag_port;
/* XDP_REDIRECT */
- struct mlx5e_xdpsq xdpsq;
+ struct mlx5e_xdpsq *xdpsq;
/* AF_XDP zero-copy */
struct mlx5e_rq xskrq;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
index 4877a9d86807..a84ebac2f011 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
@@ -866,7 +866,7 @@ mlx5_tc_ct_entry_add_rule(struct mlx5_tc_ct_priv *ct_priv,
return 0;
err_rule:
- mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, zone_rule->mh);
+ mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, attr, zone_rule->mh);
mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id);
err_mod_hdr:
kfree(attr);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index 4610621a340e..94b291662087 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -865,7 +865,7 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
if (unlikely(sq_num >= priv->channels.num))
return -ENXIO;
- sq = &priv->channels.c[sq_num]->xdpsq;
+ sq = priv->channels.c[sq_num]->xdpsq;
for (i = 0; i < n; i++) {
struct mlx5e_xmit_data_frags xdptxdf = {};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
index d61be26a4df1..3db31cc10719 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
@@ -660,7 +660,7 @@ tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
while (remaining > 0) {
skb_frag_t *frag = &record->frags[i];
- get_page(skb_frag_page(frag));
+ page_ref_inc(skb_frag_page(frag));
remaining -= skb_frag_size(frag);
info->frags[i++] = *frag;
}
@@ -763,7 +763,7 @@ void mlx5e_ktls_tx_handle_resync_dump_comp(struct mlx5e_txqsq *sq,
stats = sq->stats;
mlx5e_tx_dma_unmap(sq->pdev, dma);
- put_page(wi->resync_dump_frag_page);
+ page_ref_dec(wi->resync_dump_frag_page);
stats->tls_dump_packets++;
stats->tls_dump_bytes += wi->num_bytes;
}
@@ -816,12 +816,12 @@ mlx5e_ktls_tx_handle_ooo(struct mlx5e_ktls_offload_context_tx *priv_tx,
err_out:
for (; i < info.nr_frags; i++)
- /* The put_page() here undoes the page ref obtained in tx_sync_info_get().
+ /* The page_ref_dec() here undoes the page ref obtained in tx_sync_info_get().
* Page refs obtained for the DUMP WQEs above (by page_ref_add) will be
* released only upon their completions (or in mlx5e_free_txqsq_descs,
* if channel closes).
*/
- put_page(skb_frag_page(&info.frags[i]));
+ page_ref_dec(skb_frag_page(&info.frags[i]));
return MLX5E_KTLS_SYNC_FAIL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 1966736f98b4..cae39198b4db 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -406,6 +406,9 @@ int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv,
unlock:
mutex_unlock(&priv->state_lock);
+ if (!err)
+ netdev_update_features(priv->netdev);
+
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index ce94859014f8..d0b80b520397 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -350,19 +350,15 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node)
shampo->bitmap = bitmap_zalloc_node(shampo->hd_per_wq, GFP_KERNEL,
node);
- shampo->info = kvzalloc_node(array_size(shampo->hd_per_wq,
- sizeof(*shampo->info)),
- GFP_KERNEL, node);
shampo->pages = kvzalloc_node(array_size(shampo->hd_per_wq,
sizeof(*shampo->pages)),
GFP_KERNEL, node);
- if (!shampo->bitmap || !shampo->info || !shampo->pages)
+ if (!shampo->bitmap || !shampo->pages)
goto err_nomem;
return 0;
err_nomem:
- kvfree(shampo->info);
kvfree(shampo->bitmap);
kvfree(shampo->pages);
@@ -372,7 +368,6 @@ err_nomem:
static void mlx5e_rq_shampo_hd_info_free(struct mlx5e_rq *rq)
{
kvfree(rq->mpwqe.shampo->bitmap);
- kvfree(rq->mpwqe.shampo->info);
kvfree(rq->mpwqe.shampo->pages);
}
@@ -767,8 +762,6 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
u32 *pool_size,
int node)
{
- void *wqc = MLX5_ADDR_OF(rqc, rqp->rqc, wq);
- int wq_size;
int err;
if (!test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state))
@@ -793,9 +786,9 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
cpu_to_be32(rq->mpwqe.shampo->mkey);
rq->mpwqe.shampo->hd_per_wqe =
mlx5e_shampo_hd_per_wqe(mdev, params, rqp);
- wq_size = BIT(MLX5_GET(wq, wqc, log_wq_sz));
- *pool_size += (rq->mpwqe.shampo->hd_per_wqe * wq_size) /
- MLX5E_SHAMPO_WQ_HEADER_PER_PAGE;
+ rq->mpwqe.shampo->pages_per_wq =
+ rq->mpwqe.shampo->hd_per_wq / MLX5E_SHAMPO_WQ_HEADER_PER_PAGE;
+ *pool_size += rq->mpwqe.shampo->pages_per_wq;
return 0;
err_hw_gro_data:
@@ -1126,7 +1119,7 @@ static void mlx5e_flush_rq_cq(struct mlx5e_rq *rq)
struct mlx5_cqe64 *cqe;
if (test_bit(MLX5E_RQ_STATE_MINI_CQE_ENHANCED, &rq->state)) {
- while ((cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq)))
+ while ((cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq)))
mlx5_cqwq_pop(cqwq);
} else {
while ((cqe = mlx5_cqwq_get_cqe(cqwq)))
@@ -2086,6 +2079,44 @@ void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
mlx5e_free_xdpsq(sq);
}
+static struct mlx5e_xdpsq *mlx5e_open_xdpredirect_sq(struct mlx5e_channel *c,
+ struct mlx5e_params *params,
+ struct mlx5e_channel_param *cparam,
+ struct mlx5e_create_cq_param *ccp)
+{
+ struct mlx5e_xdpsq *xdpsq;
+ int err;
+
+ xdpsq = kvzalloc_node(sizeof(*xdpsq), GFP_KERNEL, c->cpu);
+ if (!xdpsq)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation,
+ &cparam->xdp_sq.cqp, ccp, &xdpsq->cq);
+ if (err)
+ goto err_free_xdpsq;
+
+ err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, xdpsq, true);
+ if (err)
+ goto err_close_xdpsq_cq;
+
+ return xdpsq;
+
+err_close_xdpsq_cq:
+ mlx5e_close_cq(&xdpsq->cq);
+err_free_xdpsq:
+ kvfree(xdpsq);
+
+ return ERR_PTR(err);
+}
+
+static void mlx5e_close_xdpredirect_sq(struct mlx5e_xdpsq *xdpsq)
+{
+ mlx5e_close_xdpsq(xdpsq);
+ mlx5e_close_cq(&xdpsq->cq);
+ kvfree(xdpsq);
+}
+
static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
struct net_device *netdev,
struct workqueue_struct *workqueue,
@@ -2476,6 +2507,7 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
struct mlx5e_params *params,
struct mlx5e_channel_param *cparam)
{
+ const struct net_device_ops *netdev_ops = c->netdev->netdev_ops;
struct dim_cq_moder icocq_moder = {0, 0};
struct mlx5e_create_cq_param ccp;
int err;
@@ -2496,15 +2528,18 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
if (err)
goto err_close_icosq_cq;
- 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;
+ if (netdev_ops->ndo_xdp_xmit) {
+ c->xdpsq = mlx5e_open_xdpredirect_sq(c, params, cparam, &ccp);
+ if (IS_ERR(c->xdpsq)) {
+ err = PTR_ERR(c->xdpsq);
+ goto err_close_tx_cqs;
+ }
+ }
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;
+ goto err_close_xdpredirect_sq;
err = c->xdp ? mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp,
&ccp, &c->rq_xdpsq.cq) : 0;
@@ -2516,7 +2551,7 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
err = mlx5e_open_icosq(c, params, &cparam->async_icosq, &c->async_icosq,
mlx5e_async_icosq_err_cqe_work);
if (err)
- goto err_close_xdpsq_cq;
+ goto err_close_rq_xdpsq_cq;
mutex_init(&c->icosq_recovery_lock);
@@ -2540,16 +2575,8 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
goto err_close_rq;
}
- err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, &c->xdpsq, true);
- if (err)
- goto err_close_xdp_sq;
-
return 0;
-err_close_xdp_sq:
- if (c->xdp)
- mlx5e_close_xdpsq(&c->rq_xdpsq);
-
err_close_rq:
mlx5e_close_rq(&c->rq);
@@ -2562,15 +2589,16 @@ err_close_icosq:
err_close_async_icosq:
mlx5e_close_icosq(&c->async_icosq);
-err_close_xdpsq_cq:
+err_close_rq_xdpsq_cq:
if (c->xdp)
mlx5e_close_cq(&c->rq_xdpsq.cq);
err_close_rx_cq:
mlx5e_close_cq(&c->rq.cq);
-err_close_xdp_tx_cqs:
- mlx5e_close_cq(&c->xdpsq.cq);
+err_close_xdpredirect_sq:
+ if (c->xdpsq)
+ mlx5e_close_xdpredirect_sq(c->xdpsq);
err_close_tx_cqs:
mlx5e_close_tx_cqs(c);
@@ -2586,7 +2614,6 @@ err_close_async_icosq_cq:
static void mlx5e_close_queues(struct mlx5e_channel *c)
{
- mlx5e_close_xdpsq(&c->xdpsq);
if (c->xdp)
mlx5e_close_xdpsq(&c->rq_xdpsq);
/* The same ICOSQ is used for UMRs for both RQ and XSKRQ. */
@@ -2599,7 +2626,8 @@ static void mlx5e_close_queues(struct mlx5e_channel *c)
if (c->xdp)
mlx5e_close_cq(&c->rq_xdpsq.cq);
mlx5e_close_cq(&c->rq.cq);
- mlx5e_close_cq(&c->xdpsq.cq);
+ if (c->xdpsq)
+ mlx5e_close_xdpredirect_sq(c->xdpsq);
mlx5e_close_tx_cqs(c);
mlx5e_close_cq(&c->icosq.cq);
mlx5e_close_cq(&c->async_icosq.cq);
@@ -4267,7 +4295,8 @@ void mlx5e_set_xdp_feature(struct net_device *netdev)
struct mlx5e_params *params = &priv->channels.params;
xdp_features_t val;
- if (params->packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
+ if (!netdev->netdev_ops->ndo_bpf ||
+ params->packet_merge.type != MLX5E_PACKET_MERGE_NONE) {
xdp_clear_features_flag(netdev);
return;
}
@@ -4557,6 +4586,10 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
out:
WRITE_ONCE(netdev->mtu, params->sw_mtu);
mutex_unlock(&priv->state_lock);
+
+ if (!err)
+ netdev_update_features(netdev);
+
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 92094bf60d59..554f9cb5b53f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -600,7 +600,8 @@ mlx5e_add_sqs_fwd_rules(struct mlx5e_priv *priv)
if (c->xdp)
sqs[num_sqs++] = c->rq_xdpsq.sqn;
- sqs[num_sqs++] = c->xdpsq.sqn;
+ if (c->xdpsq)
+ sqs[num_sqs++] = c->xdpsq->sqn;
}
}
if (ptp_sq) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 8e24ba96c779..1963bc5adb18 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -643,83 +643,82 @@ static void build_ksm_umr(struct mlx5e_icosq *sq, struct mlx5e_umr_wqe *umr_wqe,
umr_wqe->uctrl.mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
}
+static struct mlx5e_frag_page *mlx5e_shampo_hd_to_frag_page(struct mlx5e_rq *rq, int header_index)
+{
+ BUILD_BUG_ON(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE > PAGE_SHIFT);
+
+ return &rq->mpwqe.shampo->pages[header_index >> MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE];
+}
+
+static u64 mlx5e_shampo_hd_offset(int header_index)
+{
+ return (header_index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) <<
+ MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE;
+}
+
+static void mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index);
+
static int mlx5e_build_shampo_hd_umr(struct mlx5e_rq *rq,
struct mlx5e_icosq *sq,
u16 ksm_entries, u16 index)
{
struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
- u16 entries, pi, header_offset, err, wqe_bbs, new_entries;
+ u16 pi, header_offset, err, wqe_bbs;
u32 lkey = rq->mdev->mlx5e_res.hw_objs.mkey;
- u16 page_index = shampo->curr_page_index;
- struct mlx5e_frag_page *frag_page;
- u64 addr = shampo->last_addr;
- struct mlx5e_dma_info *dma_info;
struct mlx5e_umr_wqe *umr_wqe;
- int headroom, i;
+ int headroom, i = 0;
headroom = rq->buff.headroom;
- new_entries = ksm_entries - (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1));
- entries = ALIGN(ksm_entries, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT);
- wqe_bbs = MLX5E_KSM_UMR_WQEBBS(entries);
+ wqe_bbs = MLX5E_KSM_UMR_WQEBBS(ksm_entries);
pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
umr_wqe = mlx5_wq_cyc_get_wqe(&sq->wq, pi);
- build_ksm_umr(sq, umr_wqe, shampo->key, index, entries);
+ build_ksm_umr(sq, umr_wqe, shampo->key, index, ksm_entries);
- frag_page = &shampo->pages[page_index];
+ WARN_ON_ONCE(ksm_entries & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1));
+ while (i < ksm_entries) {
+ struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index);
+ u64 addr;
- for (i = 0; i < entries; i++, index++) {
- dma_info = &shampo->info[index];
- if (i >= ksm_entries || (index < shampo->pi && shampo->pi - index <
- MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT))
- goto update_ksm;
- header_offset = (index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) <<
- MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE;
- if (!(header_offset & (PAGE_SIZE - 1))) {
- page_index = (page_index + 1) & (shampo->hd_per_wq - 1);
- frag_page = &shampo->pages[page_index];
+ err = mlx5e_page_alloc_fragmented(rq, frag_page);
+ if (unlikely(err))
+ goto err_unmap;
- err = mlx5e_page_alloc_fragmented(rq, frag_page);
- if (unlikely(err))
- goto err_unmap;
- addr = page_pool_get_dma_addr(frag_page->page);
+ addr = page_pool_get_dma_addr(frag_page->page);
- dma_info->addr = addr;
- dma_info->frag_page = frag_page;
- } else {
- dma_info->addr = addr + header_offset;
- dma_info->frag_page = frag_page;
- }
+ for (int j = 0; j < MLX5E_SHAMPO_WQ_HEADER_PER_PAGE; j++) {
+ header_offset = mlx5e_shampo_hd_offset(index++);
-update_ksm:
- umr_wqe->inline_ksms[i] = (struct mlx5_ksm) {
- .key = cpu_to_be32(lkey),
- .va = cpu_to_be64(dma_info->addr + headroom),
- };
+ umr_wqe->inline_ksms[i++] = (struct mlx5_ksm) {
+ .key = cpu_to_be32(lkey),
+ .va = cpu_to_be64(addr + header_offset + headroom),
+ };
+ }
}
sq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) {
.wqe_type = MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR,
.num_wqebbs = wqe_bbs,
- .shampo.len = new_entries,
+ .shampo.len = ksm_entries,
};
- shampo->pi = (shampo->pi + new_entries) & (shampo->hd_per_wq - 1);
- shampo->curr_page_index = page_index;
- shampo->last_addr = addr;
+ shampo->pi = (shampo->pi + ksm_entries) & (shampo->hd_per_wq - 1);
sq->pc += wqe_bbs;
sq->doorbell_cseg = &umr_wqe->ctrl;
return 0;
err_unmap:
- while (--i >= 0) {
- dma_info = &shampo->info[--index];
- if (!(i & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1))) {
- dma_info->addr = ALIGN_DOWN(dma_info->addr, PAGE_SIZE);
- mlx5e_page_release_fragmented(rq, dma_info->frag_page);
+ while (--i) {
+ --index;
+ header_offset = mlx5e_shampo_hd_offset(index);
+ if (!header_offset) {
+ struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index);
+
+ mlx5e_page_release_fragmented(rq, frag_page);
}
}
+
rq->stats->buff_alloc_err++;
return err;
}
@@ -731,7 +730,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq)
struct mlx5e_icosq *sq = rq->icosq;
int i, err, max_ksm_entries, len;
- max_ksm_entries = MLX5E_MAX_KSM_PER_WQE(rq->mdev);
+ max_ksm_entries = ALIGN_DOWN(MLX5E_MAX_KSM_PER_WQE(rq->mdev),
+ MLX5E_SHAMPO_WQ_HEADER_PER_PAGE);
ksm_entries = bitmap_find_window(shampo->bitmap,
shampo->hd_per_wqe,
shampo->hd_per_wq, shampo->pi);
@@ -739,8 +739,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq)
if (!ksm_entries)
return 0;
- ksm_entries += (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1));
- index = ALIGN_DOWN(shampo->pi, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT);
+ /* pi is aligned to MLX5E_SHAMPO_WQ_HEADER_PER_PAGE */
+ index = shampo->pi;
entries_before = shampo->hd_per_wq - index;
if (unlikely(entries_before < ksm_entries))
@@ -851,13 +851,11 @@ static void
mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index)
{
struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
- u64 addr = shampo->info[header_index].addr;
if (((header_index + 1) & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) == 0) {
- struct mlx5e_dma_info *dma_info = &shampo->info[header_index];
+ struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
- dma_info->addr = ALIGN_DOWN(addr, PAGE_SIZE);
- mlx5e_page_release_fragmented(rq, dma_info->frag_page);
+ mlx5e_page_release_fragmented(rq, frag_page);
}
clear_bit(header_index, shampo->bitmap);
}
@@ -1211,10 +1209,10 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe,
static void *mlx5e_shampo_get_packet_hd(struct mlx5e_rq *rq, u16 header_index)
{
- struct mlx5e_dma_info *last_head = &rq->mpwqe.shampo->info[header_index];
- u16 head_offset = (last_head->addr & (PAGE_SIZE - 1)) + rq->buff.headroom;
+ struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
+ u16 head_offset = mlx5e_shampo_hd_offset(header_index) + rq->buff.headroom;
- return page_address(last_head->frag_page->page) + head_offset;
+ return page_address(frag_page->page) + head_offset;
}
static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *ipv4)
@@ -2185,29 +2183,30 @@ static struct sk_buff *
mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
struct mlx5_cqe64 *cqe, u16 header_index)
{
- struct mlx5e_dma_info *head = &rq->mpwqe.shampo->info[header_index];
- u16 head_offset = head->addr & (PAGE_SIZE - 1);
+ struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
+ dma_addr_t page_dma_addr = page_pool_get_dma_addr(frag_page->page);
+ u16 head_offset = mlx5e_shampo_hd_offset(header_index);
+ dma_addr_t dma_addr = page_dma_addr + head_offset;
u16 head_size = cqe->shampo.header_size;
u16 rx_headroom = rq->buff.headroom;
struct sk_buff *skb = NULL;
void *hdr, *data;
u32 frag_size;
- hdr = page_address(head->frag_page->page) + head_offset;
+ hdr = page_address(frag_page->page) + head_offset;
data = hdr + rx_headroom;
frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + head_size);
if (likely(frag_size <= BIT(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE))) {
/* build SKB around header */
- dma_sync_single_range_for_cpu(rq->pdev, head->addr, 0, frag_size, rq->buff.map_dir);
+ dma_sync_single_range_for_cpu(rq->pdev, dma_addr, 0, frag_size, rq->buff.map_dir);
net_prefetchw(hdr);
net_prefetch(data);
skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size, 0);
-
if (unlikely(!skb))
return NULL;
- head->frag_page->frags++;
+ frag_page->frags++;
} else {
/* allocate SKB and copy header for large header */
rq->stats->gro_large_hds++;
@@ -2219,7 +2218,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
}
net_prefetchw(skb->data);
- mlx5e_copy_skb_header(rq, skb, head->frag_page->page, head->addr,
+ mlx5e_copy_skb_header(rq, skb, frag_page->page, dma_addr,
head_offset + rx_headroom,
rx_headroom, head_size);
/* skb linear part was allocated with headlen and aligned to long */
@@ -2436,7 +2435,7 @@ static int mlx5e_rx_cq_process_enhanced_cqe_comp(struct mlx5e_rq *rq,
struct mlx5e_cq_decomp *cqd = &rq->cqd;
int work_done = 0;
- cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq);
+ cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq);
if (!cqe)
return work_done;
@@ -2466,7 +2465,7 @@ static int mlx5e_rx_cq_process_enhanced_cqe_comp(struct mlx5e_rq *rq,
rq, cqe);
work_done++;
} while (work_done < budget_rem &&
- (cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq)));
+ (cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq)));
/* last cqe might be title on next poll bulk */
if (title_cqe) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
index 5bf8318cc48b..1d60465cc2ca 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
@@ -36,6 +36,7 @@
#include "en.h"
#include "en/port.h"
#include "eswitch.h"
+#include "lib/mlx5.h"
static int mlx5e_test_health_info(struct mlx5e_priv *priv)
{
@@ -247,6 +248,9 @@ static int mlx5e_cond_loopback(struct mlx5e_priv *priv)
if (is_mdev_switchdev_mode(priv->mdev))
return -EOPNOTSUPP;
+ if (mlx5_get_sd(priv->mdev))
+ return -EOPNOTSUPP;
+
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
index 5873fde65c2e..76108299ea57 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -55,7 +55,7 @@ static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
return;
dim_update_sample(sq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
- net_dim(sq->dim, dim_sample);
+ net_dim(sq->dim, &dim_sample);
}
static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
@@ -67,7 +67,7 @@ static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
return;
dim_update_sample(rq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
- net_dim(rq->dim, dim_sample);
+ net_dim(rq->dim, &dim_sample);
}
void mlx5e_trigger_irq(struct mlx5e_icosq *sq)
@@ -165,7 +165,8 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
if (unlikely(!budget))
goto out;
- busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq.cq);
+ if (c->xdpsq)
+ busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq->cq);
if (c->xdp)
busy |= mlx5e_poll_xdpsq_cq(&c->rq_xdpsq.cq);
@@ -236,7 +237,8 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
mlx5e_cq_arm(&rq->cq);
mlx5e_cq_arm(&c->icosq.cq);
mlx5e_cq_arm(&c->async_icosq.cq);
- mlx5e_cq_arm(&c->xdpsq.cq);
+ if (c->xdpsq)
+ mlx5e_cq_arm(&c->xdpsq->cq);
if (xsk_open) {
mlx5e_handle_rx_dim(xskrq);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 68cb86b37e56..2b229b6226c6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -114,14 +114,10 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
struct mlx5_eq *eq = &eq_comp->core;
struct mlx5_eqe *eqe;
int num_eqes = 0;
- u32 cqn = -1;
- eqe = next_eqe_sw(eq);
- if (!eqe)
- goto out;
-
- do {
+ while ((eqe = next_eqe_sw(eq))) {
struct mlx5_core_cq *cq;
+ u32 cqn;
/* Make sure we read EQ entry contents after we've
* checked the ownership bit.
@@ -142,14 +138,12 @@ static int mlx5_eq_comp_int(struct notifier_block *nb,
++eq->cons_index;
- } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
+ if (++num_eqes >= MLX5_EQ_POLLING_BUDGET)
+ break;
+ }
-out:
eq_update_ci(eq, 1);
- if (cqn != -1)
- tasklet_schedule(&eq_comp->tasklet_ctx.task);
-
return 0;
}
@@ -215,11 +209,7 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
recovery = action == ASYNC_EQ_RECOVER;
mlx5_eq_async_int_lock(eq_async, recovery, &flags);
- eqe = next_eqe_sw(eq);
- if (!eqe)
- goto out;
-
- do {
+ while ((eqe = next_eqe_sw(eq))) {
/*
* Make sure we read EQ entry contents after we've
* checked the ownership bit.
@@ -231,9 +221,10 @@ static int mlx5_eq_async_int(struct notifier_block *nb,
++eq->cons_index;
- } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq)));
+ if (++num_eqes >= MLX5_EQ_POLLING_BUDGET)
+ break;
+ }
-out:
eq_update_ci(eq, 1);
mlx5_eq_async_int_unlock(eq_async, recovery, &flags);
@@ -810,15 +801,8 @@ EXPORT_SYMBOL(mlx5_eq_get_eqe);
void mlx5_eq_update_ci(struct mlx5_eq *eq, u32 cc, bool arm)
{
- __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2);
- u32 val;
-
eq->cons_index += cc;
- val = (eq->cons_index & 0xffffff) | (eq->eqn << 24);
-
- __raw_writel((__force u32)cpu_to_be32(val), addr);
- /* We still want ordering, just not swabbing, so add a barrier */
- wmb();
+ eq_update_ci(eq, arm);
}
EXPORT_SYMBOL(mlx5_eq_update_ci);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
index d0f38818363f..982fe3714683 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c
@@ -195,7 +195,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
return;
dl_port = vport->dl_port;
- mlx5_esw_qos_vport_update_node(vport, NULL, NULL);
+ mlx5_esw_qos_vport_update_parent(vport, NULL, NULL);
devl_rate_leaf_destroy(&dl_port->dl_port);
devl_port_unregister(&dl_port->dl_port);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
index 7e7f99b38a37..8b7c843446e1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
@@ -101,6 +101,12 @@ esw_qos_node_set_parent(struct mlx5_esw_sched_node *node, struct mlx5_esw_sched_
node->esw = parent->esw;
}
+void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport)
+{
+ kfree(vport->qos.sched_node);
+ memset(&vport->qos, 0, sizeof(vport->qos));
+}
+
u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport)
{
if (!vport->qos.sched_node)
@@ -118,18 +124,49 @@ mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport)
return vport->qos.sched_node->parent;
}
-static void esw_qos_sched_elem_config_warn(struct mlx5_esw_sched_node *node, int err)
+static void esw_qos_sched_elem_warn(struct mlx5_esw_sched_node *node, int err, const char *op)
{
if (node->vport) {
esw_warn(node->esw->dev,
- "E-Switch modify %s scheduling element failed (vport=%d,err=%d)\n",
- sched_node_type_str[node->type], node->vport->vport, err);
+ "E-Switch %s %s scheduling element failed (vport=%d,err=%d)\n",
+ op, sched_node_type_str[node->type], node->vport->vport, err);
return;
}
esw_warn(node->esw->dev,
- "E-Switch modify %s scheduling element failed (err=%d)\n",
- sched_node_type_str[node->type], err);
+ "E-Switch %s %s scheduling element failed (err=%d)\n",
+ op, sched_node_type_str[node->type], err);
+}
+
+static int esw_qos_node_create_sched_element(struct mlx5_esw_sched_node *node, void *ctx,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ err = mlx5_create_scheduling_element_cmd(node->esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, ctx,
+ &node->ix);
+ if (err) {
+ esw_qos_sched_elem_warn(node, err, "create");
+ NL_SET_ERR_MSG_MOD(extack, "E-Switch create scheduling element failed");
+ }
+
+ return err;
+}
+
+static int esw_qos_node_destroy_sched_element(struct mlx5_esw_sched_node *node,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ err = mlx5_destroy_scheduling_element_cmd(node->esw->dev,
+ SCHEDULING_HIERARCHY_E_SWITCH,
+ node->ix);
+ if (err) {
+ esw_qos_sched_elem_warn(node, err, "destroy");
+ NL_SET_ERR_MSG_MOD(extack, "E-Switch destroying scheduling element failed.");
+ }
+
+ return err;
}
static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_rate, u32 bw_share,
@@ -143,10 +180,21 @@ static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_r
if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
return -EOPNOTSUPP;
- MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
- MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
- bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
- bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
+ if (bw_share && (!MLX5_CAP_QOS(dev, esw_bw_share) ||
+ MLX5_CAP_QOS(dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE))
+ return -EOPNOTSUPP;
+
+ if (node->max_rate == max_rate && node->bw_share == bw_share)
+ return 0;
+
+ if (node->max_rate != max_rate) {
+ MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
+ bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
+ }
+ if (node->bw_share != bw_share) {
+ MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
+ bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
+ }
err = mlx5_modify_scheduling_element_cmd(dev,
SCHEDULING_HIERARCHY_E_SWITCH,
@@ -154,12 +202,14 @@ static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_r
node->ix,
bitmask);
if (err) {
- esw_qos_sched_elem_config_warn(node, err);
+ esw_qos_sched_elem_warn(node, err, "modify");
NL_SET_ERR_MSG_MOD(extack, "E-Switch modify scheduling element failed");
return err;
}
+ node->max_rate = max_rate;
+ node->bw_share = bw_share;
if (node->type == SCHED_NODE_TYPE_VPORTS_TSAR)
trace_mlx5_esw_node_qos_config(dev, node, node->ix, bw_share, max_rate);
else if (node->type == SCHED_NODE_TYPE_VPORT)
@@ -208,166 +258,51 @@ static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max)
return min_t(u32, max_t(u32, DIV_ROUND_UP(min_rate, divider), MLX5_MIN_BW_SHARE), fw_max);
}
-static int esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node,
- u32 divider,
- struct netlink_ext_ack *extack)
+static void esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node,
+ u32 divider,
+ struct netlink_ext_ack *extack)
{
u32 fw_max_bw_share = MLX5_CAP_QOS(node->esw->dev, max_tsar_bw_share);
u32 bw_share;
- int err;
bw_share = esw_qos_calc_bw_share(node->min_rate, divider, fw_max_bw_share);
- if (bw_share == node->bw_share)
- return 0;
-
- err = esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack);
- if (err)
- return err;
-
- node->bw_share = bw_share;
-
- return err;
+ esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack);
}
-static int esw_qos_normalize_min_rate(struct mlx5_eswitch *esw,
- struct mlx5_esw_sched_node *parent,
- struct netlink_ext_ack *extack)
+static void esw_qos_normalize_min_rate(struct mlx5_eswitch *esw,
+ struct mlx5_esw_sched_node *parent,
+ struct netlink_ext_ack *extack)
{
struct list_head *nodes = parent ? &parent->children : &esw->qos.domain->nodes;
u32 divider = esw_qos_calculate_min_rate_divider(esw, parent);
struct mlx5_esw_sched_node *node;
list_for_each_entry(node, nodes, entry) {
- int err;
-
if (node->esw != esw || node->ix == esw->qos.root_tsar_ix)
continue;
- err = esw_qos_update_sched_node_bw_share(node, divider, extack);
- if (err)
- return err;
+ esw_qos_update_sched_node_bw_share(node, divider, extack);
if (list_empty(&node->children))
continue;
- err = esw_qos_normalize_min_rate(node->esw, node, extack);
- if (err)
- return err;
+ esw_qos_normalize_min_rate(node->esw, node, extack);
}
-
- return 0;
-}
-
-static int esw_qos_set_vport_min_rate(struct mlx5_vport *vport,
- u32 min_rate, struct netlink_ext_ack *extack)
-{
- struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
- u32 fw_max_bw_share, previous_min_rate;
- bool min_rate_supported;
- int err;
-
- esw_assert_qos_lock_held(vport_node->esw);
- fw_max_bw_share = MLX5_CAP_QOS(vport->dev, max_tsar_bw_share);
- min_rate_supported = MLX5_CAP_QOS(vport->dev, esw_bw_share) &&
- fw_max_bw_share >= MLX5_MIN_BW_SHARE;
- if (min_rate && !min_rate_supported)
- return -EOPNOTSUPP;
- if (min_rate == vport_node->min_rate)
- return 0;
-
- previous_min_rate = vport_node->min_rate;
- vport_node->min_rate = min_rate;
- err = esw_qos_normalize_min_rate(vport_node->parent->esw, vport_node->parent, extack);
- if (err)
- vport_node->min_rate = previous_min_rate;
-
- return err;
-}
-
-static int esw_qos_set_vport_max_rate(struct mlx5_vport *vport,
- u32 max_rate, struct netlink_ext_ack *extack)
-{
- struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
- u32 act_max_rate = max_rate;
- bool max_rate_supported;
- int err;
-
- esw_assert_qos_lock_held(vport_node->esw);
- max_rate_supported = MLX5_CAP_QOS(vport->dev, esw_rate_limit);
-
- if (max_rate && !max_rate_supported)
- return -EOPNOTSUPP;
- if (max_rate == vport_node->max_rate)
- return 0;
-
- /* Use parent node limit if new max rate is 0. */
- if (!max_rate)
- act_max_rate = vport_node->parent->max_rate;
-
- err = esw_qos_sched_elem_config(vport_node, act_max_rate, vport_node->bw_share, extack);
- if (!err)
- vport_node->max_rate = max_rate;
-
- return err;
}
static int esw_qos_set_node_min_rate(struct mlx5_esw_sched_node *node,
u32 min_rate, struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = node->esw;
- u32 previous_min_rate;
- int err;
-
- if (!MLX5_CAP_QOS(esw->dev, esw_bw_share) ||
- MLX5_CAP_QOS(esw->dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE)
- return -EOPNOTSUPP;
if (min_rate == node->min_rate)
return 0;
- previous_min_rate = node->min_rate;
node->min_rate = min_rate;
- err = esw_qos_normalize_min_rate(esw, NULL, extack);
- if (err) {
- NL_SET_ERR_MSG_MOD(extack, "E-Switch node min rate setting failed");
-
- /* Attempt restoring previous configuration */
- node->min_rate = previous_min_rate;
- if (esw_qos_normalize_min_rate(esw, NULL, extack))
- NL_SET_ERR_MSG_MOD(extack, "E-Switch BW share restore failed");
- }
+ esw_qos_normalize_min_rate(esw, node->parent, extack);
- return err;
-}
-
-static int esw_qos_set_node_max_rate(struct mlx5_esw_sched_node *node,
- u32 max_rate, struct netlink_ext_ack *extack)
-{
- struct mlx5_esw_sched_node *vport_node;
- int err;
-
- if (node->max_rate == max_rate)
- return 0;
-
- err = esw_qos_sched_elem_config(node, max_rate, node->bw_share, extack);
- if (err)
- return err;
-
- node->max_rate = max_rate;
-
- /* Any unlimited vports in the node should be set with the value of the node. */
- list_for_each_entry(vport_node, &node->children, entry) {
- if (vport_node->max_rate)
- continue;
-
- err = esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share, extack);
- if (err)
- NL_SET_ERR_MSG_MOD(extack,
- "E-Switch vport implicit rate limit setting failed");
- }
-
- return err;
+ return 0;
}
static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id,
@@ -397,14 +332,12 @@ static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_
tsar_ix);
}
-static int
-esw_qos_vport_create_sched_element(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
- u32 max_rate, u32 bw_share, u32 *sched_elem_ix)
+static int esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node,
+ struct netlink_ext_ack *extack)
{
u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
- struct mlx5_core_dev *dev = parent->esw->dev;
+ struct mlx5_core_dev *dev = vport_node->esw->dev;
void *attr;
- int err;
if (!mlx5_qos_element_type_supported(dev,
SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT,
@@ -414,93 +347,11 @@ esw_qos_vport_create_sched_element(struct mlx5_vport *vport, struct mlx5_esw_sch
MLX5_SET(scheduling_context, sched_ctx, element_type,
SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
- MLX5_SET(vport_element, attr, vport_number, vport->vport);
- MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent->ix);
- MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
- MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
-
- err = mlx5_create_scheduling_element_cmd(dev,
- SCHEDULING_HIERARCHY_E_SWITCH,
- sched_ctx,
- sched_elem_ix);
- if (err) {
- esw_warn(dev,
- "E-Switch create vport scheduling element failed (vport=%d,err=%d)\n",
- vport->vport, err);
- return err;
- }
-
- return 0;
-}
-
-static int esw_qos_update_node_scheduling_element(struct mlx5_vport *vport,
- struct mlx5_esw_sched_node *curr_node,
- struct mlx5_esw_sched_node *new_node,
- struct netlink_ext_ack *extack)
-{
- struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
- u32 max_rate;
- int err;
-
- err = mlx5_destroy_scheduling_element_cmd(curr_node->esw->dev,
- SCHEDULING_HIERARCHY_E_SWITCH,
- vport_node->ix);
- if (err) {
- NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy vport scheduling element failed");
- return err;
- }
-
- /* Use new node max rate if vport max rate is unlimited. */
- max_rate = vport_node->max_rate ? vport_node->max_rate : new_node->max_rate;
- err = esw_qos_vport_create_sched_element(vport, new_node, max_rate,
- vport_node->bw_share,
- &vport_node->ix);
- if (err) {
- NL_SET_ERR_MSG_MOD(extack, "E-Switch vport node set failed.");
- goto err_sched;
- }
-
- esw_qos_node_set_parent(vport->qos.sched_node, new_node);
-
- return 0;
-
-err_sched:
- max_rate = vport_node->max_rate ? vport_node->max_rate : curr_node->max_rate;
- if (esw_qos_vport_create_sched_element(vport, curr_node, max_rate,
- vport_node->bw_share,
- &vport_node->ix))
- esw_warn(curr_node->esw->dev, "E-Switch vport node restore failed (vport=%d)\n",
- vport->vport);
+ MLX5_SET(vport_element, attr, vport_number, vport_node->vport->vport);
+ MLX5_SET(scheduling_context, sched_ctx, parent_element_id, vport_node->parent->ix);
+ MLX5_SET(scheduling_context, sched_ctx, max_average_bw, vport_node->max_rate);
- return err;
-}
-
-static int esw_qos_vport_update_node(struct mlx5_vport *vport,
- struct mlx5_esw_sched_node *node,
- struct netlink_ext_ack *extack)
-{
- struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
- struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
- struct mlx5_esw_sched_node *new_node, *curr_node;
- int err;
-
- esw_assert_qos_lock_held(esw);
- curr_node = vport_node->parent;
- new_node = node ?: esw->qos.node0;
- if (curr_node == new_node)
- return 0;
-
- err = esw_qos_update_node_scheduling_element(vport, curr_node, new_node, extack);
- if (err)
- return err;
-
- /* Recalculate bw share weights of old and new nodes */
- if (vport_node->bw_share || new_node->bw_share) {
- esw_qos_normalize_min_rate(curr_node->esw, curr_node, extack);
- esw_qos_normalize_min_rate(new_node->esw, new_node, extack);
- }
-
- return 0;
+ return esw_qos_node_create_sched_element(vport_node, sched_ctx, extack);
}
static struct mlx5_esw_sched_node *
@@ -531,6 +382,12 @@ static void __esw_qos_free_node(struct mlx5_esw_sched_node *node)
kfree(node);
}
+static void esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
+{
+ esw_qos_node_destroy_sched_element(node, extack);
+ __esw_qos_free_node(node);
+}
+
static struct mlx5_esw_sched_node *
__esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
@@ -552,17 +409,11 @@ __esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sch
goto err_alloc_node;
}
- err = esw_qos_normalize_min_rate(esw, NULL, extack);
- if (err) {
- NL_SET_ERR_MSG_MOD(extack, "E-Switch nodes normalization failed");
- goto err_min_rate;
- }
+ esw_qos_normalize_min_rate(esw, NULL, extack);
trace_mlx5_esw_node_qos_create(esw->dev, node, node->ix);
return node;
-err_min_rate:
- __esw_qos_free_node(node);
err_alloc_node:
if (mlx5_destroy_scheduling_element_cmd(esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH,
@@ -595,26 +446,13 @@ esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct netlink_ext_ac
return node;
}
-static int __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
+static void __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = node->esw;
- int err;
trace_mlx5_esw_node_qos_destroy(esw->dev, node, node->ix);
-
- err = mlx5_destroy_scheduling_element_cmd(esw->dev,
- SCHEDULING_HIERARCHY_E_SWITCH,
- node->ix);
- if (err)
- NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed");
- __esw_qos_free_node(node);
-
- err = esw_qos_normalize_min_rate(esw, NULL, extack);
- if (err)
- NL_SET_ERR_MSG_MOD(extack, "E-Switch nodes normalization failed");
-
-
- return err;
+ esw_qos_destroy_node(node, extack);
+ esw_qos_normalize_min_rate(esw, NULL, extack);
}
static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
@@ -699,45 +537,62 @@ static void esw_qos_put(struct mlx5_eswitch *esw)
esw_qos_destroy(esw);
}
-static int esw_qos_vport_enable(struct mlx5_vport *vport,
- u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack)
+static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
+ struct mlx5_esw_sched_node *parent = vport_node->parent;
+
+ esw_qos_node_destroy_sched_element(vport_node, extack);
+
+ vport_node->bw_share = 0;
+ list_del_init(&vport_node->entry);
+ esw_qos_normalize_min_rate(parent->esw, parent, extack);
+
+ trace_mlx5_esw_vport_qos_destroy(vport_node->esw->dev, vport);
+}
+
+static int esw_qos_vport_enable(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
+ struct netlink_ext_ack *extack)
{
- struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
- u32 sched_elem_ix;
int err;
- esw_assert_qos_lock_held(esw);
- if (vport->qos.sched_node)
- return 0;
+ esw_assert_qos_lock_held(vport->dev->priv.eswitch);
- err = esw_qos_get(esw, extack);
+ esw_qos_node_set_parent(vport->qos.sched_node, parent);
+ err = esw_qos_vport_create_sched_element(vport->qos.sched_node, extack);
if (err)
return err;
- err = esw_qos_vport_create_sched_element(vport, esw->qos.node0, max_rate, bw_share,
- &sched_elem_ix);
- if (err)
- goto err_out;
+ esw_qos_normalize_min_rate(parent->esw, parent, extack);
- vport->qos.sched_node = __esw_qos_alloc_node(esw, sched_elem_ix, SCHED_NODE_TYPE_VPORT,
- esw->qos.node0);
- if (!vport->qos.sched_node) {
- err = -ENOMEM;
- goto err_alloc;
- }
+ return 0;
+}
- vport->qos.sched_node->vport = vport;
+static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_type type,
+ struct mlx5_esw_sched_node *parent, u32 max_rate,
+ u32 min_rate, struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
+ struct mlx5_esw_sched_node *sched_node;
+ int err;
- trace_mlx5_esw_vport_qos_create(vport->dev, vport, bw_share, max_rate);
+ esw_assert_qos_lock_held(esw);
+ err = esw_qos_get(esw, extack);
+ if (err)
+ return err;
- return 0;
+ parent = parent ?: esw->qos.node0;
+ sched_node = __esw_qos_alloc_node(parent->esw, 0, type, parent);
+ if (!sched_node)
+ return -ENOMEM;
-err_alloc:
- if (mlx5_destroy_scheduling_element_cmd(esw->dev,
- SCHEDULING_HIERARCHY_E_SWITCH, sched_elem_ix))
- esw_warn(esw->dev, "E-Switch destroy vport scheduling element failed.\n");
-err_out:
- esw_qos_put(esw);
+ sched_node->max_rate = max_rate;
+ sched_node->min_rate = min_rate;
+ sched_node->vport = vport;
+ vport->qos.sched_node = sched_node;
+ err = esw_qos_vport_enable(vport, parent, extack);
+ if (err)
+ esw_qos_put(esw);
return err;
}
@@ -745,51 +600,61 @@ err_out:
void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
- struct mlx5_esw_sched_node *vport_node;
- struct mlx5_core_dev *dev;
- int err;
+ struct mlx5_esw_sched_node *parent;
lockdep_assert_held(&esw->state_lock);
esw_qos_lock(esw);
- vport_node = vport->qos.sched_node;
- if (!vport_node)
+ if (!vport->qos.sched_node)
goto unlock;
- WARN(vport_node->parent != esw->qos.node0,
- "Disabling QoS on port before detaching it from node");
- dev = vport_node->esw->dev;
- trace_mlx5_esw_vport_qos_destroy(dev, vport);
-
- err = mlx5_destroy_scheduling_element_cmd(dev,
- SCHEDULING_HIERARCHY_E_SWITCH,
- vport_node->ix);
- if (err)
- esw_warn(dev,
- "E-Switch destroy vport scheduling element failed (vport=%d,err=%d)\n",
- vport->vport, err);
-
- __esw_qos_free_node(vport_node);
- memset(&vport->qos, 0, sizeof(vport->qos));
+ parent = vport->qos.sched_node->parent;
+ WARN(parent != esw->qos.node0, "Disabling QoS on port before detaching it from node");
+ esw_qos_vport_disable(vport, NULL);
+ mlx5_esw_qos_vport_qos_free(vport);
esw_qos_put(esw);
unlock:
esw_qos_unlock(esw);
}
+static int mlx5_esw_qos_set_vport_max_rate(struct mlx5_vport *vport, u32 max_rate,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
+
+ esw_assert_qos_lock_held(vport->dev->priv.eswitch);
+
+ if (!vport_node)
+ return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, max_rate, 0,
+ extack);
+ else
+ return esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share,
+ extack);
+}
+
+static int mlx5_esw_qos_set_vport_min_rate(struct mlx5_vport *vport, u32 min_rate,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
+
+ esw_assert_qos_lock_held(vport->dev->priv.eswitch);
+
+ if (!vport_node)
+ return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, 0, min_rate,
+ extack);
+ else
+ return esw_qos_set_node_min_rate(vport_node, min_rate, extack);
+}
+
int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *vport, u32 max_rate, u32 min_rate)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err;
esw_qos_lock(esw);
- err = esw_qos_vport_enable(vport, 0, 0, NULL);
- if (err)
- goto unlock;
-
- err = esw_qos_set_vport_min_rate(vport, min_rate, NULL);
+ err = mlx5_esw_qos_set_vport_min_rate(vport, min_rate, NULL);
if (!err)
- err = esw_qos_set_vport_max_rate(vport, max_rate, NULL);
-unlock:
+ err = mlx5_esw_qos_set_vport_max_rate(vport, max_rate, NULL);
esw_qos_unlock(esw);
return err;
}
@@ -809,6 +674,31 @@ bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *m
return enabled;
}
+static int esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
+ struct mlx5_esw_sched_node *curr_parent;
+ int err;
+
+ esw_assert_qos_lock_held(esw);
+ curr_parent = vport->qos.sched_node->parent;
+ parent = parent ?: esw->qos.node0;
+ if (curr_parent == parent)
+ return 0;
+
+ esw_qos_vport_disable(vport, extack);
+
+ err = esw_qos_vport_enable(vport, parent, extack);
+ if (err) {
+ if (esw_qos_vport_enable(vport, curr_parent, NULL))
+ esw_warn(parent->esw->dev, "vport restore QoS failed (vport=%d)\n",
+ vport->vport);
+ }
+
+ return err;
+}
+
static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
{
struct ethtool_link_ksettings lksettings;
@@ -875,10 +765,8 @@ static int mlx5_esw_qos_link_speed_verify(struct mlx5_core_dev *mdev,
int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
{
- u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
struct mlx5_vport *vport;
u32 link_speed_max;
- u32 bitmask;
int err;
vport = mlx5_eswitch_get_vport(esw, vport_num);
@@ -897,20 +785,7 @@ int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32
}
esw_qos_lock(esw);
- if (!vport->qos.sched_node) {
- /* Eswitch QoS wasn't enabled yet. Enable it and vport QoS. */
- err = esw_qos_vport_enable(vport, rate_mbps, 0, NULL);
- } else {
- struct mlx5_core_dev *dev = vport->qos.sched_node->parent->esw->dev;
-
- MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
- bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
- err = mlx5_modify_scheduling_element_cmd(dev,
- SCHEDULING_HIERARCHY_E_SWITCH,
- ctx,
- vport->qos.sched_node->ix,
- bitmask);
- }
+ err = mlx5_esw_qos_set_vport_max_rate(vport, rate_mbps, NULL);
esw_qos_unlock(esw);
return err;
@@ -951,6 +826,9 @@ static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char *
int mlx5_esw_qos_init(struct mlx5_eswitch *esw)
{
+ if (esw->qos.domain)
+ return 0; /* Nothing to change. */
+
return esw_qos_domain_init(esw);
}
@@ -978,12 +856,7 @@ int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void
return err;
esw_qos_lock(esw);
- err = esw_qos_vport_enable(vport, 0, 0, extack);
- if (err)
- goto unlock;
-
- err = esw_qos_set_vport_min_rate(vport, tx_share, extack);
-unlock:
+ err = mlx5_esw_qos_set_vport_min_rate(vport, tx_share, extack);
esw_qos_unlock(esw);
return err;
}
@@ -1004,12 +877,7 @@ int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *
return err;
esw_qos_lock(esw);
- err = esw_qos_vport_enable(vport, 0, 0, extack);
- if (err)
- goto unlock;
-
- err = esw_qos_set_vport_max_rate(vport, tx_max, extack);
-unlock:
+ err = mlx5_esw_qos_set_vport_max_rate(vport, tx_max, extack);
esw_qos_unlock(esw);
return err;
}
@@ -1043,7 +911,7 @@ int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *
return err;
esw_qos_lock(esw);
- err = esw_qos_set_node_max_rate(node, tx_max, extack);
+ err = esw_qos_sched_elem_config(node, tx_max, node->bw_share, extack);
esw_qos_unlock(esw);
return err;
}
@@ -1084,35 +952,30 @@ int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
{
struct mlx5_esw_sched_node *node = priv;
struct mlx5_eswitch *esw = node->esw;
- int err;
esw_qos_lock(esw);
- err = __esw_qos_destroy_node(node, extack);
+ __esw_qos_destroy_node(node, extack);
esw_qos_put(esw);
esw_qos_unlock(esw);
- return err;
+ return 0;
}
-int mlx5_esw_qos_vport_update_node(struct mlx5_vport *vport,
- struct mlx5_esw_sched_node *node,
- struct netlink_ext_ack *extack)
+int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
+ struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err = 0;
- if (node && node->esw != esw) {
+ if (parent && parent->esw != esw) {
NL_SET_ERR_MSG_MOD(extack, "Cross E-Switch scheduling is not supported");
return -EOPNOTSUPP;
}
esw_qos_lock(esw);
- if (!vport->qos.sched_node && !node)
- goto unlock;
-
- err = esw_qos_vport_enable(vport, 0, 0, extack);
- if (!err)
- err = esw_qos_vport_update_node(vport, node, extack);
-unlock:
+ if (!vport->qos.sched_node && parent)
+ err = mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, parent, 0, 0, extack);
+ else if (vport->qos.sched_node)
+ err = esw_qos_vport_update_parent(vport, parent, extack);
esw_qos_unlock(esw);
return err;
}
@@ -1126,8 +989,8 @@ int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate,
struct mlx5_vport *vport = priv;
if (!parent)
- return mlx5_esw_qos_vport_update_node(vport, NULL, extack);
+ return mlx5_esw_qos_vport_update_parent(vport, NULL, extack);
node = parent_priv;
- return mlx5_esw_qos_vport_update_node(vport, node, extack);
+ return mlx5_esw_qos_vport_update_parent(vport, node, extack);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h
index 61a6fdd5c267..6eb8f6a648c8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h
@@ -13,6 +13,7 @@ int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *evport, u32 max_rate, u32 min
bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate);
void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport);
+void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport);
u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport);
struct mlx5_esw_sched_node *mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 09719e9b8611..7fb8a3381f84 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1061,8 +1061,7 @@ static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
unsigned long i;
mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
- kfree(vport->qos.sched_node);
- memset(&vport->qos, 0, sizeof(vport->qos));
+ mlx5_esw_qos_vport_qos_free(vport);
memset(&vport->info, 0, sizeof(vport->info));
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
}
@@ -1074,8 +1073,7 @@ static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw)
unsigned long i;
mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) {
- kfree(vport->qos.sched_node);
- memset(&vport->qos, 0, sizeof(vport->qos));
+ mlx5_esw_qos_vport_qos_free(vport);
memset(&vport->info, 0, sizeof(vport->info));
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
}
@@ -1485,17 +1483,16 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
err = mlx5_esw_qos_init(esw);
if (err)
- goto err_qos_init;
+ goto err_esw_init;
if (esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_legacy_enable(esw);
} else {
- mlx5_rescan_drivers(esw->dev);
err = esw_offloads_enable(esw);
}
if (err)
- goto err_esw_enable;
+ goto err_esw_init;
esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
@@ -1509,9 +1506,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
return 0;
-err_esw_enable:
- mlx5_esw_qos_cleanup(esw);
-err_qos_init:
+err_esw_init:
mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
mlx5_esw_acls_ns_cleanup(esw);
return err;
@@ -1640,7 +1635,6 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
if (esw->mode == MLX5_ESWITCH_OFFLOADS)
devl_rate_nodes_destroy(devlink);
- mlx5_esw_qos_cleanup(esw);
}
void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
@@ -1884,6 +1878,11 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
if (err)
goto reps_err;
+ esw->mode = MLX5_ESWITCH_LEGACY;
+ err = mlx5_esw_qos_init(esw);
+ if (err)
+ goto reps_err;
+
mutex_init(&esw->offloads.encap_tbl_lock);
hash_init(esw->offloads.encap_tbl);
mutex_init(&esw->offloads.decap_tbl_lock);
@@ -1897,7 +1896,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
refcount_set(&esw->qos.refcnt, 0);
esw->enabled_vports = 0;
- esw->mode = MLX5_ESWITCH_LEGACY;
esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
@@ -1934,6 +1932,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
esw_info(esw->dev, "cleanup\n");
+ mlx5_esw_qos_cleanup(esw);
destroy_workqueue(esw->work_queue);
WARN_ON(refcount_read(&esw->qos.refcnt));
mutex_destroy(&esw->state_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 14dd42d44e6f..a83d41121db6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -427,9 +427,8 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
u16 vport_num, bool setting);
int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport,
u32 max_rate, u32 min_rate);
-int mlx5_esw_qos_vport_update_node(struct mlx5_vport *vport,
- struct mlx5_esw_sched_node *node,
- struct netlink_ext_ack *extack);
+int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *node,
+ struct netlink_ext_ack *extack);
int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting);
int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting);
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index fd34f43d18d5..d6ff2dc4c19e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -2332,18 +2332,35 @@ out_free:
return err;
}
+static void esw_mode_change(struct mlx5_eswitch *esw, u16 mode)
+{
+ mlx5_devcom_comp_lock(esw->dev->priv.hca_devcom_comp);
+
+ if (esw->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) {
+ esw->mode = mode;
+ mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp);
+ return;
+ }
+
+ esw->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
+ mlx5_rescan_drivers_locked(esw->dev);
+ esw->mode = mode;
+ esw->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
+ mlx5_rescan_drivers_locked(esw->dev);
+ mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp);
+}
+
static int esw_offloads_start(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
int err;
- esw->mode = MLX5_ESWITCH_OFFLOADS;
+ esw_mode_change(esw, MLX5_ESWITCH_OFFLOADS);
err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch to offloads");
- esw->mode = MLX5_ESWITCH_LEGACY;
- mlx5_rescan_drivers(esw->dev);
+ esw_mode_change(esw, MLX5_ESWITCH_LEGACY);
return err;
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
@@ -2527,8 +2544,11 @@ static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
struct mlx5_eswitch_rep *rep, u8 rep_type)
{
if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
- REP_LOADED, REP_REGISTERED) == REP_LOADED)
+ REP_LOADED, REP_REGISTERED) == REP_LOADED) {
+ if (rep_type == REP_ETH)
+ __esw_offloads_unload_rep(esw, rep, REP_IB);
esw->offloads.rep_ops[rep_type]->unload(rep);
+ }
}
static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
@@ -3584,7 +3604,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
{
int err;
- esw->mode = MLX5_ESWITCH_LEGACY;
+ esw_mode_change(esw, MLX5_ESWITCH_LEGACY);
/* If changing from switchdev to legacy mode without sriov enabled,
* no need to create legacy fdb.
@@ -3770,7 +3790,6 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
err = esw_offloads_start(esw, extack);
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
err = esw_offloads_stop(esw, extack);
- mlx5_rescan_drivers(esw->dev);
} else {
err = -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
index c2db0a1c132b..2eabfcc247c6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
@@ -2105,13 +2105,22 @@ lookup_fte_locked(struct mlx5_flow_group *g,
fte_tmp = NULL;
goto out;
}
+
+ nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
+
if (!fte_tmp->node.active) {
+ up_write_ref_node(&fte_tmp->node, false);
+
+ if (take_write)
+ up_write_ref_node(&g->node, false);
+ else
+ up_read_ref_node(&g->node);
+
tree_put_node(&fte_tmp->node, false);
- fte_tmp = NULL;
- goto out;
+
+ return NULL;
}
- nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD);
out:
if (take_write)
up_write_ref_node(&g->node, false);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index b30976627c6b..bad2df0715ec 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -37,7 +37,7 @@
#include <linux/mlx5/fs.h>
#include <linux/rhashtable.h>
#include <linux/llist.h>
-#include <steering/fs_dr.h>
+#include <steering/sws/fs_dr.h>
#define FDB_TC_MAX_CHAIN 3
#define FDB_FT_CHAIN (FDB_TC_MAX_CHAIN + 1)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index b306ae79bf97..4822d01123b4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -402,9 +402,7 @@ static int mlx5_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info);
- struct mlx5_timer *timer = &clock->timer;
struct mlx5_core_dev *mdev;
- unsigned long flags;
u64 cycles, ns;
mdev = container_of(clock, struct mlx5_core_dev, clock);
@@ -413,10 +411,8 @@ static int mlx5_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts,
goto out;
}
- write_seqlock_irqsave(&clock->lock, flags);
cycles = mlx5_read_time(mdev, sts, false);
- ns = timecounter_cyc2time(&timer->tc, cycles);
- write_sequnlock_irqrestore(&clock->lock, flags);
+ ns = mlx5_timecounter_cyc2time(clock, cycles);
*ts = ns_to_timespec64(ns);
out:
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
index 4b7f7131c560..b1edc71ffc6d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h
@@ -72,7 +72,7 @@ static inline void eq_update_ci(struct mlx5_eq *eq, int arm)
__raw_writel((__force u32)cpu_to_be32(val), addr);
/* We still want ordering, just not swabbing, so add a barrier */
- mb();
+ wmb();
}
int mlx5_eq_table_init(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h
index 452d0df339ac..404f3d4b6380 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h
@@ -4,8 +4,8 @@
#ifndef __MLX5_LIB_SMFS_H__
#define __MLX5_LIB_SMFS_H__
-#include "steering/mlx5dr.h"
-#include "steering/dr_types.h"
+#include "steering/sws/mlx5dr.h"
+#include "steering/sws/dr_types.h"
struct mlx5dr_matcher *
mlx5_smfs_matcher_create(struct mlx5dr_table *table, u32 priority, struct mlx5_flow_spec *spec);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
index 81a9232a03e1..7db9cab9bedf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
@@ -593,9 +593,11 @@ static void irq_pool_free(struct mlx5_irq_pool *pool)
kvfree(pool);
}
-static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
+static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec,
+ bool dynamic_vec)
{
struct mlx5_irq_table *table = dev->priv.irq_table;
+ int sf_vec_available = sf_vec;
int num_sf_ctrl;
int err;
@@ -616,6 +618,13 @@ static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
num_sf_ctrl = DIV_ROUND_UP(mlx5_sf_max_functions(dev),
MLX5_SFS_PER_CTRL_IRQ);
num_sf_ctrl = min_t(int, MLX5_IRQ_CTRL_SF_MAX, num_sf_ctrl);
+ if (!dynamic_vec && (num_sf_ctrl + 1) > sf_vec_available) {
+ mlx5_core_dbg(dev,
+ "Not enough IRQs for SFs control and completion pool, required=%d avail=%d\n",
+ num_sf_ctrl + 1, sf_vec_available);
+ return 0;
+ }
+
table->sf_ctrl_pool = irq_pool_alloc(dev, pcif_vec, num_sf_ctrl,
"mlx5_sf_ctrl",
MLX5_EQ_SHARE_IRQ_MIN_CTRL,
@@ -624,9 +633,11 @@ static int irq_pools_init(struct mlx5_core_dev *dev, int sf_vec, int pcif_vec)
err = PTR_ERR(table->sf_ctrl_pool);
goto err_pf;
}
- /* init sf_comp_pool */
+ sf_vec_available -= num_sf_ctrl;
+
+ /* init sf_comp_pool, remaining vectors are for the SF completions */
table->sf_comp_pool = irq_pool_alloc(dev, pcif_vec + num_sf_ctrl,
- sf_vec - num_sf_ctrl, "mlx5_sf_comp",
+ sf_vec_available, "mlx5_sf_comp",
MLX5_EQ_SHARE_IRQ_MIN_COMP,
MLX5_EQ_SHARE_IRQ_MAX_COMP);
if (IS_ERR(table->sf_comp_pool)) {
@@ -715,6 +726,7 @@ int mlx5_irq_table_get_num_comp(struct mlx5_irq_table *table)
int mlx5_irq_table_create(struct mlx5_core_dev *dev)
{
int num_eqs = mlx5_max_eq_cap_get(dev);
+ bool dynamic_vec;
int total_vec;
int pcif_vec;
int req_vec;
@@ -724,21 +736,31 @@ int mlx5_irq_table_create(struct mlx5_core_dev *dev)
if (mlx5_core_is_sf(dev))
return 0;
+ /* PCI PF vectors usage is limited by online cpus, device EQs and
+ * PCI MSI-X capability.
+ */
pcif_vec = MLX5_CAP_GEN(dev, num_ports) * num_online_cpus() + 1;
pcif_vec = min_t(int, pcif_vec, num_eqs);
+ pcif_vec = min_t(int, pcif_vec, pci_msix_vec_count(dev->pdev));
total_vec = pcif_vec;
if (mlx5_sf_max_functions(dev))
total_vec += MLX5_MAX_MSIX_PER_SF * mlx5_sf_max_functions(dev);
total_vec = min_t(int, total_vec, pci_msix_vec_count(dev->pdev));
- pcif_vec = min_t(int, pcif_vec, pci_msix_vec_count(dev->pdev));
req_vec = pci_msix_can_alloc_dyn(dev->pdev) ? 1 : total_vec;
n = pci_alloc_irq_vectors(dev->pdev, 1, req_vec, PCI_IRQ_MSIX);
if (n < 0)
return n;
- err = irq_pools_init(dev, total_vec - pcif_vec, pcif_vec);
+ /* Further limit vectors of the pools based on platform for non dynamic case */
+ dynamic_vec = pci_msix_can_alloc_dyn(dev->pdev);
+ if (!dynamic_vec) {
+ pcif_vec = min_t(int, n, pcif_vec);
+ total_vec = min_t(int, n, total_vec);
+ }
+
+ err = irq_pools_init(dev, total_vec - pcif_vec, pcif_vec, dynamic_vec);
if (err)
pci_free_irq_vectors(dev->pdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c
index b27bb4106532..a897cdc60fdb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
#define MLX5HWS_ACTION_METER_INIT_COLOR_OFFSET 1
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h
index bf5c1b241006..e8f562c31826 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_ACTION_H_
-#define MLX5HWS_ACTION_H_
+#ifndef HWS_ACTION_H_
+#define HWS_ACTION_H_
/* Max number of STEs needed for a rule (including match) */
#define MLX5HWS_ACTION_MAX_STE 20
@@ -304,4 +304,4 @@ mlx5hws_action_apply_setter(struct mlx5hws_actions_apply_data *apply,
htonl(num_of_actions << 29);
}
-#endif /* MLX5HWS_ACTION_H_ */
+#endif /* HWS_ACTION_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c
index e6ed66202a40..b9aef80ba094 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
-#include "mlx5hws_buddy.h"
+#include "internal.h"
+#include "buddy.h"
static int hws_buddy_init(struct mlx5hws_buddy_mem *buddy, u32 max_order)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h
index 338c44bbedaf..ef6b223677aa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_BUDDY_H_
-#define MLX5HWS_BUDDY_H_
+#ifndef HWS_BUDDY_H_
+#define HWS_BUDDY_H_
struct mlx5hws_buddy_mem {
unsigned long **bitmap;
@@ -18,4 +18,4 @@ int mlx5hws_buddy_alloc_mem(struct mlx5hws_buddy_mem *buddy, u32 order);
void mlx5hws_buddy_free_mem(struct mlx5hws_buddy_mem *buddy, u32 seg, u32 order);
-#endif /* MLX5HWS_BUDDY_H_ */
+#endif /* HWS_BUDDY_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
index 8f3a6f9d703d..baacf662c0ab 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
static u16 hws_bwc_gen_queue_idx(struct mlx5hws_context *ctx)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h
index 4fe8c32d8fbe..0b745968e21e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_BWC_H_
-#define MLX5HWS_BWC_H_
+#ifndef HWS_BWC_H_
+#define HWS_BWC_H_
#define MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG 1
#define MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP 1
@@ -70,4 +70,4 @@ static inline u16 mlx5hws_bwc_get_queue_id(struct mlx5hws_context *ctx, u16 idx)
return idx + mlx5hws_bwc_queues(ctx);
}
-#endif /* MLX5HWS_BWC_H_ */
+#endif /* HWS_BWC_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c
index 601fad5fc54a..c00010ca86bd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx,
u8 match_criteria_enable,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h
index 068ee8118609..340f0688e394 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_BWC_COMPLEX_H_
-#define MLX5HWS_BWC_COMPLEX_H_
+#ifndef HWS_BWC_COMPLEX_H_
+#define HWS_BWC_COMPLEX_H_
bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx,
u8 match_criteria_enable,
@@ -26,4 +26,4 @@ int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule,
int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule);
-#endif /* MLX5HWS_BWC_COMPLEX_H_ */
+#endif /* HWS_BWC_COMPLEX_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c
index 2c7b14172049..c00c138c3366 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
static enum mlx5_ifc_flow_destination_type
hws_cmd_dest_type_to_ifc_dest_type(enum mlx5_flow_destination_type type)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h
index 2fbcf4ff571a..434f62b0904e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_CMD_H_
-#define MLX5HWS_CMD_H_
+#ifndef HWS_CMD_H_
+#define HWS_CMD_H_
#define WIRE_PORT 0xFFFF
@@ -358,4 +358,4 @@ int mlx5hws_cmd_allow_other_vhca_access(struct mlx5_core_dev *mdev,
int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function,
u16 vport_number, u16 *gvmi);
-#endif /* MLX5HWS_CMD_H_ */
+#endif /* HWS_CMD_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c
index 00e4fdf4a558..fd48b05e91e0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved. */
-#include "mlx5hws_internal.h"
+#include "internal.h"
bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
index 8ab548aa402b..47f5cc8de73f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_CONTEXT_H_
-#define MLX5HWS_CONTEXT_H_
+#ifndef HWS_CONTEXT_H_
+#define HWS_CONTEXT_H_
enum mlx5hws_context_flags {
MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT = 1 << 0,
@@ -62,4 +62,4 @@ bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx);
u8 mlx5hws_context_get_reparse_mode(struct mlx5hws_context *ctx);
-#endif /* MLX5HWS_CONTEXT_H_ */
+#endif /* HWS_CONTEXT_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c
index 2b8c5a4e1c4c..5b200b4bc1a8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c
@@ -5,7 +5,7 @@
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/version.h>
-#include "mlx5hws_internal.h"
+#include "internal.h"
static int
hws_debug_dump_matcher_template_definer(struct seq_file *f,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h
index b93a536035d9..e44e7ae28f93 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_DEBUG_H_
-#define MLX5HWS_DEBUG_H_
+#ifndef HWS_DEBUG_H_
+#define HWS_DEBUG_H_
#define HWS_DEBUG_FORMAT_VERSION "1.0"
@@ -37,4 +37,4 @@ mlx5hws_debug_icm_to_idx(u64 icm_addr)
void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx);
void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx);
-#endif /* MLX5HWS_DEBUG_H_ */
+#endif /* HWS_DEBUG_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c
index 3f4c58bada37..8fe96eb76baf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
/* Pattern tunnel Layer bits. */
#define MLX5_FLOW_LAYER_VXLAN BIT(12)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h
index 2f6a7df4021c..9432d5084def 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_DEFINER_H_
-#define MLX5HWS_DEFINER_H_
+#ifndef HWS_DEFINER_H_
+#define HWS_DEFINER_H_
/* Max available selecotrs */
#define DW_SELECTORS 9
@@ -831,4 +831,4 @@ mlx5hws_definer_conv_match_params_to_compressed_fc(struct mlx5hws_context *ctx,
u32 *match_param,
int *fc_sz);
-#endif /* MLX5HWS_DEFINER_H_ */
+#endif /* HWS_DEFINER_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h
index 5643be1cd5bf..3c8635f286ce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_INTERNAL_H_
-#define MLX5HWS_INTERNAL_H_
+#ifndef HWS_INTERNAL_H_
+#define HWS_INTERNAL_H_
#include <linux/mlx5/transobj.h>
#include <linux/mlx5/vport.h>
@@ -10,22 +10,22 @@
#include "wq.h"
#include "lib/mlx5.h"
-#include "mlx5hws_prm.h"
+#include "prm.h"
#include "mlx5hws.h"
-#include "mlx5hws_pool.h"
-#include "mlx5hws_vport.h"
-#include "mlx5hws_context.h"
-#include "mlx5hws_table.h"
-#include "mlx5hws_send.h"
-#include "mlx5hws_rule.h"
-#include "mlx5hws_cmd.h"
-#include "mlx5hws_action.h"
-#include "mlx5hws_definer.h"
-#include "mlx5hws_matcher.h"
-#include "mlx5hws_debug.h"
-#include "mlx5hws_pat_arg.h"
-#include "mlx5hws_bwc.h"
-#include "mlx5hws_bwc_complex.h"
+#include "pool.h"
+#include "vport.h"
+#include "context.h"
+#include "table.h"
+#include "send.h"
+#include "rule.h"
+#include "cmd.h"
+#include "action.h"
+#include "definer.h"
+#include "matcher.h"
+#include "debug.h"
+#include "pat_arg.h"
+#include "bwc.h"
+#include "bwc_complex.h"
#define W_SIZE 2
#define DW_SIZE 4
@@ -56,4 +56,4 @@ static inline unsigned long align(unsigned long val, unsigned long align)
return (val + align - 1) & ~(align - 1);
}
-#endif /* MLX5HWS_INTERNAL_H_ */
+#endif /* HWS_INTERNAL_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c
index 61a1155d4b4f..1bb3a6f8c3cd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
enum mlx5hws_matcher_rtc_type {
HWS_MATCHER_RTC_TYPE_MATCH,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h
index 125391d1a114..81ff487f57be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#ifndef MLX5HWS_MATCHER_H_
-#define MLX5HWS_MATCHER_H_
+#ifndef HWS_MATCHER_H_
+#define HWS_MATCHER_H_
/* We calculated that concatenating a collision table to the main table with
* 3% of the main table rows will be enough resources for high insertion
@@ -104,4 +104,4 @@ static inline bool mlx5hws_matcher_is_insert_by_idx(struct mlx5hws_matcher *matc
return matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX;
}
-#endif /* MLX5HWS_MATCHER_H_ */
+#endif /* HWS_MATCHER_H_ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c
index e084a5cbf81f..06db5e4726ae 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
enum mlx5hws_arg_chunk_size
mlx5hws_arg_data_size_to_arg_log_size(u16 data_size)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h
index 27ca93385b08..27ca93385b08 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c
index a8a63e3278be..fed2d913f3b8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
-#include "mlx5hws_buddy.h"
+#include "internal.h"
+#include "buddy.h"
static void hws_pool_free_one_resource(struct mlx5hws_pool_resource *resource)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h
index 621298b352b2..621298b352b2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h
index de92cecbeb92..de92cecbeb92 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c
index 8a011b958b43..e20c67a04203 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
static void hws_rule_skip(struct mlx5hws_matcher *matcher,
struct mlx5hws_match_template *mt,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h
index 495cdd17e9f3..495cdd17e9f3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c
index 6d443e6ee8d9..424797b6d802 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
#include "lib/clock.h"
enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h
index b50825d6dc53..b50825d6dc53 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c
index 8c063a8d87d7..9576e02d00c3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
u32 mlx5hws_table_get_id(struct mlx5hws_table *tbl)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h
index dd50420eec9e..dd50420eec9e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c
index faf42421c43f..d8e382b9fa61 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */
-#include "mlx5hws_internal.h"
+#include "internal.h"
int mlx5hws_vport_init_vports(struct mlx5hws_context *ctx)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h
index 0912fc166b3a..0912fc166b3a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c
index 2ebb61ef3ea9..2ebb61ef3ea9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c
index 01ed6442095d..01ed6442095d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c
index fe228d948b47..fe228d948b47 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c
index baefb9a3fa05..baefb9a3fa05 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c
index 030a5776c937..030a5776c937 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h
index 57c6b363b870..57c6b363b870 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c
index d5ea97751945..d5ea97751945 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c
index 3d74109f8230..3d74109f8230 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c
index f05ef0cd54ba..f05ef0cd54ba 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c
index 0b5af9f3f605..0b5af9f3f605 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c
index 0726848eb3ff..0726848eb3ff 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c
index 8ca534ef5d03..8ca534ef5d03 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_rule.c
index d1db04baa1fa..d1db04baa1fa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_rule.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c
index 6fa06ba2d346..6fa06ba2d346 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c
index e94fbb015efa..e94fbb015efa 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h
index 54a6619c3ecb..54a6619c3ecb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c
index e9f6c7ed7a7b..e9f6c7ed7a7b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c
index 1d49704b9542..1d49704b9542 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h
index e2fc69867088..e2fc69867088 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c
index 808b013cf48c..808b013cf48c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c
index 69294a66fd7f..69294a66fd7f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h
index 7618c6147f86..7618c6147f86 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c
index 4b349d4005e4..4b349d4005e4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h
index 99a3b2eff6b8..99a3b2eff6b8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h
index fb078fa0f0cc..fb078fa0f0cc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h
index ca3b0f1453a7..ca3b0f1453a7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h
index 3ac7dc67509f..3ac7dc67509f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
index e4ef1d24a3ad..6debb8fd33ff 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h
@@ -244,7 +244,7 @@ static inline struct mlx5_cqe64 *mlx5_cqwq_get_cqe(struct mlx5_cqwq *wq)
}
static inline
-struct mlx5_cqe64 *mlx5_cqwq_get_cqe_enahnced_comp(struct mlx5_cqwq *wq)
+struct mlx5_cqe64 *mlx5_cqwq_get_cqe_enhanced_comp(struct mlx5_cqwq *wq)
{
u8 sw_validity_iteration_count = mlx5_cqwq_get_wrap_cnt(wq) & 0xff;
u32 ci = mlx5_cqwq_get_ci(wq);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 060e5b939211..d6f37456fb31 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -389,15 +389,27 @@ static void mlxsw_pci_wqe_frag_unmap(struct mlxsw_pci *mlxsw_pci, char *wqe,
dma_unmap_single(&pdev->dev, mapaddr, frag_len, direction);
}
-static struct sk_buff *mlxsw_pci_rdq_build_skb(struct page *pages[],
+static struct sk_buff *mlxsw_pci_rdq_build_skb(struct mlxsw_pci_queue *q,
+ struct page *pages[],
u16 byte_count)
{
+ struct mlxsw_pci_queue *cq = q->u.rdq.cq;
unsigned int linear_data_size;
+ struct page_pool *page_pool;
struct sk_buff *skb;
int page_index = 0;
bool linear_only;
void *data;
+ linear_only = byte_count + MLXSW_PCI_RX_BUF_SW_OVERHEAD <= PAGE_SIZE;
+ linear_data_size = linear_only ? byte_count :
+ PAGE_SIZE -
+ MLXSW_PCI_RX_BUF_SW_OVERHEAD;
+
+ page_pool = cq->u.cq.page_pool;
+ page_pool_dma_sync_for_cpu(page_pool, pages[page_index],
+ MLXSW_PCI_SKB_HEADROOM, linear_data_size);
+
data = page_address(pages[page_index]);
net_prefetch(data);
@@ -405,11 +417,6 @@ static struct sk_buff *mlxsw_pci_rdq_build_skb(struct page *pages[],
if (unlikely(!skb))
return ERR_PTR(-ENOMEM);
- linear_only = byte_count + MLXSW_PCI_RX_BUF_SW_OVERHEAD <= PAGE_SIZE;
- linear_data_size = linear_only ? byte_count :
- PAGE_SIZE -
- MLXSW_PCI_RX_BUF_SW_OVERHEAD;
-
skb_reserve(skb, MLXSW_PCI_SKB_HEADROOM);
skb_put(skb, linear_data_size);
@@ -425,6 +432,7 @@ static struct sk_buff *mlxsw_pci_rdq_build_skb(struct page *pages[],
page = pages[page_index];
frag_size = min(byte_count, PAGE_SIZE);
+ page_pool_dma_sync_for_cpu(page_pool, page, 0, frag_size);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
page, 0, frag_size, PAGE_SIZE);
byte_count -= frag_size;
@@ -760,7 +768,7 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
if (err)
goto out;
- skb = mlxsw_pci_rdq_build_skb(pages, byte_count);
+ skb = mlxsw_pci_rdq_build_skb(q, pages, byte_count);
if (IS_ERR(skb)) {
dev_err_ratelimited(&pdev->dev, "Failed to build skb for RDQ\n");
mlxsw_pci_rdq_pages_recycle(q, pages, num_sg_entries);
@@ -988,12 +996,13 @@ static int mlxsw_pci_cq_page_pool_init(struct mlxsw_pci_queue *q,
if (cq_type != MLXSW_PCI_CQ_RDQ)
return 0;
- pp_params.flags = PP_FLAG_DMA_MAP;
+ pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
pp_params.pool_size = MLXSW_PCI_WQE_COUNT * mlxsw_pci->num_sg_entries;
pp_params.nid = dev_to_node(&mlxsw_pci->pdev->dev);
pp_params.dev = &mlxsw_pci->pdev->dev;
pp_params.napi = &q->u.cq.napi;
pp_params.dma_dir = DMA_FROM_DEVICE;
+ pp_params.max_len = PAGE_SIZE;
page_pool = page_pool_create(&pp_params);
if (IS_ERR(page_pool))
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
index d761a1235994..7ea798a4949e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
@@ -481,11 +481,33 @@ mlxsw_sp_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry,
struct netlink_ext_ack *extack)
{
+ u32 new_kvdl_index, old_kvdl_index = ipip_entry->dip_kvdl_index;
+ struct in6_addr old_addr6 = ipip_entry->parms.daddr.addr6;
struct mlxsw_sp_ipip_parms new_parms;
+ int err;
new_parms = mlxsw_sp_ipip_netdev_parms_init_gre6(ipip_entry->ol_dev);
- return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
- &new_parms, extack);
+
+ err = mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp,
+ &new_parms.daddr.addr6,
+ &new_kvdl_index);
+ if (err)
+ return err;
+ ipip_entry->dip_kvdl_index = new_kvdl_index;
+
+ err = mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
+ &new_parms, extack);
+ if (err)
+ goto err_change_gre;
+
+ mlxsw_sp_ipv6_addr_put(mlxsw_sp, &old_addr6);
+
+ return 0;
+
+err_change_gre:
+ ipip_entry->dip_kvdl_index = old_kvdl_index;
+ mlxsw_sp_ipv6_addr_put(mlxsw_sp, &new_parms.daddr.addr6);
+ return err;
}
static int
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index 5b174cb95eb8..d94081c7658e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -16,6 +16,7 @@
#include "spectrum.h"
#include "spectrum_ptp.h"
#include "core.h"
+#include "txheader.h"
#define MLXSW_SP1_PTP_CLOCK_CYCLES_SHIFT 29
#define MLXSW_SP1_PTP_CLOCK_FREQ_KHZ 156257 /* 6.4nSec */
@@ -1684,6 +1685,12 @@ int mlxsw_sp_ptp_txhdr_construct(struct mlxsw_core *mlxsw_core,
struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info)
{
+ if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
+ this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+
mlxsw_sp_txhdr_construct(skb, tx_info);
return 0;
}
diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile
index cadd4dac6620..425e8b801265 100644
--- a/drivers/net/ethernet/meta/fbnic/Makefile
+++ b/drivers/net/ethernet/meta/fbnic/Makefile
@@ -7,7 +7,8 @@
obj-$(CONFIG_FBNIC) += fbnic.o
-fbnic-y := fbnic_devlink.o \
+fbnic-y := fbnic_csr.o \
+ fbnic_devlink.o \
fbnic_ethtool.o \
fbnic_fw.o \
fbnic_hw_stats.o \
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h
index fec567c8fe4a..98870cb2b689 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic.h
@@ -48,6 +48,7 @@ struct fbnic_dev {
struct fbnic_act_tcam act_tcam[FBNIC_RPC_TCAM_ACT_NUM_ENTRIES];
struct fbnic_mac_addr mac_addr[FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES];
u8 mac_addr_boundary;
+ u8 tce_tcam_last;
/* Number of TCQs/RCQs available on hardware */
u16 max_num_queues;
@@ -155,6 +156,9 @@ int fbnic_alloc_irqs(struct fbnic_dev *fbd);
void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,
const size_t str_sz);
+void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version);
+int fbnic_csr_regs_len(struct fbnic_dev *fbd);
+
enum fbnic_boards {
fbnic_board_asic
};
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.c b/drivers/net/ethernet/meta/fbnic/fbnic_csr.c
new file mode 100644
index 000000000000..2118901b25e9
--- /dev/null
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#include "fbnic.h"
+
+#define FBNIC_BOUNDS(section) { \
+ .start = FBNIC_CSR_START_##section, \
+ .end = FBNIC_CSR_END_##section + 1, \
+}
+
+struct fbnic_csr_bounds {
+ u32 start;
+ u32 end;
+};
+
+static const struct fbnic_csr_bounds fbnic_csr_sects[] = {
+ FBNIC_BOUNDS(INTR),
+ FBNIC_BOUNDS(INTR_CQ),
+ FBNIC_BOUNDS(QM_TX),
+ FBNIC_BOUNDS(QM_RX),
+ FBNIC_BOUNDS(TCE),
+ FBNIC_BOUNDS(TCE_RAM),
+ FBNIC_BOUNDS(TMI),
+ FBNIC_BOUNDS(PTP),
+ FBNIC_BOUNDS(RXB),
+ FBNIC_BOUNDS(RPC),
+ FBNIC_BOUNDS(FAB),
+ FBNIC_BOUNDS(MASTER),
+ FBNIC_BOUNDS(PCS),
+ FBNIC_BOUNDS(RSFEC),
+ FBNIC_BOUNDS(MAC_MAC),
+ FBNIC_BOUNDS(SIG),
+ FBNIC_BOUNDS(PUL_USER),
+ FBNIC_BOUNDS(QUEUE),
+ FBNIC_BOUNDS(RPC_RAM),
+};
+
+#define FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY 14
+#define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64
+
+#define FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY 4
+#define FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES 32
+
+#define FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY 9
+#define FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES 8
+
+#define FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY 9
+#define FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES 8
+
+#define FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY 9
+#define FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES 8
+
+#define FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY 9
+#define FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES 8
+
+#define FBNIC_RPC_RSS_TBL_DW_PER_ENTRY 2
+#define FBNIC_RPC_RSS_TBL_NUM_ENTRIES 256
+
+static void fbnic_csr_get_regs_rpc_ram(struct fbnic_dev *fbd, u32 **data_p)
+{
+ u32 start = FBNIC_CSR_START_RPC_RAM;
+ u32 end = FBNIC_CSR_END_RPC_RAM;
+ u32 *data = *data_p;
+ u32 i, j;
+
+ *(data++) = start;
+ *(data++) = end - 1;
+
+ /* FBNIC_RPC_TCAM_ACT */
+ for (i = 0; i < FBNIC_RPC_TCAM_ACT_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_ACT(i, j));
+ }
+
+ /* FBNIC_RPC_TCAM_MACDA */
+ for (i = 0; i < FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_MACDA(i, j));
+ }
+
+ /* FBNIC_RPC_TCAM_OUTER_IPSRC */
+ for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(i, j));
+ }
+
+ /* FBNIC_RPC_TCAM_OUTER_IPDST */
+ for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(i, j));
+ }
+
+ /* FBNIC_RPC_TCAM_IPSRC */
+ for (i = 0; i < FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPSRC(i, j));
+ }
+
+ /* FBNIC_RPC_TCAM_IPDST */
+ for (i = 0; i < FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPDST(i, j));
+ }
+
+ /* FBNIC_RPC_RSS_TBL */
+ for (i = 0; i < FBNIC_RPC_RSS_TBL_NUM_ENTRIES; i++) {
+ for (j = 0; j < FBNIC_RPC_RSS_TBL_DW_PER_ENTRY; j++)
+ *(data++) = rd32(fbd, FBNIC_RPC_RSS_TBL(i, j));
+ }
+
+ *data_p = data;
+}
+
+void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version)
+{
+ const struct fbnic_csr_bounds *bound;
+ u32 *start = data;
+ int i, j;
+
+ *regs_version = 1u;
+
+ /* Skip RPC_RAM section which cannot be dumped linearly */
+ for (i = 0, bound = fbnic_csr_sects;
+ i < ARRAY_SIZE(fbnic_csr_sects) - 1; i++, ++bound) {
+ *(data++) = bound->start;
+ *(data++) = bound->end - 1;
+ for (j = bound->start; j < bound->end; j++)
+ *(data++) = rd32(fbd, j);
+ }
+
+ /* Dump the RPC_RAM as special case registers */
+ fbnic_csr_get_regs_rpc_ram(fbd, &data);
+
+ WARN_ON(data - start != fbnic_csr_regs_len(fbd));
+}
+
+int fbnic_csr_regs_len(struct fbnic_dev *fbd)
+{
+ int i, len = 0;
+
+ /* Dump includes start and end information of each section
+ * which results in an offset of 2
+ */
+ for (i = 0; i < ARRAY_SIZE(fbnic_csr_sects); i++)
+ len += fbnic_csr_sects[i].end - fbnic_csr_sects[i].start + 2;
+
+ return len;
+}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
index 79cdd231d327..f9a531ce9e17 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h
@@ -397,6 +397,14 @@ enum {
#define FBNIC_TCE_DROP_CTRL_TTI_FRM_DROP_EN CSR_BIT(1)
#define FBNIC_TCE_DROP_CTRL_TTI_TBI_DROP_EN CSR_BIT(2)
+#define FBNIC_TCE_TCAM_IDX2DEST_MAP 0x0404A /* 0x10128 */
+#define FBNIC_TCE_TCAM_IDX2DEST_MAP_DEST_ID_0 CSR_GENMASK(3, 0)
+enum {
+ FBNIC_TCE_TCAM_DEST_MAC = 1,
+ FBNIC_TCE_TCAM_DEST_BMC = 2,
+ FBNIC_TCE_TCAM_DEST_FW = 4,
+};
+
#define FBNIC_TCE_TXB_TX_BMC_Q_CTRL 0x0404B /* 0x1012c */
#define FBNIC_TCE_TXB_BMC_DWRR_CTRL 0x0404C /* 0x10130 */
#define FBNIC_TCE_TXB_BMC_DWRR_CTRL_QUANTUM0 CSR_GENMASK(7, 0)
@@ -407,6 +415,18 @@ enum {
#define FBNIC_TCE_TXB_BMC_DWRR_CTRL_EXT 0x0404F /* 0x1013c */
#define FBNIC_CSR_END_TCE 0x04050 /* CSR section delimiter */
+/* TCE RAM registers */
+#define FBNIC_CSR_START_TCE_RAM 0x04200 /* CSR section delimiter */
+#define FBNIC_TCE_RAM_TCAM(m, n) \
+ (0x04200 + 0x8 * (n) + (m)) /* 0x10800 + 32*n + 4*m */
+#define FBNIC_TCE_RAM_TCAM_MASK CSR_GENMASK(15, 0)
+#define FBNIC_TCE_RAM_TCAM_VALUE CSR_GENMASK(31, 16)
+#define FBNIC_TCE_RAM_TCAM3(n) (0x04218 + (n)) /* 0x010860 + 4*n */
+#define FBNIC_TCE_RAM_TCAM3_DEST_MASK CSR_GENMASK(5, 3)
+#define FBNIC_TCE_RAM_TCAM3_MCQ_MASK CSR_BIT(7)
+#define FBNIC_TCE_RAM_TCAM3_VALIDATE CSR_BIT(31)
+#define FBNIC_CSR_END_TCE_RAM 0x0421F /* CSR section delimiter */
+
/* TMI registers */
#define FBNIC_CSR_START_TMI 0x04400 /* CSR section delimiter */
#define FBNIC_TMI_SOP_PROT_CTRL 0x04400 /* 0x11000 */
@@ -645,6 +665,15 @@ enum {
#define FBNIC_RPC_TCAM_MACDA_VALUE CSR_GENMASK(15, 0)
#define FBNIC_RPC_TCAM_MACDA_MASK CSR_GENMASK(31, 16)
+#define FBNIC_RPC_TCAM_OUTER_IPSRC(m, n)\
+ (0x08c00 + 0x08 * (n) + (m)) /* 0x023000 + 32*n + 4*m */
+#define FBNIC_RPC_TCAM_OUTER_IPDST(m, n)\
+ (0x08c48 + 0x08 * (n) + (m)) /* 0x023120 + 32*n + 4*m */
+#define FBNIC_RPC_TCAM_IPSRC(m, n)\
+ (0x08c90 + 0x08 * (n) + (m)) /* 0x023240 + 32*n + 4*m */
+#define FBNIC_RPC_TCAM_IPDST(m, n)\
+ (0x08cd8 + 0x08 * (n) + (m)) /* 0x023360 + 32*n + 4*m */
+
#define FBNIC_RPC_RSS_TBL(n, m) \
(0x08d20 + 0x100 * (n) + (m)) /* 0x023480 + 1024*n + 4*m */
#define FBNIC_RPC_RSS_TBL_COUNT 2
@@ -663,6 +692,13 @@ enum {
#define FBNIC_MASTER_SPARE_0 0x0C41B /* 0x3106c */
#define FBNIC_CSR_END_MASTER 0x0C452 /* CSR section delimiter */
+/* MAC PCS registers */
+#define FBNIC_CSR_START_PCS 0x10000 /* CSR section delimiter */
+#define FBNIC_CSR_END_PCS 0x10668 /* CSR section delimiter */
+
+#define FBNIC_CSR_START_RSFEC 0x10800 /* CSR section delimiter */
+#define FBNIC_CSR_END_RSFEC 0x108c8 /* CSR section delimiter */
+
/* MAC MAC registers (ASIC only) */
#define FBNIC_CSR_START_MAC_MAC 0x11000 /* CSR section delimiter */
#define FBNIC_MAC_COMMAND_CONFIG 0x11002 /* 0x44008 */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
index 1117d5a32867..354b5397815f 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
@@ -116,8 +116,25 @@ static void fbnic_get_ts_stats(struct net_device *netdev,
}
}
+static void fbnic_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *data)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+
+ fbnic_csr_get_regs(fbn->fbd, data, &regs->version);
+}
+
+static int fbnic_get_regs_len(struct net_device *netdev)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+
+ return fbnic_csr_regs_len(fbn->fbd) * sizeof(u32);
+}
+
static const struct ethtool_ops fbnic_ethtool_ops = {
.get_drvinfo = fbnic_get_drvinfo,
+ .get_regs_len = fbnic_get_regs_len,
+ .get_regs = fbnic_get_regs,
.get_ts_info = fbnic_get_ts_info,
.get_ts_stats = fbnic_get_ts_stats,
.get_eth_mac_stats = fbnic_get_eth_mac_stats,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index c08798fad203..fc7d80db5fa6 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -273,6 +273,7 @@ void __fbnic_set_rx_mode(struct net_device *netdev)
/* Write updates to hardware */
fbnic_write_rules(fbd);
fbnic_write_macda(fbd);
+ fbnic_write_tce_tcam(fbd);
}
static void fbnic_set_rx_mode(struct net_device *netdev)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c
index 337b8b3aef2f..908c098cd59e 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c
@@ -587,6 +587,116 @@ static void fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsigned int idx)
wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), 0);
}
+static void fbnic_clear_tce_tcam_entry(struct fbnic_dev *fbd, unsigned int idx)
+{
+ int i;
+
+ /* Invalidate entry and clear addr state info */
+ for (i = 0; i <= FBNIC_TCE_TCAM_WORD_LEN; i++)
+ wr32(fbd, FBNIC_TCE_RAM_TCAM(idx, i), 0);
+}
+
+static void fbnic_write_tce_tcam_dest(struct fbnic_dev *fbd, unsigned int idx,
+ struct fbnic_mac_addr *mac_addr)
+{
+ u32 dest = FBNIC_TCE_TCAM_DEST_BMC;
+ u32 idx2dest_map;
+
+ if (is_multicast_ether_addr(mac_addr->value.addr8))
+ dest |= FBNIC_TCE_TCAM_DEST_MAC;
+
+ idx2dest_map = rd32(fbd, FBNIC_TCE_TCAM_IDX2DEST_MAP);
+ idx2dest_map &= ~(FBNIC_TCE_TCAM_IDX2DEST_MAP_DEST_ID_0 << (4 * idx));
+ idx2dest_map |= dest << (4 * idx);
+
+ wr32(fbd, FBNIC_TCE_TCAM_IDX2DEST_MAP, idx2dest_map);
+}
+
+static void fbnic_write_tce_tcam_entry(struct fbnic_dev *fbd, unsigned int idx,
+ struct fbnic_mac_addr *mac_addr)
+{
+ __be16 *mask, *value;
+ int i;
+
+ mask = &mac_addr->mask.addr16[FBNIC_TCE_TCAM_WORD_LEN - 1];
+ value = &mac_addr->value.addr16[FBNIC_TCE_TCAM_WORD_LEN - 1];
+
+ for (i = 0; i < FBNIC_TCE_TCAM_WORD_LEN; i++)
+ wr32(fbd, FBNIC_TCE_RAM_TCAM(idx, i),
+ FIELD_PREP(FBNIC_TCE_RAM_TCAM_MASK, ntohs(*mask--)) |
+ FIELD_PREP(FBNIC_TCE_RAM_TCAM_VALUE, ntohs(*value--)));
+
+ wrfl(fbd);
+
+ wr32(fbd, FBNIC_TCE_RAM_TCAM3(idx), FBNIC_TCE_RAM_TCAM3_MCQ_MASK |
+ FBNIC_TCE_RAM_TCAM3_DEST_MASK |
+ FBNIC_TCE_RAM_TCAM3_VALIDATE);
+}
+
+static void __fbnic_write_tce_tcam_rev(struct fbnic_dev *fbd)
+{
+ int tcam_idx = FBNIC_TCE_TCAM_NUM_ENTRIES;
+ int mac_idx;
+
+ for (mac_idx = ARRAY_SIZE(fbd->mac_addr); mac_idx--;) {
+ struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[mac_idx];
+
+ /* Verify BMC bit is set */
+ if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam))
+ continue;
+
+ if (!tcam_idx) {
+ dev_err(fbd->dev, "TCE TCAM overflow\n");
+ return;
+ }
+
+ tcam_idx--;
+ fbnic_write_tce_tcam_dest(fbd, tcam_idx, mac_addr);
+ fbnic_write_tce_tcam_entry(fbd, tcam_idx, mac_addr);
+ }
+
+ while (tcam_idx)
+ fbnic_clear_tce_tcam_entry(fbd, --tcam_idx);
+
+ fbd->tce_tcam_last = tcam_idx;
+}
+
+static void __fbnic_write_tce_tcam(struct fbnic_dev *fbd)
+{
+ int tcam_idx = 0;
+ int mac_idx;
+
+ for (mac_idx = 0; mac_idx < ARRAY_SIZE(fbd->mac_addr); mac_idx++) {
+ struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[mac_idx];
+
+ /* Verify BMC bit is set */
+ if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam))
+ continue;
+
+ if (tcam_idx == FBNIC_TCE_TCAM_NUM_ENTRIES) {
+ dev_err(fbd->dev, "TCE TCAM overflow\n");
+ return;
+ }
+
+ fbnic_write_tce_tcam_dest(fbd, tcam_idx, mac_addr);
+ fbnic_write_tce_tcam_entry(fbd, tcam_idx, mac_addr);
+ tcam_idx++;
+ }
+
+ while (tcam_idx < FBNIC_TCE_TCAM_NUM_ENTRIES)
+ fbnic_clear_tce_tcam_entry(fbd, tcam_idx++);
+
+ fbd->tce_tcam_last = tcam_idx;
+}
+
+void fbnic_write_tce_tcam(struct fbnic_dev *fbd)
+{
+ if (fbd->tce_tcam_last)
+ __fbnic_write_tce_tcam_rev(fbd);
+ else
+ __fbnic_write_tce_tcam(fbd);
+}
+
void fbnic_clear_rules(struct fbnic_dev *fbd)
{
u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h
index d62935f722a2..0d8285fa5b45 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h
@@ -35,6 +35,9 @@ enum {
#define FBNIC_RPC_TCAM_ACT_WORD_LEN 11
#define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64
+#define FBNIC_TCE_TCAM_WORD_LEN 3
+#define FBNIC_TCE_TCAM_NUM_ENTRIES 8
+
struct fbnic_mac_addr {
union {
unsigned char addr8[ETH_ALEN];
@@ -186,4 +189,5 @@ static inline int __fbnic_mc_unsync(struct fbnic_mac_addr *mac_addr)
void fbnic_clear_rules(struct fbnic_dev *fbd);
void fbnic_write_rules(struct fbnic_dev *fbd);
+void fbnic_write_tce_tcam(struct fbnic_dev *fbd);
#endif /* _FBNIC_RPC_H_ */
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index ee046468652c..73832fb2bc32 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -59,6 +59,7 @@ config LAN743X
source "drivers/net/ethernet/microchip/lan865x/Kconfig"
source "drivers/net/ethernet/microchip/lan966x/Kconfig"
+source "drivers/net/ethernet/microchip/lan969x/Kconfig"
source "drivers/net/ethernet/microchip/sparx5/Kconfig"
source "drivers/net/ethernet/microchip/vcap/Kconfig"
source "drivers/net/ethernet/microchip/fdma/Kconfig"
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index 3c65baed9fd8..7770df82200f 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -11,6 +11,7 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
obj-$(CONFIG_LAN865X) += lan865x/
obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
+obj-$(CONFIG_LAN969X_SWITCH) += lan969x/
obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
obj-$(CONFIG_VCAP) += vcap/
obj-$(CONFIG_FDMA) += fdma/
diff --git a/drivers/net/ethernet/microchip/lan969x/Kconfig b/drivers/net/ethernet/microchip/lan969x/Kconfig
new file mode 100644
index 000000000000..c5c6122ae2ec
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/Kconfig
@@ -0,0 +1,5 @@
+config LAN969X_SWITCH
+ bool "Lan969x switch driver"
+ depends on SPARX5_SWITCH
+ help
+ This driver supports the lan969x family of network switch devices.
diff --git a/drivers/net/ethernet/microchip/lan969x/Makefile b/drivers/net/ethernet/microchip/lan969x/Makefile
new file mode 100644
index 000000000000..316405cbbc71
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Microchip lan969x network device drivers.
+#
+
+obj-$(CONFIG_SPARX5_SWITCH) += lan969x-switch.o
+
+lan969x-switch-y := lan969x_regs.o lan969x.o lan969x_calendar.o \
+ lan969x_vcap_ag_api.o lan969x_vcap_impl.o
+
+# Provide include files
+ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/fdma
+ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x.c b/drivers/net/ethernet/microchip/lan969x/lan969x.c
new file mode 100644
index 000000000000..ac37d0f74ee3
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip lan969x Switch driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "lan969x.h"
+
+#define LAN969X_SDLB_GRP_CNT 5
+#define LAN969X_HSCH_LEAK_GRP_CNT 4
+
+static const struct sparx5_main_io_resource lan969x_main_iomap[] = {
+ { TARGET_CPU, 0xc0000, 0 }, /* 0xe00c0000 */
+ { TARGET_FDMA, 0xc0400, 0 }, /* 0xe00c0400 */
+ { TARGET_GCB, 0x2010000, 1 }, /* 0xe2010000 */
+ { TARGET_QS, 0x2030000, 1 }, /* 0xe2030000 */
+ { TARGET_PTP, 0x2040000, 1 }, /* 0xe2040000 */
+ { TARGET_ANA_ACL, 0x2050000, 1 }, /* 0xe2050000 */
+ { TARGET_LRN, 0x2060000, 1 }, /* 0xe2060000 */
+ { TARGET_VCAP_SUPER, 0x2080000, 1 }, /* 0xe2080000 */
+ { TARGET_QSYS, 0x20a0000, 1 }, /* 0xe20a0000 */
+ { TARGET_QFWD, 0x20b0000, 1 }, /* 0xe20b0000 */
+ { TARGET_XQS, 0x20c0000, 1 }, /* 0xe20c0000 */
+ { TARGET_VCAP_ES2, 0x20d0000, 1 }, /* 0xe20d0000 */
+ { TARGET_VCAP_ES0, 0x20e0000, 1 }, /* 0xe20e0000 */
+ { TARGET_ANA_AC_POL, 0x2200000, 1 }, /* 0xe2200000 */
+ { TARGET_QRES, 0x2280000, 1 }, /* 0xe2280000 */
+ { TARGET_EACL, 0x22c0000, 1 }, /* 0xe22c0000 */
+ { TARGET_ANA_CL, 0x2400000, 1 }, /* 0xe2400000 */
+ { TARGET_ANA_L3, 0x2480000, 1 }, /* 0xe2480000 */
+ { TARGET_ANA_AC_SDLB, 0x2500000, 1 }, /* 0xe2500000 */
+ { TARGET_HSCH, 0x2580000, 1 }, /* 0xe2580000 */
+ { TARGET_REW, 0x2600000, 1 }, /* 0xe2600000 */
+ { TARGET_ANA_L2, 0x2800000, 1 }, /* 0xe2800000 */
+ { TARGET_ANA_AC, 0x2900000, 1 }, /* 0xe2900000 */
+ { TARGET_VOP, 0x2a00000, 1 }, /* 0xe2a00000 */
+ { TARGET_DEV2G5, 0x3004000, 1 }, /* 0xe3004000 */
+ { TARGET_DEV10G, 0x3008000, 1 }, /* 0xe3008000 */
+ { TARGET_PCS10G_BR, 0x300c000, 1 }, /* 0xe300c000 */
+ { TARGET_DEV2G5 + 1, 0x3010000, 1 }, /* 0xe3010000 */
+ { TARGET_DEV2G5 + 2, 0x3014000, 1 }, /* 0xe3014000 */
+ { TARGET_DEV2G5 + 3, 0x3018000, 1 }, /* 0xe3018000 */
+ { TARGET_DEV2G5 + 4, 0x301c000, 1 }, /* 0xe301c000 */
+ { TARGET_DEV10G + 1, 0x3020000, 1 }, /* 0xe3020000 */
+ { TARGET_PCS10G_BR + 1, 0x3024000, 1 }, /* 0xe3024000 */
+ { TARGET_DEV2G5 + 5, 0x3028000, 1 }, /* 0xe3028000 */
+ { TARGET_DEV2G5 + 6, 0x302c000, 1 }, /* 0xe302c000 */
+ { TARGET_DEV2G5 + 7, 0x3030000, 1 }, /* 0xe3030000 */
+ { TARGET_DEV2G5 + 8, 0x3034000, 1 }, /* 0xe3034000 */
+ { TARGET_DEV10G + 2, 0x3038000, 1 }, /* 0xe3038000 */
+ { TARGET_PCS10G_BR + 2, 0x303c000, 1 }, /* 0xe303c000 */
+ { TARGET_DEV2G5 + 9, 0x3040000, 1 }, /* 0xe3040000 */
+ { TARGET_DEV5G, 0x3044000, 1 }, /* 0xe3044000 */
+ { TARGET_PCS5G_BR, 0x3048000, 1 }, /* 0xe3048000 */
+ { TARGET_DEV2G5 + 10, 0x304c000, 1 }, /* 0xe304c000 */
+ { TARGET_DEV2G5 + 11, 0x3050000, 1 }, /* 0xe3050000 */
+ { TARGET_DEV2G5 + 12, 0x3054000, 1 }, /* 0xe3054000 */
+ { TARGET_DEV10G + 3, 0x3058000, 1 }, /* 0xe3058000 */
+ { TARGET_PCS10G_BR + 3, 0x305c000, 1 }, /* 0xe305c000 */
+ { TARGET_DEV2G5 + 13, 0x3060000, 1 }, /* 0xe3060000 */
+ { TARGET_DEV5G + 1, 0x3064000, 1 }, /* 0xe3064000 */
+ { TARGET_PCS5G_BR + 1, 0x3068000, 1 }, /* 0xe3068000 */
+ { TARGET_DEV2G5 + 14, 0x306c000, 1 }, /* 0xe306c000 */
+ { TARGET_DEV2G5 + 15, 0x3070000, 1 }, /* 0xe3070000 */
+ { TARGET_DEV2G5 + 16, 0x3074000, 1 }, /* 0xe3074000 */
+ { TARGET_DEV10G + 4, 0x3078000, 1 }, /* 0xe3078000 */
+ { TARGET_PCS10G_BR + 4, 0x307c000, 1 }, /* 0xe307c000 */
+ { TARGET_DEV2G5 + 17, 0x3080000, 1 }, /* 0xe3080000 */
+ { TARGET_DEV5G + 2, 0x3084000, 1 }, /* 0xe3084000 */
+ { TARGET_PCS5G_BR + 2, 0x3088000, 1 }, /* 0xe3088000 */
+ { TARGET_DEV2G5 + 18, 0x308c000, 1 }, /* 0xe308c000 */
+ { TARGET_DEV2G5 + 19, 0x3090000, 1 }, /* 0xe3090000 */
+ { TARGET_DEV2G5 + 20, 0x3094000, 1 }, /* 0xe3094000 */
+ { TARGET_DEV10G + 5, 0x3098000, 1 }, /* 0xe3098000 */
+ { TARGET_PCS10G_BR + 5, 0x309c000, 1 }, /* 0xe309c000 */
+ { TARGET_DEV2G5 + 21, 0x30a0000, 1 }, /* 0xe30a0000 */
+ { TARGET_DEV5G + 3, 0x30a4000, 1 }, /* 0xe30a4000 */
+ { TARGET_PCS5G_BR + 3, 0x30a8000, 1 }, /* 0xe30a8000 */
+ { TARGET_DEV2G5 + 22, 0x30ac000, 1 }, /* 0xe30ac000 */
+ { TARGET_DEV2G5 + 23, 0x30b0000, 1 }, /* 0xe30b0000 */
+ { TARGET_DEV2G5 + 24, 0x30b4000, 1 }, /* 0xe30b4000 */
+ { TARGET_DEV10G + 6, 0x30b8000, 1 }, /* 0xe30b8000 */
+ { TARGET_PCS10G_BR + 6, 0x30bc000, 1 }, /* 0xe30bc000 */
+ { TARGET_DEV2G5 + 25, 0x30c0000, 1 }, /* 0xe30c0000 */
+ { TARGET_DEV10G + 7, 0x30c4000, 1 }, /* 0xe30c4000 */
+ { TARGET_PCS10G_BR + 7, 0x30c8000, 1 }, /* 0xe30c8000 */
+ { TARGET_DEV2G5 + 26, 0x30cc000, 1 }, /* 0xe30cc000 */
+ { TARGET_DEV10G + 8, 0x30d0000, 1 }, /* 0xe30d0000 */
+ { TARGET_PCS10G_BR + 8, 0x30d4000, 1 }, /* 0xe30d4000 */
+ { TARGET_DEV2G5 + 27, 0x30d8000, 1 }, /* 0xe30d8000 */
+ { TARGET_DEV10G + 9, 0x30dc000, 1 }, /* 0xe30dc000 */
+ { TARGET_PCS10G_BR + 9, 0x30e0000, 1 }, /* 0xe30e0000 */
+ { TARGET_DSM, 0x30ec000, 1 }, /* 0xe30ec000 */
+ { TARGET_PORT_CONF, 0x30f0000, 1 }, /* 0xe30f0000 */
+ { TARGET_ASM, 0x3200000, 1 }, /* 0xe3200000 */
+};
+
+static struct sparx5_sdlb_group lan969x_sdlb_groups[LAN969X_SDLB_GRP_CNT] = {
+ { 1000000000, 8192 / 2, 64 }, /* 1 G */
+ { 500000000, 8192 / 2, 64 }, /* 500 M */
+ { 100000000, 8192 / 4, 64 }, /* 100 M */
+ { 50000000, 8192 / 4, 64 }, /* 50 M */
+ { 5000000, 8192 / 8, 64 }, /* 10 M */
+};
+
+static u32 lan969x_hsch_max_group_rate[LAN969X_HSCH_LEAK_GRP_CNT] = {
+ 655355, 1048568, 6553550, 10485680
+};
+
+static struct sparx5_sdlb_group *lan969x_get_sdlb_group(int idx)
+{
+ return &lan969x_sdlb_groups[idx];
+}
+
+static u32 lan969x_get_hsch_max_group_rate(int grp)
+{
+ return lan969x_hsch_max_group_rate[grp];
+}
+
+static u32 lan969x_get_dev_mode_bit(struct sparx5 *sparx5, int port)
+{
+ if (lan969x_port_is_2g5(port) || lan969x_port_is_5g(port))
+ return port;
+
+ /* 10G */
+ switch (port) {
+ case 0:
+ return 12;
+ case 4:
+ return 13;
+ case 8:
+ return 14;
+ case 12:
+ return 0;
+ default:
+ return port;
+ }
+}
+
+static u32 lan969x_port_dev_mapping(struct sparx5 *sparx5, int port)
+{
+ if (lan969x_port_is_5g(port)) {
+ switch (port) {
+ case 9:
+ return 0;
+ case 13:
+ return 1;
+ case 17:
+ return 2;
+ case 21:
+ return 3;
+ }
+ }
+
+ if (lan969x_port_is_10g(port)) {
+ switch (port) {
+ case 0:
+ return 0;
+ case 4:
+ return 1;
+ case 8:
+ return 2;
+ case 12:
+ return 3;
+ case 16:
+ return 4;
+ case 20:
+ return 5;
+ case 24:
+ return 6;
+ case 25:
+ return 7;
+ case 26:
+ return 8;
+ case 27:
+ return 9;
+ }
+ }
+
+ /* 2g5 port */
+ return port;
+}
+
+static int lan969x_port_mux_set(struct sparx5 *sparx5, struct sparx5_port *port,
+ struct sparx5_port_config *conf)
+{
+ u32 portno = port->portno;
+ u32 inst;
+
+ if (port->conf.portmode == conf->portmode)
+ return 0; /* Nothing to do */
+
+ switch (conf->portmode) {
+ case PHY_INTERFACE_MODE_QSGMII: /* QSGMII: 4x2G5 devices. Mode Q' */
+ inst = (portno - portno % 4) / 4;
+ spx5_rmw(BIT(inst), BIT(inst), sparx5, PORT_CONF_QSGMII_ENA);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static irqreturn_t lan969x_ptp_irq_handler(int irq, void *args)
+{
+ int budget = SPARX5_MAX_PTP_ID;
+ struct sparx5 *sparx5 = args;
+
+ while (budget--) {
+ struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sparx5_port *port;
+ struct timespec64 ts;
+ unsigned long flags;
+ u32 val, id, txport;
+ u32 delay;
+
+ val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL);
+
+ /* Check if a timestamp can be retrieved */
+ if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD))
+ break;
+
+ WARN_ON(val & PTP_TWOSTEP_CTRL_PTP_OVFL);
+
+ if (!(val & PTP_TWOSTEP_CTRL_STAMP_TX))
+ continue;
+
+ /* Retrieve the ts Tx port */
+ txport = PTP_TWOSTEP_CTRL_STAMP_PORT_GET(val);
+
+ /* Retrieve its associated skb */
+ port = sparx5->ports[txport];
+
+ /* Retrieve the delay */
+ delay = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC);
+ delay = PTP_TWOSTEP_STAMP_NSEC_NS_GET(delay);
+
+ /* Get next timestamp from fifo, which needs to be the
+ * rx timestamp which represents the id of the frame
+ */
+ spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
+ PTP_TWOSTEP_CTRL_PTP_NXT,
+ sparx5, PTP_TWOSTEP_CTRL);
+
+ val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL);
+
+ /* Check if a timestamp can be retrieved */
+ if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD))
+ break;
+
+ /* Read RX timestamping to get the ID */
+ id = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC);
+ id <<= 8;
+ id |= spx5_rd(sparx5, PTP_TWOSTEP_STAMP_SUBNS);
+
+ spin_lock_irqsave(&port->tx_skbs.lock, flags);
+ skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
+ if (SPARX5_SKB_CB(skb)->ts_id != id)
+ continue;
+
+ __skb_unlink(skb, &port->tx_skbs);
+ skb_match = skb;
+ break;
+ }
+ spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
+
+ /* Next ts */
+ spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
+ PTP_TWOSTEP_CTRL_PTP_NXT,
+ sparx5, PTP_TWOSTEP_CTRL);
+
+ if (WARN_ON(!skb_match))
+ continue;
+
+ spin_lock(&sparx5->ptp_ts_id_lock);
+ sparx5->ptp_skbs--;
+ spin_unlock(&sparx5->ptp_ts_id_lock);
+
+ /* Get the h/w timestamp */
+ sparx5_get_hwtimestamp(sparx5, &ts, delay);
+
+ /* Set the timestamp in the skb */
+ shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+ skb_tstamp_tx(skb_match, &shhwtstamps);
+
+ dev_kfree_skb_any(skb_match);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct sparx5_regs lan969x_regs = {
+ .tsize = lan969x_tsize,
+ .gaddr = lan969x_gaddr,
+ .gcnt = lan969x_gcnt,
+ .gsize = lan969x_gsize,
+ .raddr = lan969x_raddr,
+ .rcnt = lan969x_rcnt,
+ .fpos = lan969x_fpos,
+ .fsize = lan969x_fsize,
+};
+
+static const struct sparx5_consts lan969x_consts = {
+ .n_ports = 30,
+ .n_ports_all = 35,
+ .n_hsch_l1_elems = 32,
+ .n_hsch_queues = 4,
+ .n_lb_groups = 5,
+ .n_pgids = 1054, /* (1024 + n_ports) */
+ .n_sio_clks = 1,
+ .n_own_upsids = 1,
+ .n_auto_cals = 4,
+ .n_filters = 256,
+ .n_gates = 256,
+ .n_sdlbs = 496,
+ .n_dsm_cal_taxis = 5,
+ .buf_size = 1572864,
+ .qres_max_prio_idx = 315,
+ .qres_max_colour_idx = 323,
+ .tod_pin = 4,
+ .vcaps = lan969x_vcaps,
+ .vcap_stats = &lan969x_vcap_stats,
+ .vcaps_cfg = lan969x_vcap_inst_cfg,
+};
+
+static const struct sparx5_ops lan969x_ops = {
+ .is_port_2g5 = &lan969x_port_is_2g5,
+ .is_port_5g = &lan969x_port_is_5g,
+ .is_port_10g = &lan969x_port_is_10g,
+ .is_port_25g = &lan969x_port_is_25g,
+ .get_port_dev_index = &lan969x_port_dev_mapping,
+ .get_port_dev_bit = &lan969x_get_dev_mode_bit,
+ .get_hsch_max_group_rate = &lan969x_get_hsch_max_group_rate,
+ .get_sdlb_group = &lan969x_get_sdlb_group,
+ .set_port_mux = &lan969x_port_mux_set,
+ .ptp_irq_handler = &lan969x_ptp_irq_handler,
+ .dsm_calendar_calc = &lan969x_dsm_calendar_calc,
+};
+
+const struct sparx5_match_data lan969x_desc = {
+ .iomap = lan969x_main_iomap,
+ .iomap_size = ARRAY_SIZE(lan969x_main_iomap),
+ .ioranges = 2,
+ .regs = &lan969x_regs,
+ .consts = &lan969x_consts,
+ .ops = &lan969x_ops,
+};
+EXPORT_SYMBOL_GPL(lan969x_desc);
+
+MODULE_DESCRIPTION("Microchip lan969x switch driver");
+MODULE_AUTHOR("Daniel Machon <daniel.machon@microchip.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x.h b/drivers/net/ethernet/microchip/lan969x/lan969x.h
new file mode 100644
index 000000000000..2489d0d32dfd
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Microchip lan969x Switch driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#ifndef __LAN969X_H__
+#define __LAN969X_H__
+
+#include "../sparx5/sparx5_main.h"
+#include "../sparx5/sparx5_regs.h"
+#include "../sparx5/sparx5_vcap_impl.h"
+
+/* lan969x.c */
+extern const struct sparx5_match_data lan969x_desc;
+
+/* lan969x_vcap_ag_api.c */
+extern const struct vcap_statistics lan969x_vcap_stats;
+extern const struct vcap_info lan969x_vcaps[];
+
+/* lan969x_vcap_impl.c */
+extern const struct sparx5_vcap_inst lan969x_vcap_inst_cfg[];
+
+/* lan969x_regs.c */
+extern const unsigned int lan969x_tsize[TSIZE_LAST];
+extern const unsigned int lan969x_raddr[RADDR_LAST];
+extern const unsigned int lan969x_rcnt[RCNT_LAST];
+extern const unsigned int lan969x_gaddr[GADDR_LAST];
+extern const unsigned int lan969x_gcnt[GCNT_LAST];
+extern const unsigned int lan969x_gsize[GSIZE_LAST];
+extern const unsigned int lan969x_fpos[FPOS_LAST];
+extern const unsigned int lan969x_fsize[FSIZE_LAST];
+
+static inline bool lan969x_port_is_2g5(int portno)
+{
+ return portno == 1 || portno == 2 || portno == 3 ||
+ portno == 5 || portno == 6 || portno == 7 ||
+ portno == 10 || portno == 11 || portno == 14 ||
+ portno == 15 || portno == 18 || portno == 19 ||
+ portno == 22 || portno == 23;
+}
+
+static inline bool lan969x_port_is_5g(int portno)
+{
+ return portno == 9 || portno == 13 || portno == 17 ||
+ portno == 21;
+}
+
+static inline bool lan969x_port_is_10g(int portno)
+{
+ return portno == 0 || portno == 4 || portno == 8 ||
+ portno == 12 || portno == 16 || portno == 20 ||
+ portno == 24 || portno == 25 || portno == 26 ||
+ portno == 27;
+}
+
+static inline bool lan969x_port_is_25g(int portno)
+{
+ return false;
+}
+
+/* lan969x_calendar.c */
+int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
+ struct sparx5_calendar_data *data);
+#endif
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c b/drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c
new file mode 100644
index 000000000000..e857640df185
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip lan969x Switch driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include "lan969x.h"
+
+#define LAN969X_DSM_CAL_DEVS_PER_TAXI 10
+#define LAN969X_DSM_CAL_TAXIS 5
+
+enum lan969x_dsm_cal_dev {
+ DSM_CAL_DEV_2G5,
+ DSM_CAL_DEV_5G,
+ DSM_CAL_DEV_10G,
+ DSM_CAL_DEV_OTHER, /* 1G or less */
+ DSM_CAL_DEV_MAX
+};
+
+/* Each entry in the following struct defines properties for a given speed
+ * (10G, 5G, 2.5G, or 1G or less).
+ */
+struct lan969x_dsm_cal_dev_speed {
+ /* Number of devices that requires this speed. */
+ u32 n_devs;
+
+ /* Array of devices that requires this speed. */
+ u32 devs[LAN969X_DSM_CAL_DEVS_PER_TAXI];
+
+ /* Number of slots required for one device running this speed. */
+ u32 n_slots;
+
+ /* Gap between two slots for one device running this speed. */
+ u32 gap;
+};
+
+static u32
+lan969x_taxi_ports[LAN969X_DSM_CAL_TAXIS][LAN969X_DSM_CAL_DEVS_PER_TAXI] = {
+ { 0, 4, 1, 2, 3, 5, 6, 7, 28, 29 },
+ { 8, 12, 9, 13, 10, 11, 14, 15, 99, 99 },
+ { 16, 20, 17, 21, 18, 19, 22, 23, 99, 99 },
+ { 24, 25, 99, 99, 99, 99, 99, 99, 99, 99 },
+ { 26, 27, 99, 99, 99, 99, 99, 99, 99, 99 }
+};
+
+static int lan969x_dsm_cal_idx_get(u32 *calendar, u32 cal_len, u32 *cal_idx)
+{
+ if (*cal_idx >= cal_len)
+ return -EINVAL;
+
+ do {
+ if (calendar[*cal_idx] == SPX5_DSM_CAL_EMPTY)
+ return 0;
+
+ (*cal_idx)++;
+ } while (*cal_idx < cal_len);
+
+ return -ENOENT;
+}
+
+static enum lan969x_dsm_cal_dev lan969x_dsm_cal_get_dev(int speed)
+{
+ return (speed == 10000 ? DSM_CAL_DEV_10G :
+ speed == 5000 ? DSM_CAL_DEV_5G :
+ speed == 2500 ? DSM_CAL_DEV_2G5 :
+ DSM_CAL_DEV_OTHER);
+}
+
+static int lan969x_dsm_cal_get_speed(enum lan969x_dsm_cal_dev dev)
+{
+ return (dev == DSM_CAL_DEV_10G ? 10000 :
+ dev == DSM_CAL_DEV_5G ? 5000 :
+ dev == DSM_CAL_DEV_2G5 ? 2500 :
+ 1000);
+}
+
+int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
+ struct sparx5_calendar_data *data)
+{
+ struct lan969x_dsm_cal_dev_speed dev_speeds[DSM_CAL_DEV_MAX] = {};
+ u32 cal_len, n_slots, taxi_bw, n_devs = 0, required_bw = 0;
+ struct lan969x_dsm_cal_dev_speed *speed;
+ int err;
+
+ /* Maximum bandwidth for this taxi */
+ taxi_bw = (128 * 1000000) / sparx5_clk_period(sparx5->coreclock);
+
+ memcpy(data->taxi_ports, &lan969x_taxi_ports[taxi],
+ LAN969X_DSM_CAL_DEVS_PER_TAXI * sizeof(u32));
+
+ for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) {
+ u32 portno = data->taxi_ports[i];
+ enum sparx5_cal_bw bw;
+
+ bw = sparx5_get_port_cal_speed(sparx5, portno);
+
+ if (portno < sparx5->data->consts->n_ports_all)
+ data->taxi_speeds[i] = sparx5_cal_speed_to_value(bw);
+ else
+ data->taxi_speeds[i] = 0;
+ }
+
+ /* Determine the different port types (10G, 5G, 2.5G, <= 1G) in the
+ * this taxi map.
+ */
+ for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) {
+ u32 taxi_speed = data->taxi_speeds[i];
+ enum lan969x_dsm_cal_dev dev;
+
+ if (taxi_speed == 0)
+ continue;
+
+ required_bw += taxi_speed;
+
+ dev = lan969x_dsm_cal_get_dev(taxi_speed);
+ speed = &dev_speeds[dev];
+ speed->devs[speed->n_devs++] = i;
+ n_devs++;
+ }
+
+ if (required_bw > taxi_bw) {
+ pr_err("Required bandwidth: %u is higher than total taxi bandwidth: %u",
+ required_bw, taxi_bw);
+ return -EINVAL;
+ }
+
+ if (n_devs == 0) {
+ data->schedule[0] = SPX5_DSM_CAL_EMPTY;
+ return 0;
+ }
+
+ cal_len = n_devs;
+
+ /* Search for a calendar length that fits all active devices. */
+ while (cal_len < SPX5_DSM_CAL_LEN) {
+ u32 bw_per_slot = taxi_bw / cal_len;
+
+ n_slots = 0;
+
+ for (int i = 0; i < DSM_CAL_DEV_MAX; i++) {
+ speed = &dev_speeds[i];
+
+ if (speed->n_devs == 0)
+ continue;
+
+ required_bw = lan969x_dsm_cal_get_speed(i);
+ speed->n_slots = DIV_ROUND_UP(required_bw, bw_per_slot);
+
+ if (speed->n_slots)
+ speed->gap = DIV_ROUND_UP(cal_len,
+ speed->n_slots);
+ else
+ speed->gap = 0;
+
+ n_slots += speed->n_slots * speed->n_devs;
+ }
+
+ if (n_slots <= cal_len)
+ break; /* Found a suitable calendar length. */
+
+ /* Not good enough yet. */
+ cal_len = n_slots;
+ }
+
+ if (cal_len > SPX5_DSM_CAL_LEN) {
+ pr_err("Invalid length: %u for taxi: %u", cal_len, taxi);
+ return -EINVAL;
+ }
+
+ for (u32 i = 0; i < SPX5_DSM_CAL_LEN; i++)
+ data->schedule[i] = SPX5_DSM_CAL_EMPTY;
+
+ /* Place the remaining devices */
+ for (u32 i = 0; i < DSM_CAL_DEV_MAX; i++) {
+ speed = &dev_speeds[i];
+ for (u32 dev = 0; dev < speed->n_devs; dev++) {
+ u32 idx = 0;
+
+ for (n_slots = 0; n_slots < speed->n_slots; n_slots++) {
+ err = lan969x_dsm_cal_idx_get(data->schedule,
+ cal_len, &idx);
+ if (err)
+ return err;
+ data->schedule[idx] = speed->devs[dev];
+ idx += speed->gap;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x_regs.c b/drivers/net/ethernet/microchip/lan969x/lan969x_regs.c
new file mode 100644
index 000000000000..ace4ba21eec4
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x_regs.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip lan969x Switch driver
+ *
+ * Copyright (c) 2024 Microchip Technology Inc.
+ */
+
+/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200.
+ * Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b
+ */
+
+#include "lan969x.h"
+
+const unsigned int lan969x_tsize[TSIZE_LAST] = {
+ [TC_DEV10G] = 10,
+ [TC_DEV2G5] = 28,
+ [TC_DEV5G] = 4,
+ [TC_PCS10G_BR] = 10,
+ [TC_PCS5G_BR] = 4,
+};
+
+const unsigned int lan969x_raddr[RADDR_LAST] = {
+ [RA_CPU_PROC_CTRL] = 160,
+ [RA_GCB_SOFT_RST] = 12,
+ [RA_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 20,
+};
+
+const unsigned int lan969x_rcnt[RCNT_LAST] = {
+ [RC_ANA_AC_OWN_UPSID] = 1,
+ [RC_ANA_ACL_VCAP_S2_CFG] = 35,
+ [RC_ANA_ACL_OWN_UPSID] = 1,
+ [RC_ANA_CL_OWN_UPSID] = 1,
+ [RC_ANA_L2_OWN_UPSID] = 1,
+ [RC_ASM_PORT_CFG] = 32,
+ [RC_DSM_BUF_CFG] = 32,
+ [RC_DSM_DEV_TX_STOP_WM_CFG] = 32,
+ [RC_DSM_RX_PAUSE_CFG] = 32,
+ [RC_DSM_MAC_CFG] = 32,
+ [RC_DSM_MAC_ADDR_BASE_HIGH_CFG] = 30,
+ [RC_DSM_MAC_ADDR_BASE_LOW_CFG] = 30,
+ [RC_DSM_TAXI_CAL_CFG] = 6,
+ [RC_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 30,
+ [RC_HSCH_PORT_MODE] = 35,
+ [RC_QFWD_SWITCH_PORT_MODE] = 35,
+ [RC_QSYS_PAUSE_CFG] = 35,
+ [RC_QSYS_ATOP] = 35,
+ [RC_QSYS_FWD_PRESSURE] = 35,
+ [RC_QSYS_CAL_AUTO] = 4,
+ [RC_REW_OWN_UPSID] = 1,
+ [RC_REW_RTAG_ETAG_CTRL] = 35,
+};
+
+const unsigned int lan969x_gaddr[GADDR_LAST] = {
+ [GA_ANA_AC_RAM_CTRL] = 202000,
+ [GA_ANA_AC_PS_COMMON] = 202880,
+ [GA_ANA_AC_MIRROR_PROBE] = 203232,
+ [GA_ANA_AC_SRC] = 201728,
+ [GA_ANA_AC_PGID] = 131072,
+ [GA_ANA_AC_TSN_SF] = 202028,
+ [GA_ANA_AC_TSN_SF_CFG] = 148480,
+ [GA_ANA_AC_TSN_SF_STATUS] = 147936,
+ [GA_ANA_AC_SG_ACCESS] = 202032,
+ [GA_ANA_AC_SG_CONFIG] = 202752,
+ [GA_ANA_AC_SG_STATUS] = 147952,
+ [GA_ANA_AC_SG_STATUS_STICKY] = 202044,
+ [GA_ANA_AC_STAT_GLOBAL_CFG_PORT] = 202048,
+ [GA_ANA_AC_STAT_CNT_CFG_PORT] = 204800,
+ [GA_ANA_AC_STAT_GLOBAL_CFG_ACL] = 202068,
+ [GA_ANA_ACL_COMMON] = 8192,
+ [GA_ANA_ACL_KEY_SEL] = 9204,
+ [GA_ANA_ACL_CNT_B] = 4096,
+ [GA_ANA_ACL_STICKY] = 10852,
+ [GA_ANA_AC_POL_POL_ALL_CFG] = 17504,
+ [GA_ANA_AC_POL_COMMON_BDLB] = 19464,
+ [GA_ANA_AC_POL_COMMON_BUM_SLB] = 19472,
+ [GA_ANA_AC_SDLB_LBGRP_TBL] = 31788,
+ [GA_ANA_CL_PORT] = 65536,
+ [GA_ANA_CL_COMMON] = 87040,
+ [GA_ANA_L2_COMMON] = 561928,
+ [GA_ANA_L3_COMMON] = 370752,
+ [GA_ANA_L3_VLAN_ARP_L3MC_STICKY] = 368580,
+ [GA_ASM_CFG] = 18304,
+ [GA_ASM_PFC_TIMER_CFG] = 15568,
+ [GA_ASM_LBK_WM_CFG] = 15596,
+ [GA_ASM_LBK_MISC_CFG] = 15608,
+ [GA_ASM_RAM_CTRL] = 15684,
+ [GA_EACL_ES2_KEY_SELECT_PROFILE] = 36864,
+ [GA_EACL_CNT_TBL] = 30720,
+ [GA_EACL_POL_CFG] = 38400,
+ [GA_EACL_ES2_STICKY] = 29072,
+ [GA_EACL_RAM_CTRL] = 29112,
+ [GA_GCB_SIO_CTRL] = 560,
+ [GA_HSCH_HSCH_DWRR] = 36480,
+ [GA_HSCH_HSCH_MISC] = 36608,
+ [GA_HSCH_HSCH_LEAK_LISTS] = 37256,
+ [GA_HSCH_SYSTEM] = 37384,
+ [GA_HSCH_MMGT] = 36260,
+ [GA_HSCH_TAS_CONFIG] = 37696,
+ [GA_PTP_PTP_CFG] = 512,
+ [GA_PTP_PTP_TOD_DOMAINS] = 528,
+ [GA_PTP_PHASE_DETECTOR_CTRL] = 628,
+ [GA_QSYS_CALCFG] = 2164,
+ [GA_QSYS_RAM_CTRL] = 2204,
+ [GA_REW_COMMON] = 98304,
+ [GA_REW_PORT] = 49152,
+ [GA_REW_VOE_PORT_LM_CNT] = 90112,
+ [GA_REW_RAM_CTRL] = 93992,
+ [GA_VOP_RAM_CTRL] = 16368,
+ [GA_XQS_SYSTEM] = 5744,
+ [GA_XQS_QLIMIT_SHR] = 6912,
+};
+
+const unsigned int lan969x_gcnt[GCNT_LAST] = {
+ [GC_ANA_AC_SRC] = 67,
+ [GC_ANA_AC_PGID] = 1054,
+ [GC_ANA_AC_TSN_SF_CFG] = 256,
+ [GC_ANA_AC_STAT_CNT_CFG_PORT] = 35,
+ [GC_ANA_ACL_KEY_SEL] = 99,
+ [GC_ANA_ACL_CNT_A] = 1024,
+ [GC_ANA_ACL_CNT_B] = 1024,
+ [GC_ANA_AC_SDLB_LBGRP_TBL] = 5,
+ [GC_ANA_AC_SDLB_LBSET_TBL] = 496,
+ [GC_ANA_CL_PORT] = 35,
+ [GC_ANA_L2_ISDX_LIMIT] = 256,
+ [GC_ANA_L2_ISDX] = 1024,
+ [GC_ANA_L3_VLAN] = 4608,
+ [GC_ASM_DEV_STATISTICS] = 30,
+ [GC_EACL_ES2_KEY_SELECT_PROFILE] = 68,
+ [GC_EACL_CNT_TBL] = 512,
+ [GC_GCB_SIO_CTRL] = 1,
+ [GC_HSCH_HSCH_CFG] = 1120,
+ [GC_HSCH_HSCH_DWRR] = 32,
+ [GC_PTP_PTP_PINS] = 8,
+ [GC_PTP_PHASE_DETECTOR_CTRL] = 8,
+ [GC_REW_PORT] = 35,
+ [GC_REW_VOE_PORT_LM_CNT] = 240,
+};
+
+const unsigned int lan969x_gsize[GSIZE_LAST] = {
+ [GW_ANA_AC_SRC] = 4,
+ [GW_ANA_L2_COMMON] = 712,
+ [GW_ASM_CFG] = 1092,
+ [GW_CPU_CPU_REGS] = 180,
+ [GW_DEV2G5_PHASE_DETECTOR_CTRL] = 12,
+ [GW_FDMA_FDMA] = 448,
+ [GW_GCB_CHIP_REGS] = 180,
+ [GW_HSCH_TAS_CONFIG] = 16,
+ [GW_PTP_PHASE_DETECTOR_CTRL] = 12,
+ [GW_QSYS_PAUSE_CFG] = 988,
+};
+
+const unsigned int lan969x_fpos[FPOS_LAST] = {
+ [FP_CPU_PROC_CTRL_AARCH64_MODE_ENA] = 7,
+ [FP_CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS] = 6,
+ [FP_CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS] = 5,
+ [FP_CPU_PROC_CTRL_BE_EXCEP_MODE] = 4,
+ [FP_CPU_PROC_CTRL_VINITHI] = 3,
+ [FP_CPU_PROC_CTRL_CFGTE] = 2,
+ [FP_CPU_PROC_CTRL_CP15S_DISABLE] = 1,
+ [FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE] = 0,
+ [FP_CPU_PROC_CTRL_L2_FLUSH_REQ] = 8,
+ [FP_DEV2G5_PHAD_CTRL_PHAD_ENA] = 5,
+ [FP_DEV2G5_PHAD_CTRL_PHAD_FAILED] = 3,
+ [FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE] = 5,
+ [FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY] = 4,
+ [FP_FDMA_CH_CFG_CH_INJ_PORT] = 3,
+ [FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION] = 27,
+ [FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC] = 25,
+ [FP_PTP_PTP_PIN_CFG_PTP_PIN_INV_POL] = 24,
+ [FP_PTP_PHAD_CTRL_PHAD_ENA] = 5,
+ [FP_PTP_PHAD_CTRL_PHAD_FAILED] = 3,
+};
+
+const unsigned int lan969x_fsize[FSIZE_LAST] = {
+ [FW_ANA_AC_PROBE_PORT_CFG_PROBE_PORT_MASK] = 30,
+ [FW_ANA_AC_SRC_CFG_PORT_MASK] = 30,
+ [FW_ANA_AC_PGID_CFG_PORT_MASK] = 30,
+ [FW_ANA_AC_TSN_SF_PORT_NUM] = 7,
+ [FW_ANA_AC_TSN_SF_CFG_TSN_SGID] = 8,
+ [FW_ANA_AC_TSN_SF_STATUS_TSN_SFID] = 8,
+ [FW_ANA_AC_SG_ACCESS_CTRL_SGID] = 8,
+ [FW_ANA_AC_PORT_SGE_CFG_MASK] = 17,
+ [FW_ANA_AC_SDLB_XLB_START_LBSET_START] = 9,
+ [FW_ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT] = 3,
+ [FW_ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT] = 9,
+ [FW_ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT] = 9,
+ [FW_ANA_AC_SDLB_XLB_NEXT_LBGRP] = 3,
+ [FW_ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR] = 9,
+ [FW_ANA_L2_AUTO_LRN_CFG_AUTO_LRN_ENA] = 30,
+ [FW_ANA_L2_DLB_CFG_DLB_IDX] = 9,
+ [FW_ANA_L2_TSN_CFG_TSN_SFID] = 8,
+ [FW_ANA_L3_VLAN_MASK_CFG_VLAN_PORT_MASK] = 30,
+ [FW_FDMA_CH_CFG_CH_DCB_DB_CNT] = 2,
+ [FW_GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL] = 7,
+ [FW_HSCH_SE_CFG_SE_DWRR_CNT] = 5,
+ [FW_HSCH_SE_CONNECT_SE_LEAK_LINK] = 14,
+ [FW_HSCH_SE_DLB_SENSE_SE_DLB_DPORT] = 6,
+ [FW_HSCH_HSCH_CFG_CFG_CFG_SE_IDX] = 11,
+ [FW_HSCH_HSCH_LEAK_CFG_LEAK_FIRST] = 14,
+ [FW_HSCH_FLUSH_CTRL_FLUSH_PORT] = 6,
+ [FW_HSCH_FLUSH_CTRL_FLUSH_HIER] = 14,
+ [FW_LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW] = 13,
+ [FW_LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX] = 8,
+ [FW_LRN_AUTOAGE_CFG_2_NEXT_ROW] = 13,
+ [FW_PTP_PTP_PIN_INTR_INTR_PTP] = 8,
+ [FW_PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA] = 8,
+ [FW_PTP_PTP_INTR_IDENT_INTR_PTP_IDENT] = 8,
+ [FW_PTP_PTP_PIN_CFG_PTP_PIN_SELECT] = 3,
+ [FW_QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL] = 6,
+ [FW_QRES_RES_CFG_WM_HIGH] = 11,
+ [FW_QRES_RES_STAT_MAXUSE] = 19,
+ [FW_QRES_RES_STAT_CUR_INUSE] = 19,
+ [FW_QSYS_PAUSE_CFG_PAUSE_START] = 11,
+ [FW_QSYS_PAUSE_CFG_PAUSE_STOP] = 11,
+ [FW_QSYS_ATOP_ATOP] = 11,
+ [FW_QSYS_ATOP_TOT_CFG_ATOP_TOT] = 11,
+ [FW_REW_RTAG_ETAG_CTRL_IPE_TBL] = 6,
+ [FW_XQS_STAT_CFG_STAT_VIEW] = 10,
+ [FW_XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP] = 14,
+ [FW_XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP] = 14,
+ [FW_XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP] = 14,
+ [FW_XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM] = 14,
+};
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_ag_api.c b/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_ag_api.c
new file mode 100644
index 000000000000..7acc5bcf337a
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_ag_api.c
@@ -0,0 +1,3843 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries.
+ * Microchip VCAP API
+ */
+
+/* This file is autogenerated by cml-utils 2024-10-07 11:10:56 +0200.
+ * Commit ID: b5ddc8e244eb2481a9524f1ddc630a8b41e7c391
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include "lan969x.h"
+
+/* keyfields */
+static const struct vcap_field is0_normal_7tuple_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 1,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_GEN_IDX_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 2,
+ .width = 2,
+ },
+ [VCAP_KF_LOOKUP_GEN_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 4,
+ .width = 10,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U72,
+ .offset = 16,
+ .width = 65,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 81,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 82,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 83,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_TPID0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 86,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 89,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 93,
+ .width = 12,
+ },
+ [VCAP_KF_8021Q_TPID1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 105,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 108,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI1] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 111,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 112,
+ .width = 12,
+ },
+ [VCAP_KF_8021Q_TPID2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 124,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 127,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI2] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 130,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 131,
+ .width = 12,
+ },
+ [VCAP_KF_L2_DMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 144,
+ .width = 48,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 192,
+ .width = 48,
+ },
+ [VCAP_KF_IP_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 240,
+ .width = 1,
+ },
+ [VCAP_KF_ETYPE_LEN_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 241,
+ .width = 1,
+ },
+ [VCAP_KF_ETYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 242,
+ .width = 16,
+ },
+ [VCAP_KF_IP_SNAP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 258,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 259,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 260,
+ .width = 2,
+ },
+ [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 262,
+ .width = 1,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 263,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DSCP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 264,
+ .width = 6,
+ },
+ [VCAP_KF_L3_IP6_DIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 270,
+ .width = 128,
+ },
+ [VCAP_KF_L3_IP6_SIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 398,
+ .width = 128,
+ },
+ [VCAP_KF_TCP_UDP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 526,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 527,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 528,
+ .width = 16,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 544,
+ .width = 8,
+ },
+};
+
+static const struct vcap_field is0_normal_5tuple_ip4_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 2,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 2,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_GEN_IDX_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 3,
+ .width = 2,
+ },
+ [VCAP_KF_LOOKUP_GEN_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 10,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 15,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U72,
+ .offset = 17,
+ .width = 65,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 82,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 83,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_TPID0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 87,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 90,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 93,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID0] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 94,
+ .width = 12,
+ },
+ [VCAP_KF_8021Q_TPID1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 106,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 109,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI1] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 112,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID1] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 113,
+ .width = 12,
+ },
+ [VCAP_KF_8021Q_TPID2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 125,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_PCP2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 128,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI2] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 131,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID2] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 132,
+ .width = 12,
+ },
+ [VCAP_KF_IP_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 145,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 146,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 147,
+ .width = 2,
+ },
+ [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 149,
+ .width = 1,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 150,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DSCP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 151,
+ .width = 6,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 157,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 189,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP_PROTO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 221,
+ .width = 8,
+ },
+ [VCAP_KF_TCP_UDP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 229,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 230,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 231,
+ .width = 8,
+ },
+ [VCAP_KF_IP_PAYLOAD_5TUPLE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 239,
+ .width = 32,
+ },
+};
+
+static const struct vcap_field is2_mac_etype_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 4,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 4,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 32,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 52,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 53,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 54,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 56,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 57,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 80,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 88,
+ .width = 1,
+ },
+ [VCAP_KF_L2_DMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 89,
+ .width = 48,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 137,
+ .width = 48,
+ },
+ [VCAP_KF_ETYPE_LEN_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 185,
+ .width = 1,
+ },
+ [VCAP_KF_ETYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 186,
+ .width = 16,
+ },
+ [VCAP_KF_L2_PAYLOAD_ETYPE] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 202,
+ .width = 64,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 266,
+ .width = 16,
+ },
+ [VCAP_KF_OAM_CCM_CNTS_EQ0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 282,
+ .width = 1,
+ },
+ [VCAP_KF_OAM_Y1731_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 283,
+ .width = 1,
+ },
+};
+
+static const struct vcap_field is2_arp_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 4,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 4,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 32,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 52,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 53,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 54,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 56,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 57,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 80,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 85,
+ .width = 48,
+ },
+ [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 133,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 134,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_LEN_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 135,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_TGT_MATCH_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 136,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_SENDER_MATCH_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 137,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 138,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_OPCODE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 139,
+ .width = 2,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 141,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 173,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 205,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 206,
+ .width = 16,
+ },
+};
+
+static const struct vcap_field is2_ip4_tcp_udp_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 4,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 4,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 32,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 52,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 53,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 54,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 56,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 57,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 80,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 88,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 89,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 90,
+ .width = 2,
+ },
+ [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 93,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 94,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 95,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 103,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 135,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 167,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 168,
+ .width = 1,
+ },
+ [VCAP_KF_L4_DPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 169,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 185,
+ .width = 16,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 201,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 217,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SEQUENCE_EQ0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 218,
+ .width = 1,
+ },
+ [VCAP_KF_L4_FIN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 219,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SYN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 220,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RST] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 221,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PSH] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 222,
+ .width = 1,
+ },
+ [VCAP_KF_L4_ACK] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 223,
+ .width = 1,
+ },
+ [VCAP_KF_L4_URG] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 224,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PAYLOAD] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 225,
+ .width = 64,
+ },
+};
+
+static const struct vcap_field is2_ip4_other_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 4,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 4,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 32,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 52,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 53,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 54,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 56,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 57,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 80,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 88,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 89,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 90,
+ .width = 2,
+ },
+ [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 93,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 94,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 95,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 103,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 135,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 167,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP_PROTO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 168,
+ .width = 8,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 176,
+ .width = 16,
+ },
+ [VCAP_KF_L3_PAYLOAD] = {
+ .type = VCAP_FIELD_U112,
+ .offset = 192,
+ .width = 96,
+ },
+};
+
+static const struct vcap_field is2_ip6_std_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 4,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 4,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 5,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 32,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 52,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 53,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 54,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 56,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 57,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 80,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 89,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP6_SIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 90,
+ .width = 128,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 218,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP_PROTO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 219,
+ .width = 8,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 227,
+ .width = 16,
+ },
+ [VCAP_KF_L3_PAYLOAD] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 243,
+ .width = 40,
+ },
+};
+
+static const struct vcap_field is2_ip_7tuple_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 2,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 2,
+ .width = 1,
+ },
+ [VCAP_KF_LOOKUP_PAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 3,
+ .width = 8,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 11,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 12,
+ .width = 4,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 2,
+ },
+ [VCAP_KF_IF_IGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U72,
+ .offset = 18,
+ .width = 65,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 83,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 85,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 98,
+ .width = 13,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 111,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 112,
+ .width = 3,
+ },
+ [VCAP_KF_L2_FWD_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 115,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 118,
+ .width = 1,
+ },
+ [VCAP_KF_L3_DST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 119,
+ .width = 1,
+ },
+ [VCAP_KF_L2_DMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 120,
+ .width = 48,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 168,
+ .width = 48,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 218,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 219,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 220,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP6_DIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 228,
+ .width = 128,
+ },
+ [VCAP_KF_L3_IP6_SIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 356,
+ .width = 128,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 484,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_UDP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 485,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 486,
+ .width = 1,
+ },
+ [VCAP_KF_L4_DPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 487,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 503,
+ .width = 16,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 519,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 535,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SEQUENCE_EQ0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 536,
+ .width = 1,
+ },
+ [VCAP_KF_L4_FIN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 537,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SYN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 538,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RST] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 539,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PSH] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 540,
+ .width = 1,
+ },
+ [VCAP_KF_L4_ACK] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 541,
+ .width = 1,
+ },
+ [VCAP_KF_L4_URG] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 542,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PAYLOAD] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 543,
+ .width = 64,
+ },
+};
+
+static const struct vcap_field es0_isdx_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_KF_IF_EGR_PORT_NO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 1,
+ .width = 6,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 7,
+ .width = 13,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 20,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_TPID] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 23,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 27,
+ .width = 1,
+ },
+ [VCAP_KF_PROT_ACTIVE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 28,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 38,
+ .width = 10,
+ },
+};
+
+static const struct vcap_field es2_mac_etype_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 3,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 3,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 14,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 44,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 76,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 77,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 91,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_L2_DMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 96,
+ .width = 48,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 144,
+ .width = 48,
+ },
+ [VCAP_KF_ETYPE_LEN_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 192,
+ .width = 1,
+ },
+ [VCAP_KF_ETYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 193,
+ .width = 16,
+ },
+ [VCAP_KF_L2_PAYLOAD_ETYPE] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 209,
+ .width = 64,
+ },
+ [VCAP_KF_OAM_CCM_CNTS_EQ0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 273,
+ .width = 1,
+ },
+ [VCAP_KF_OAM_Y1731_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 274,
+ .width = 1,
+ },
+};
+
+static const struct vcap_field es2_arp_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 3,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 3,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 14,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 44,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 76,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 77,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 91,
+ .width = 1,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 95,
+ .width = 48,
+ },
+ [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 143,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 144,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_LEN_OK_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 145,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_TGT_MATCH_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 146,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_SENDER_MATCH_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 147,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 148,
+ .width = 1,
+ },
+ [VCAP_KF_ARP_OPCODE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 149,
+ .width = 2,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 151,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 183,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 215,
+ .width = 1,
+ },
+};
+
+static const struct vcap_field es2_ip4_tcp_udp_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 3,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 3,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 14,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 44,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 76,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 77,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 91,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 96,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 97,
+ .width = 2,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 99,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 100,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 101,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 109,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 141,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 173,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 174,
+ .width = 1,
+ },
+ [VCAP_KF_L4_DPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 175,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 191,
+ .width = 16,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 207,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 223,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SEQUENCE_EQ0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 224,
+ .width = 1,
+ },
+ [VCAP_KF_L4_FIN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 225,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SYN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 226,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RST] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 227,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PSH] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 228,
+ .width = 1,
+ },
+ [VCAP_KF_L4_ACK] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 229,
+ .width = 1,
+ },
+ [VCAP_KF_L4_URG] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 230,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PAYLOAD] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 231,
+ .width = 64,
+ },
+};
+
+static const struct vcap_field es2_ip4_other_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 3,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 3,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 14,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 44,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 76,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 77,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 91,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 96,
+ .width = 1,
+ },
+ [VCAP_KF_L3_FRAGMENT_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 97,
+ .width = 2,
+ },
+ [VCAP_KF_L3_OPTIONS_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 99,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 100,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 101,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP4_DIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 109,
+ .width = 32,
+ },
+ [VCAP_KF_L3_IP4_SIP] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 141,
+ .width = 32,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 173,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP_PROTO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 174,
+ .width = 8,
+ },
+ [VCAP_KF_L3_PAYLOAD] = {
+ .type = VCAP_FIELD_U112,
+ .offset = 182,
+ .width = 96,
+ },
+};
+
+static const struct vcap_field es2_ip_7tuple_keyfield[] = {
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 10,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 11,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 12,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 13,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 23,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 25,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 38,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 73,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 74,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 81,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 85,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 88,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 89,
+ .width = 1,
+ },
+ [VCAP_KF_L2_DMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 93,
+ .width = 48,
+ },
+ [VCAP_KF_L2_SMAC] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 141,
+ .width = 48,
+ },
+ [VCAP_KF_IP4_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 191,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 192,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TOS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 193,
+ .width = 8,
+ },
+ [VCAP_KF_L3_IP6_DIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 201,
+ .width = 128,
+ },
+ [VCAP_KF_L3_IP6_SIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 329,
+ .width = 128,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 457,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_UDP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 458,
+ .width = 1,
+ },
+ [VCAP_KF_TCP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 459,
+ .width = 1,
+ },
+ [VCAP_KF_L4_DPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 460,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 476,
+ .width = 16,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 492,
+ .width = 16,
+ },
+ [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 508,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SEQUENCE_EQ0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 509,
+ .width = 1,
+ },
+ [VCAP_KF_L4_FIN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 510,
+ .width = 1,
+ },
+ [VCAP_KF_L4_SYN] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 511,
+ .width = 1,
+ },
+ [VCAP_KF_L4_RST] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 512,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PSH] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 513,
+ .width = 1,
+ },
+ [VCAP_KF_L4_ACK] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 514,
+ .width = 1,
+ },
+ [VCAP_KF_L4_URG] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 515,
+ .width = 1,
+ },
+ [VCAP_KF_L4_PAYLOAD] = {
+ .type = VCAP_FIELD_U64,
+ .offset = 516,
+ .width = 64,
+ },
+};
+
+static const struct vcap_field es2_ip6_std_keyfield[] = {
+ [VCAP_KF_TYPE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 3,
+ },
+ [VCAP_KF_LOOKUP_FIRST_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 3,
+ .width = 1,
+ },
+ [VCAP_KF_L2_MC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 13,
+ .width = 1,
+ },
+ [VCAP_KF_L2_BC_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 14,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_GT0_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_KF_ISDX_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 10,
+ },
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_KF_8021Q_VID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 13,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 41,
+ .width = 3,
+ },
+ [VCAP_KF_IF_EGR_PORT_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 44,
+ .width = 32,
+ },
+ [VCAP_KF_IF_IGR_PORT_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 76,
+ .width = 1,
+ },
+ [VCAP_KF_IF_IGR_PORT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 77,
+ .width = 7,
+ },
+ [VCAP_KF_8021Q_PCP_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 84,
+ .width = 3,
+ },
+ [VCAP_KF_8021Q_DEI_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 87,
+ .width = 1,
+ },
+ [VCAP_KF_COSID_CLS] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 88,
+ .width = 3,
+ },
+ [VCAP_KF_L3_DPL_CLS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 91,
+ .width = 1,
+ },
+ [VCAP_KF_L3_RT_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 92,
+ .width = 1,
+ },
+ [VCAP_KF_L3_TTL_GT0] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 96,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP6_SIP] = {
+ .type = VCAP_FIELD_U128,
+ .offset = 97,
+ .width = 128,
+ },
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 225,
+ .width = 1,
+ },
+ [VCAP_KF_L3_IP_PROTO] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 226,
+ .width = 8,
+ },
+ [VCAP_KF_L4_RNG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 234,
+ .width = 16,
+ },
+ [VCAP_KF_L3_PAYLOAD] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 250,
+ .width = 40,
+ },
+};
+
+/* keyfield_set */
+static const struct vcap_set is0_keyfield_set[] = {
+ [VCAP_KFS_NORMAL_7TUPLE] = {
+ .type_id = 0,
+ .sw_per_item = 12,
+ .sw_cnt = 1,
+ },
+ [VCAP_KFS_NORMAL_5TUPLE_IP4] = {
+ .type_id = 2,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+};
+
+static const struct vcap_set is2_keyfield_set[] = {
+ [VCAP_KFS_MAC_ETYPE] = {
+ .type_id = 0,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_ARP] = {
+ .type_id = 3,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP4_TCP_UDP] = {
+ .type_id = 4,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP4_OTHER] = {
+ .type_id = 5,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP6_STD] = {
+ .type_id = 6,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP_7TUPLE] = {
+ .type_id = 1,
+ .sw_per_item = 12,
+ .sw_cnt = 1,
+ },
+};
+
+static const struct vcap_set es0_keyfield_set[] = {
+ [VCAP_KFS_ISDX] = {
+ .type_id = 0,
+ .sw_per_item = 1,
+ .sw_cnt = 1,
+ },
+};
+
+static const struct vcap_set es2_keyfield_set[] = {
+ [VCAP_KFS_MAC_ETYPE] = {
+ .type_id = 0,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_ARP] = {
+ .type_id = 1,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP4_TCP_UDP] = {
+ .type_id = 2,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP4_OTHER] = {
+ .type_id = 3,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+ [VCAP_KFS_IP_7TUPLE] = {
+ .type_id = -1,
+ .sw_per_item = 12,
+ .sw_cnt = 1,
+ },
+ [VCAP_KFS_IP6_STD] = {
+ .type_id = 4,
+ .sw_per_item = 6,
+ .sw_cnt = 2,
+ },
+};
+
+/* keyfield_set map */
+static const struct vcap_field *is0_keyfield_set_map[] = {
+ [VCAP_KFS_NORMAL_7TUPLE] = is0_normal_7tuple_keyfield,
+ [VCAP_KFS_NORMAL_5TUPLE_IP4] = is0_normal_5tuple_ip4_keyfield,
+};
+
+static const struct vcap_field *is2_keyfield_set_map[] = {
+ [VCAP_KFS_MAC_ETYPE] = is2_mac_etype_keyfield,
+ [VCAP_KFS_ARP] = is2_arp_keyfield,
+ [VCAP_KFS_IP4_TCP_UDP] = is2_ip4_tcp_udp_keyfield,
+ [VCAP_KFS_IP4_OTHER] = is2_ip4_other_keyfield,
+ [VCAP_KFS_IP6_STD] = is2_ip6_std_keyfield,
+ [VCAP_KFS_IP_7TUPLE] = is2_ip_7tuple_keyfield,
+};
+
+static const struct vcap_field *es0_keyfield_set_map[] = {
+ [VCAP_KFS_ISDX] = es0_isdx_keyfield,
+};
+
+static const struct vcap_field *es2_keyfield_set_map[] = {
+ [VCAP_KFS_MAC_ETYPE] = es2_mac_etype_keyfield,
+ [VCAP_KFS_ARP] = es2_arp_keyfield,
+ [VCAP_KFS_IP4_TCP_UDP] = es2_ip4_tcp_udp_keyfield,
+ [VCAP_KFS_IP4_OTHER] = es2_ip4_other_keyfield,
+ [VCAP_KFS_IP_7TUPLE] = es2_ip_7tuple_keyfield,
+ [VCAP_KFS_IP6_STD] = es2_ip6_std_keyfield,
+};
+
+/* keyfield_set map sizes */
+static int is0_keyfield_set_map_size[] = {
+ [VCAP_KFS_NORMAL_7TUPLE] = ARRAY_SIZE(is0_normal_7tuple_keyfield),
+ [VCAP_KFS_NORMAL_5TUPLE_IP4] = ARRAY_SIZE(is0_normal_5tuple_ip4_keyfield),
+};
+
+static int is2_keyfield_set_map_size[] = {
+ [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(is2_mac_etype_keyfield),
+ [VCAP_KFS_ARP] = ARRAY_SIZE(is2_arp_keyfield),
+ [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(is2_ip4_tcp_udp_keyfield),
+ [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(is2_ip4_other_keyfield),
+ [VCAP_KFS_IP6_STD] = ARRAY_SIZE(is2_ip6_std_keyfield),
+ [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(is2_ip_7tuple_keyfield),
+};
+
+static int es0_keyfield_set_map_size[] = {
+ [VCAP_KFS_ISDX] = ARRAY_SIZE(es0_isdx_keyfield),
+};
+
+static int es2_keyfield_set_map_size[] = {
+ [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(es2_mac_etype_keyfield),
+ [VCAP_KFS_ARP] = ARRAY_SIZE(es2_arp_keyfield),
+ [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(es2_ip4_tcp_udp_keyfield),
+ [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(es2_ip4_other_keyfield),
+ [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(es2_ip_7tuple_keyfield),
+ [VCAP_KFS_IP6_STD] = ARRAY_SIZE(es2_ip6_std_keyfield),
+};
+
+/* actionfields */
+static const struct vcap_field is0_classification_actionfield[] = {
+ [VCAP_AF_TYPE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_AF_DSCP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 1,
+ .width = 1,
+ },
+ [VCAP_AF_DSCP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 2,
+ .width = 6,
+ },
+ [VCAP_AF_QOS_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 12,
+ .width = 1,
+ },
+ [VCAP_AF_QOS_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 13,
+ .width = 3,
+ },
+ [VCAP_AF_DP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 16,
+ .width = 1,
+ },
+ [VCAP_AF_DP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 17,
+ .width = 2,
+ },
+ [VCAP_AF_DEI_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 19,
+ .width = 1,
+ },
+ [VCAP_AF_DEI_VAL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 20,
+ .width = 1,
+ },
+ [VCAP_AF_PCP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 21,
+ .width = 1,
+ },
+ [VCAP_AF_PCP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 22,
+ .width = 3,
+ },
+ [VCAP_AF_MAP_LOOKUP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 25,
+ .width = 2,
+ },
+ [VCAP_AF_MAP_KEY] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 27,
+ .width = 3,
+ },
+ [VCAP_AF_MAP_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 30,
+ .width = 7,
+ },
+ [VCAP_AF_CLS_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 37,
+ .width = 3,
+ },
+ [VCAP_AF_VID_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 43,
+ .width = 13,
+ },
+ [VCAP_AF_ISDX_ADD_REPLACE_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 66,
+ .width = 1,
+ },
+ [VCAP_AF_ISDX_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 67,
+ .width = 10,
+ },
+ [VCAP_AF_PAG_OVERRIDE_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 107,
+ .width = 8,
+ },
+ [VCAP_AF_PAG_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 115,
+ .width = 8,
+ },
+ [VCAP_AF_NXT_IDX_CTRL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 167,
+ .width = 3,
+ },
+ [VCAP_AF_NXT_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 170,
+ .width = 10,
+ },
+};
+
+static const struct vcap_field is0_full_actionfield[] = {
+ [VCAP_AF_DSCP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_AF_DSCP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 1,
+ .width = 6,
+ },
+ [VCAP_AF_QOS_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 11,
+ .width = 1,
+ },
+ [VCAP_AF_QOS_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 12,
+ .width = 3,
+ },
+ [VCAP_AF_DP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_AF_DP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 16,
+ .width = 2,
+ },
+ [VCAP_AF_DEI_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 18,
+ .width = 1,
+ },
+ [VCAP_AF_DEI_VAL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 19,
+ .width = 1,
+ },
+ [VCAP_AF_PCP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 20,
+ .width = 1,
+ },
+ [VCAP_AF_PCP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 21,
+ .width = 3,
+ },
+ [VCAP_AF_MAP_LOOKUP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 24,
+ .width = 2,
+ },
+ [VCAP_AF_MAP_KEY] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 26,
+ .width = 3,
+ },
+ [VCAP_AF_MAP_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 29,
+ .width = 7,
+ },
+ [VCAP_AF_CLS_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 36,
+ .width = 3,
+ },
+ [VCAP_AF_VID_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 42,
+ .width = 13,
+ },
+ [VCAP_AF_ISDX_ADD_REPLACE_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 65,
+ .width = 1,
+ },
+ [VCAP_AF_ISDX_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 66,
+ .width = 10,
+ },
+ [VCAP_AF_MASK_MODE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 76,
+ .width = 3,
+ },
+ [VCAP_AF_PORT_MASK] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 79,
+ .width = 37,
+ },
+ [VCAP_AF_PAG_OVERRIDE_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 174,
+ .width = 8,
+ },
+ [VCAP_AF_PAG_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 182,
+ .width = 8,
+ },
+ [VCAP_AF_NXT_IDX_CTRL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 266,
+ .width = 3,
+ },
+ [VCAP_AF_NXT_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 269,
+ .width = 10,
+ },
+};
+
+static const struct vcap_field is0_class_reduced_actionfield[] = {
+ [VCAP_AF_TYPE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_AF_QOS_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 5,
+ .width = 1,
+ },
+ [VCAP_AF_QOS_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 6,
+ .width = 3,
+ },
+ [VCAP_AF_DP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 9,
+ .width = 1,
+ },
+ [VCAP_AF_DP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 10,
+ .width = 2,
+ },
+ [VCAP_AF_MAP_LOOKUP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 12,
+ .width = 2,
+ },
+ [VCAP_AF_MAP_KEY] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 3,
+ },
+ [VCAP_AF_CLS_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 17,
+ .width = 3,
+ },
+ [VCAP_AF_VID_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 23,
+ .width = 13,
+ },
+ [VCAP_AF_ISDX_ADD_REPLACE_SEL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 46,
+ .width = 1,
+ },
+ [VCAP_AF_ISDX_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 47,
+ .width = 10,
+ },
+ [VCAP_AF_NXT_IDX_CTRL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 89,
+ .width = 3,
+ },
+ [VCAP_AF_NXT_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 92,
+ .width = 10,
+ },
+};
+
+static const struct vcap_field is2_base_type_actionfield[] = {
+ [VCAP_AF_PIPELINE_FORCE_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 1,
+ .width = 1,
+ },
+ [VCAP_AF_PIPELINE_PT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 2,
+ .width = 5,
+ },
+ [VCAP_AF_HIT_ME_ONCE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 7,
+ .width = 1,
+ },
+ [VCAP_AF_INTR_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 8,
+ .width = 1,
+ },
+ [VCAP_AF_CPU_COPY_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 9,
+ .width = 1,
+ },
+ [VCAP_AF_CPU_QUEUE_NUM] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 10,
+ .width = 3,
+ },
+ [VCAP_AF_LRN_DIS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 15,
+ .width = 1,
+ },
+ [VCAP_AF_RT_DIS] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 16,
+ .width = 1,
+ },
+ [VCAP_AF_POLICE_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 17,
+ .width = 1,
+ },
+ [VCAP_AF_POLICE_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 5,
+ },
+ [VCAP_AF_IGNORE_PIPELINE_CTRL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 23,
+ .width = 1,
+ },
+ [VCAP_AF_MASK_MODE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 27,
+ .width = 3,
+ },
+ [VCAP_AF_PORT_MASK] = {
+ .type = VCAP_FIELD_U48,
+ .offset = 30,
+ .width = 37,
+ },
+ [VCAP_AF_MIRROR_PROBE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 78,
+ .width = 2,
+ },
+ [VCAP_AF_MATCH_ID] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 131,
+ .width = 16,
+ },
+ [VCAP_AF_MATCH_ID_MASK] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 147,
+ .width = 16,
+ },
+ [VCAP_AF_CNT_ID] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 163,
+ .width = 10,
+ },
+};
+
+static const struct vcap_field es0_es0_actionfield[] = {
+ [VCAP_AF_PUSH_OUTER_TAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 0,
+ .width = 2,
+ },
+ [VCAP_AF_PUSH_INNER_TAG] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 2,
+ .width = 1,
+ },
+ [VCAP_AF_TAG_A_TPID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 3,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_A_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 6,
+ .width = 2,
+ },
+ [VCAP_AF_TAG_A_PCP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 8,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_A_DEI_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 11,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_B_TPID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 14,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_B_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 17,
+ .width = 2,
+ },
+ [VCAP_AF_TAG_B_PCP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 19,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_B_DEI_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 22,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_C_TPID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 25,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_C_PCP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 28,
+ .width = 3,
+ },
+ [VCAP_AF_TAG_C_DEI_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 31,
+ .width = 3,
+ },
+ [VCAP_AF_VID_A_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 34,
+ .width = 12,
+ },
+ [VCAP_AF_PCP_A_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 46,
+ .width = 3,
+ },
+ [VCAP_AF_DEI_A_VAL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 49,
+ .width = 1,
+ },
+ [VCAP_AF_VID_B_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 50,
+ .width = 12,
+ },
+ [VCAP_AF_PCP_B_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 62,
+ .width = 3,
+ },
+ [VCAP_AF_DEI_B_VAL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 65,
+ .width = 1,
+ },
+ [VCAP_AF_VID_C_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 66,
+ .width = 12,
+ },
+ [VCAP_AF_PCP_C_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 78,
+ .width = 3,
+ },
+ [VCAP_AF_DEI_C_VAL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 81,
+ .width = 1,
+ },
+ [VCAP_AF_POP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 82,
+ .width = 2,
+ },
+ [VCAP_AF_UNTAG_VID_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 84,
+ .width = 1,
+ },
+ [VCAP_AF_PUSH_CUSTOMER_TAG] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 85,
+ .width = 2,
+ },
+ [VCAP_AF_TAG_C_VID_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 87,
+ .width = 2,
+ },
+ [VCAP_AF_DSCP_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 127,
+ .width = 3,
+ },
+ [VCAP_AF_DSCP_VAL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 130,
+ .width = 6,
+ },
+ [VCAP_AF_ESDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 319,
+ .width = 10,
+ },
+ [VCAP_AF_FWD_SEL] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 438,
+ .width = 2,
+ },
+ [VCAP_AF_CPU_QU] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 440,
+ .width = 3,
+ },
+ [VCAP_AF_PIPELINE_PT] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 443,
+ .width = 2,
+ },
+ [VCAP_AF_PIPELINE_ACT] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 445,
+ .width = 1,
+ },
+ [VCAP_AF_SWAP_MACS_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 454,
+ .width = 1,
+ },
+ [VCAP_AF_LOOP_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 455,
+ .width = 1,
+ },
+};
+
+static const struct vcap_field es2_base_type_actionfield[] = {
+ [VCAP_AF_HIT_ME_ONCE] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 0,
+ .width = 1,
+ },
+ [VCAP_AF_INTR_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 1,
+ .width = 1,
+ },
+ [VCAP_AF_FWD_MODE] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 2,
+ .width = 2,
+ },
+ [VCAP_AF_COPY_QUEUE_NUM] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 4,
+ .width = 14,
+ },
+ [VCAP_AF_COPY_PORT_NUM] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 18,
+ .width = 6,
+ },
+ [VCAP_AF_MIRROR_PROBE_ID] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 24,
+ .width = 2,
+ },
+ [VCAP_AF_CPU_COPY_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 26,
+ .width = 1,
+ },
+ [VCAP_AF_CPU_QUEUE_NUM] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 27,
+ .width = 3,
+ },
+ [VCAP_AF_POLICE_ENA] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 30,
+ .width = 1,
+ },
+ [VCAP_AF_POLICE_REMARK] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 31,
+ .width = 1,
+ },
+ [VCAP_AF_POLICE_IDX] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 32,
+ .width = 5,
+ },
+ [VCAP_AF_ES2_REW_CMD] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 37,
+ .width = 3,
+ },
+ [VCAP_AF_CNT_ID] = {
+ .type = VCAP_FIELD_U32,
+ .offset = 40,
+ .width = 9,
+ },
+ [VCAP_AF_IGNORE_PIPELINE_CTRL] = {
+ .type = VCAP_FIELD_BIT,
+ .offset = 49,
+ .width = 1,
+ },
+};
+
+/* actionfield_set */
+static const struct vcap_set is0_actionfield_set[] = {
+ [VCAP_AFS_CLASSIFICATION] = {
+ .type_id = 1,
+ .sw_per_item = 2,
+ .sw_cnt = 6,
+ },
+ [VCAP_AFS_FULL] = {
+ .type_id = -1,
+ .sw_per_item = 3,
+ .sw_cnt = 4,
+ },
+ [VCAP_AFS_CLASS_REDUCED] = {
+ .type_id = 1,
+ .sw_per_item = 1,
+ .sw_cnt = 12,
+ },
+};
+
+static const struct vcap_set is2_actionfield_set[] = {
+ [VCAP_AFS_BASE_TYPE] = {
+ .type_id = -1,
+ .sw_per_item = 3,
+ .sw_cnt = 4,
+ },
+};
+
+static const struct vcap_set es0_actionfield_set[] = {
+ [VCAP_AFS_ES0] = {
+ .type_id = -1,
+ .sw_per_item = 1,
+ .sw_cnt = 1,
+ },
+};
+
+static const struct vcap_set es2_actionfield_set[] = {
+ [VCAP_AFS_BASE_TYPE] = {
+ .type_id = -1,
+ .sw_per_item = 3,
+ .sw_cnt = 4,
+ },
+};
+
+/* actionfield_set map */
+static const struct vcap_field *is0_actionfield_set_map[] = {
+ [VCAP_AFS_CLASSIFICATION] = is0_classification_actionfield,
+ [VCAP_AFS_FULL] = is0_full_actionfield,
+ [VCAP_AFS_CLASS_REDUCED] = is0_class_reduced_actionfield,
+};
+
+static const struct vcap_field *is2_actionfield_set_map[] = {
+ [VCAP_AFS_BASE_TYPE] = is2_base_type_actionfield,
+};
+
+static const struct vcap_field *es0_actionfield_set_map[] = {
+ [VCAP_AFS_ES0] = es0_es0_actionfield,
+};
+
+static const struct vcap_field *es2_actionfield_set_map[] = {
+ [VCAP_AFS_BASE_TYPE] = es2_base_type_actionfield,
+};
+
+/* actionfield_set map size */
+static int is0_actionfield_set_map_size[] = {
+ [VCAP_AFS_CLASSIFICATION] = ARRAY_SIZE(is0_classification_actionfield),
+ [VCAP_AFS_FULL] = ARRAY_SIZE(is0_full_actionfield),
+ [VCAP_AFS_CLASS_REDUCED] = ARRAY_SIZE(is0_class_reduced_actionfield),
+};
+
+static int is2_actionfield_set_map_size[] = {
+ [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(is2_base_type_actionfield),
+};
+
+static int es0_actionfield_set_map_size[] = {
+ [VCAP_AFS_ES0] = ARRAY_SIZE(es0_es0_actionfield),
+};
+
+static int es2_actionfield_set_map_size[] = {
+ [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(es2_base_type_actionfield),
+};
+
+/* Type Groups */
+static const struct vcap_typegroup is0_x12_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 5,
+ .value = 16,
+ },
+ {
+ .offset = 52,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 104,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 156,
+ .width = 3,
+ .value = 0,
+ },
+ {
+ .offset = 208,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 260,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 312,
+ .width = 4,
+ .value = 0,
+ },
+ {
+ .offset = 364,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 416,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 468,
+ .width = 3,
+ .value = 0,
+ },
+ {
+ .offset = 520,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 572,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is0_x6_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 4,
+ .value = 8,
+ },
+ {
+ .offset = 52,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 104,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 156,
+ .width = 3,
+ .value = 0,
+ },
+ {
+ .offset = 208,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 260,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is0_x3_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup is0_x2_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup is0_x1_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup is2_x12_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 3,
+ .value = 4,
+ },
+ {
+ .offset = 156,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 312,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 468,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is2_x6_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 2,
+ .value = 2,
+ },
+ {
+ .offset = 156,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is2_x3_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup is2_x1_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup es0_x1_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup es2_x12_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 3,
+ .value = 4,
+ },
+ {
+ .offset = 156,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 312,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 468,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup es2_x6_keyfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 2,
+ .value = 2,
+ },
+ {
+ .offset = 156,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup es2_x3_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup es2_x1_keyfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup *is0_keyfield_set_typegroups[] = {
+ [12] = is0_x12_keyfield_set_typegroups,
+ [6] = is0_x6_keyfield_set_typegroups,
+ [3] = is0_x3_keyfield_set_typegroups,
+ [2] = is0_x2_keyfield_set_typegroups,
+ [1] = is0_x1_keyfield_set_typegroups,
+ [13] = NULL,
+};
+
+static const struct vcap_typegroup *is2_keyfield_set_typegroups[] = {
+ [12] = is2_x12_keyfield_set_typegroups,
+ [6] = is2_x6_keyfield_set_typegroups,
+ [3] = is2_x3_keyfield_set_typegroups,
+ [1] = is2_x1_keyfield_set_typegroups,
+ [13] = NULL,
+};
+
+static const struct vcap_typegroup *es0_keyfield_set_typegroups[] = {
+ [1] = es0_x1_keyfield_set_typegroups,
+ [2] = NULL,
+};
+
+static const struct vcap_typegroup *es2_keyfield_set_typegroups[] = {
+ [12] = es2_x12_keyfield_set_typegroups,
+ [6] = es2_x6_keyfield_set_typegroups,
+ [3] = es2_x3_keyfield_set_typegroups,
+ [1] = es2_x1_keyfield_set_typegroups,
+ [13] = NULL,
+};
+
+static const struct vcap_typegroup is0_x3_actionfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 3,
+ .value = 4,
+ },
+ {
+ .offset = 103,
+ .width = 2,
+ .value = 0,
+ },
+ {
+ .offset = 206,
+ .width = 2,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is0_x2_actionfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 2,
+ .value = 2,
+ },
+ {
+ .offset = 103,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is0_x1_actionfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 1,
+ .value = 1,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is2_x3_actionfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 2,
+ .value = 2,
+ },
+ {
+ .offset = 95,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 190,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup is2_x1_actionfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup es0_x1_actionfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup es2_x3_actionfield_set_typegroups[] = {
+ {
+ .offset = 0,
+ .width = 2,
+ .value = 2,
+ },
+ {
+ .offset = 19,
+ .width = 1,
+ .value = 0,
+ },
+ {
+ .offset = 38,
+ .width = 1,
+ .value = 0,
+ },
+ {}
+};
+
+static const struct vcap_typegroup es2_x1_actionfield_set_typegroups[] = {
+ {}
+};
+
+static const struct vcap_typegroup *is0_actionfield_set_typegroups[] = {
+ [3] = is0_x3_actionfield_set_typegroups,
+ [2] = is0_x2_actionfield_set_typegroups,
+ [1] = is0_x1_actionfield_set_typegroups,
+ [13] = NULL,
+};
+
+static const struct vcap_typegroup *is2_actionfield_set_typegroups[] = {
+ [3] = is2_x3_actionfield_set_typegroups,
+ [1] = is2_x1_actionfield_set_typegroups,
+ [13] = NULL,
+};
+
+static const struct vcap_typegroup *es0_actionfield_set_typegroups[] = {
+ [1] = es0_x1_actionfield_set_typegroups,
+ [2] = NULL,
+};
+
+static const struct vcap_typegroup *es2_actionfield_set_typegroups[] = {
+ [3] = es2_x3_actionfield_set_typegroups,
+ [1] = es2_x1_actionfield_set_typegroups,
+ [13] = NULL,
+};
+
+/* Keyfieldset names */
+static const char * const vcap_keyfield_set_names[] = {
+ [VCAP_KFS_NO_VALUE] = "(None)",
+ [VCAP_KFS_ARP] = "VCAP_KFS_ARP",
+ [VCAP_KFS_ETAG] = "VCAP_KFS_ETAG",
+ [VCAP_KFS_IP4_OTHER] = "VCAP_KFS_IP4_OTHER",
+ [VCAP_KFS_IP4_TCP_UDP] = "VCAP_KFS_IP4_TCP_UDP",
+ [VCAP_KFS_IP4_VID] = "VCAP_KFS_IP4_VID",
+ [VCAP_KFS_IP6_OTHER] = "VCAP_KFS_IP6_OTHER",
+ [VCAP_KFS_IP6_STD] = "VCAP_KFS_IP6_STD",
+ [VCAP_KFS_IP6_TCP_UDP] = "VCAP_KFS_IP6_TCP_UDP",
+ [VCAP_KFS_IP6_VID] = "VCAP_KFS_IP6_VID",
+ [VCAP_KFS_IP_7TUPLE] = "VCAP_KFS_IP_7TUPLE",
+ [VCAP_KFS_ISDX] = "VCAP_KFS_ISDX",
+ [VCAP_KFS_LL_FULL] = "VCAP_KFS_LL_FULL",
+ [VCAP_KFS_MAC_ETYPE] = "VCAP_KFS_MAC_ETYPE",
+ [VCAP_KFS_MAC_LLC] = "VCAP_KFS_MAC_LLC",
+ [VCAP_KFS_MAC_SNAP] = "VCAP_KFS_MAC_SNAP",
+ [VCAP_KFS_NORMAL_5TUPLE_IP4] = "VCAP_KFS_NORMAL_5TUPLE_IP4",
+ [VCAP_KFS_NORMAL_7TUPLE] = "VCAP_KFS_NORMAL_7TUPLE",
+ [VCAP_KFS_OAM] = "VCAP_KFS_OAM",
+ [VCAP_KFS_PURE_5TUPLE_IP4] = "VCAP_KFS_PURE_5TUPLE_IP4",
+ [VCAP_KFS_SMAC_SIP4] = "VCAP_KFS_SMAC_SIP4",
+ [VCAP_KFS_SMAC_SIP6] = "VCAP_KFS_SMAC_SIP6",
+};
+
+/* Actionfieldset names */
+static const char * const vcap_actionfield_set_names[] = {
+ [VCAP_AFS_NO_VALUE] = "(None)",
+ [VCAP_AFS_BASE_TYPE] = "VCAP_AFS_BASE_TYPE",
+ [VCAP_AFS_CLASSIFICATION] = "VCAP_AFS_CLASSIFICATION",
+ [VCAP_AFS_CLASS_REDUCED] = "VCAP_AFS_CLASS_REDUCED",
+ [VCAP_AFS_ES0] = "VCAP_AFS_ES0",
+ [VCAP_AFS_FULL] = "VCAP_AFS_FULL",
+ [VCAP_AFS_SMAC_SIP] = "VCAP_AFS_SMAC_SIP",
+};
+
+/* Keyfield names */
+static const char * const vcap_keyfield_names[] = {
+ [VCAP_KF_NO_VALUE] = "(None)",
+ [VCAP_KF_8021BR_ECID_BASE] = "8021BR_ECID_BASE",
+ [VCAP_KF_8021BR_ECID_EXT] = "8021BR_ECID_EXT",
+ [VCAP_KF_8021BR_E_TAGGED] = "8021BR_E_TAGGED",
+ [VCAP_KF_8021BR_GRP] = "8021BR_GRP",
+ [VCAP_KF_8021BR_IGR_ECID_BASE] = "8021BR_IGR_ECID_BASE",
+ [VCAP_KF_8021BR_IGR_ECID_EXT] = "8021BR_IGR_ECID_EXT",
+ [VCAP_KF_8021Q_DEI0] = "8021Q_DEI0",
+ [VCAP_KF_8021Q_DEI1] = "8021Q_DEI1",
+ [VCAP_KF_8021Q_DEI2] = "8021Q_DEI2",
+ [VCAP_KF_8021Q_DEI_CLS] = "8021Q_DEI_CLS",
+ [VCAP_KF_8021Q_PCP0] = "8021Q_PCP0",
+ [VCAP_KF_8021Q_PCP1] = "8021Q_PCP1",
+ [VCAP_KF_8021Q_PCP2] = "8021Q_PCP2",
+ [VCAP_KF_8021Q_PCP_CLS] = "8021Q_PCP_CLS",
+ [VCAP_KF_8021Q_TPID] = "8021Q_TPID",
+ [VCAP_KF_8021Q_TPID0] = "8021Q_TPID0",
+ [VCAP_KF_8021Q_TPID1] = "8021Q_TPID1",
+ [VCAP_KF_8021Q_TPID2] = "8021Q_TPID2",
+ [VCAP_KF_8021Q_VID0] = "8021Q_VID0",
+ [VCAP_KF_8021Q_VID1] = "8021Q_VID1",
+ [VCAP_KF_8021Q_VID2] = "8021Q_VID2",
+ [VCAP_KF_8021Q_VID_CLS] = "8021Q_VID_CLS",
+ [VCAP_KF_8021Q_VLAN_TAGGED_IS] = "8021Q_VLAN_TAGGED_IS",
+ [VCAP_KF_8021Q_VLAN_TAGS] = "8021Q_VLAN_TAGS",
+ [VCAP_KF_ACL_GRP_ID] = "ACL_GRP_ID",
+ [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = "ARP_ADDR_SPACE_OK_IS",
+ [VCAP_KF_ARP_LEN_OK_IS] = "ARP_LEN_OK_IS",
+ [VCAP_KF_ARP_OPCODE] = "ARP_OPCODE",
+ [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = "ARP_OPCODE_UNKNOWN_IS",
+ [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = "ARP_PROTO_SPACE_OK_IS",
+ [VCAP_KF_ARP_SENDER_MATCH_IS] = "ARP_SENDER_MATCH_IS",
+ [VCAP_KF_ARP_TGT_MATCH_IS] = "ARP_TGT_MATCH_IS",
+ [VCAP_KF_COSID_CLS] = "COSID_CLS",
+ [VCAP_KF_ES0_ISDX_KEY_ENA] = "ES0_ISDX_KEY_ENA",
+ [VCAP_KF_ETYPE] = "ETYPE",
+ [VCAP_KF_ETYPE_LEN_IS] = "ETYPE_LEN_IS",
+ [VCAP_KF_HOST_MATCH] = "HOST_MATCH",
+ [VCAP_KF_IF_EGR_PORT_MASK] = "IF_EGR_PORT_MASK",
+ [VCAP_KF_IF_EGR_PORT_MASK_RNG] = "IF_EGR_PORT_MASK_RNG",
+ [VCAP_KF_IF_EGR_PORT_NO] = "IF_EGR_PORT_NO",
+ [VCAP_KF_IF_IGR_PORT] = "IF_IGR_PORT",
+ [VCAP_KF_IF_IGR_PORT_MASK] = "IF_IGR_PORT_MASK",
+ [VCAP_KF_IF_IGR_PORT_MASK_L3] = "IF_IGR_PORT_MASK_L3",
+ [VCAP_KF_IF_IGR_PORT_MASK_RNG] = "IF_IGR_PORT_MASK_RNG",
+ [VCAP_KF_IF_IGR_PORT_MASK_SEL] = "IF_IGR_PORT_MASK_SEL",
+ [VCAP_KF_IF_IGR_PORT_SEL] = "IF_IGR_PORT_SEL",
+ [VCAP_KF_IP4_IS] = "IP4_IS",
+ [VCAP_KF_IP_MC_IS] = "IP_MC_IS",
+ [VCAP_KF_IP_PAYLOAD_5TUPLE] = "IP_PAYLOAD_5TUPLE",
+ [VCAP_KF_IP_SNAP_IS] = "IP_SNAP_IS",
+ [VCAP_KF_ISDX_CLS] = "ISDX_CLS",
+ [VCAP_KF_ISDX_GT0_IS] = "ISDX_GT0_IS",
+ [VCAP_KF_L2_BC_IS] = "L2_BC_IS",
+ [VCAP_KF_L2_DMAC] = "L2_DMAC",
+ [VCAP_KF_L2_FRM_TYPE] = "L2_FRM_TYPE",
+ [VCAP_KF_L2_FWD_IS] = "L2_FWD_IS",
+ [VCAP_KF_L2_LLC] = "L2_LLC",
+ [VCAP_KF_L2_MC_IS] = "L2_MC_IS",
+ [VCAP_KF_L2_PAYLOAD0] = "L2_PAYLOAD0",
+ [VCAP_KF_L2_PAYLOAD1] = "L2_PAYLOAD1",
+ [VCAP_KF_L2_PAYLOAD2] = "L2_PAYLOAD2",
+ [VCAP_KF_L2_PAYLOAD_ETYPE] = "L2_PAYLOAD_ETYPE",
+ [VCAP_KF_L2_SMAC] = "L2_SMAC",
+ [VCAP_KF_L2_SNAP] = "L2_SNAP",
+ [VCAP_KF_L3_DIP_EQ_SIP_IS] = "L3_DIP_EQ_SIP_IS",
+ [VCAP_KF_L3_DPL_CLS] = "L3_DPL_CLS",
+ [VCAP_KF_L3_DSCP] = "L3_DSCP",
+ [VCAP_KF_L3_DST_IS] = "L3_DST_IS",
+ [VCAP_KF_L3_FRAGMENT] = "L3_FRAGMENT",
+ [VCAP_KF_L3_FRAGMENT_TYPE] = "L3_FRAGMENT_TYPE",
+ [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = "L3_FRAG_INVLD_L4_LEN",
+ [VCAP_KF_L3_FRAG_OFS_GT0] = "L3_FRAG_OFS_GT0",
+ [VCAP_KF_L3_IP4_DIP] = "L3_IP4_DIP",
+ [VCAP_KF_L3_IP4_SIP] = "L3_IP4_SIP",
+ [VCAP_KF_L3_IP6_DIP] = "L3_IP6_DIP",
+ [VCAP_KF_L3_IP6_SIP] = "L3_IP6_SIP",
+ [VCAP_KF_L3_IP_PROTO] = "L3_IP_PROTO",
+ [VCAP_KF_L3_OPTIONS_IS] = "L3_OPTIONS_IS",
+ [VCAP_KF_L3_PAYLOAD] = "L3_PAYLOAD",
+ [VCAP_KF_L3_RT_IS] = "L3_RT_IS",
+ [VCAP_KF_L3_TOS] = "L3_TOS",
+ [VCAP_KF_L3_TTL_GT0] = "L3_TTL_GT0",
+ [VCAP_KF_L4_1588_DOM] = "L4_1588_DOM",
+ [VCAP_KF_L4_1588_VER] = "L4_1588_VER",
+ [VCAP_KF_L4_ACK] = "L4_ACK",
+ [VCAP_KF_L4_DPORT] = "L4_DPORT",
+ [VCAP_KF_L4_FIN] = "L4_FIN",
+ [VCAP_KF_L4_PAYLOAD] = "L4_PAYLOAD",
+ [VCAP_KF_L4_PSH] = "L4_PSH",
+ [VCAP_KF_L4_RNG] = "L4_RNG",
+ [VCAP_KF_L4_RST] = "L4_RST",
+ [VCAP_KF_L4_SEQUENCE_EQ0_IS] = "L4_SEQUENCE_EQ0_IS",
+ [VCAP_KF_L4_SPORT] = "L4_SPORT",
+ [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = "L4_SPORT_EQ_DPORT_IS",
+ [VCAP_KF_L4_SYN] = "L4_SYN",
+ [VCAP_KF_L4_URG] = "L4_URG",
+ [VCAP_KF_LOOKUP_FIRST_IS] = "LOOKUP_FIRST_IS",
+ [VCAP_KF_LOOKUP_GEN_IDX] = "LOOKUP_GEN_IDX",
+ [VCAP_KF_LOOKUP_GEN_IDX_SEL] = "LOOKUP_GEN_IDX_SEL",
+ [VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG",
+ [VCAP_KF_MIRROR_PROBE] = "MIRROR_PROBE",
+ [VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0",
+ [VCAP_KF_OAM_DETECTED] = "OAM_DETECTED",
+ [VCAP_KF_OAM_FLAGS] = "OAM_FLAGS",
+ [VCAP_KF_OAM_MEL_FLAGS] = "OAM_MEL_FLAGS",
+ [VCAP_KF_OAM_MEPID] = "OAM_MEPID",
+ [VCAP_KF_OAM_OPCODE] = "OAM_OPCODE",
+ [VCAP_KF_OAM_VER] = "OAM_VER",
+ [VCAP_KF_OAM_Y1731_IS] = "OAM_Y1731_IS",
+ [VCAP_KF_PROT_ACTIVE] = "PROT_ACTIVE",
+ [VCAP_KF_TCP_IS] = "TCP_IS",
+ [VCAP_KF_TCP_UDP_IS] = "TCP_UDP_IS",
+ [VCAP_KF_TYPE] = "TYPE",
+};
+
+/* Actionfield names */
+static const char * const vcap_actionfield_names[] = {
+ [VCAP_AF_NO_VALUE] = "(None)",
+ [VCAP_AF_ACL_ID] = "ACL_ID",
+ [VCAP_AF_CLS_VID_SEL] = "CLS_VID_SEL",
+ [VCAP_AF_CNT_ID] = "CNT_ID",
+ [VCAP_AF_COPY_PORT_NUM] = "COPY_PORT_NUM",
+ [VCAP_AF_COPY_QUEUE_NUM] = "COPY_QUEUE_NUM",
+ [VCAP_AF_CPU_COPY_ENA] = "CPU_COPY_ENA",
+ [VCAP_AF_CPU_QU] = "CPU_QU",
+ [VCAP_AF_CPU_QUEUE_NUM] = "CPU_QUEUE_NUM",
+ [VCAP_AF_DEI_A_VAL] = "DEI_A_VAL",
+ [VCAP_AF_DEI_B_VAL] = "DEI_B_VAL",
+ [VCAP_AF_DEI_C_VAL] = "DEI_C_VAL",
+ [VCAP_AF_DEI_ENA] = "DEI_ENA",
+ [VCAP_AF_DEI_VAL] = "DEI_VAL",
+ [VCAP_AF_DP_ENA] = "DP_ENA",
+ [VCAP_AF_DP_VAL] = "DP_VAL",
+ [VCAP_AF_DSCP_ENA] = "DSCP_ENA",
+ [VCAP_AF_DSCP_SEL] = "DSCP_SEL",
+ [VCAP_AF_DSCP_VAL] = "DSCP_VAL",
+ [VCAP_AF_ES2_REW_CMD] = "ES2_REW_CMD",
+ [VCAP_AF_ESDX] = "ESDX",
+ [VCAP_AF_FWD_KILL_ENA] = "FWD_KILL_ENA",
+ [VCAP_AF_FWD_MODE] = "FWD_MODE",
+ [VCAP_AF_FWD_SEL] = "FWD_SEL",
+ [VCAP_AF_HIT_ME_ONCE] = "HIT_ME_ONCE",
+ [VCAP_AF_HOST_MATCH] = "HOST_MATCH",
+ [VCAP_AF_IGNORE_PIPELINE_CTRL] = "IGNORE_PIPELINE_CTRL",
+ [VCAP_AF_INTR_ENA] = "INTR_ENA",
+ [VCAP_AF_ISDX_ADD_REPLACE_SEL] = "ISDX_ADD_REPLACE_SEL",
+ [VCAP_AF_ISDX_ENA] = "ISDX_ENA",
+ [VCAP_AF_ISDX_VAL] = "ISDX_VAL",
+ [VCAP_AF_LOOP_ENA] = "LOOP_ENA",
+ [VCAP_AF_LRN_DIS] = "LRN_DIS",
+ [VCAP_AF_MAP_IDX] = "MAP_IDX",
+ [VCAP_AF_MAP_KEY] = "MAP_KEY",
+ [VCAP_AF_MAP_LOOKUP_SEL] = "MAP_LOOKUP_SEL",
+ [VCAP_AF_MASK_MODE] = "MASK_MODE",
+ [VCAP_AF_MATCH_ID] = "MATCH_ID",
+ [VCAP_AF_MATCH_ID_MASK] = "MATCH_ID_MASK",
+ [VCAP_AF_MIRROR_ENA] = "MIRROR_ENA",
+ [VCAP_AF_MIRROR_PROBE] = "MIRROR_PROBE",
+ [VCAP_AF_MIRROR_PROBE_ID] = "MIRROR_PROBE_ID",
+ [VCAP_AF_NXT_IDX] = "NXT_IDX",
+ [VCAP_AF_NXT_IDX_CTRL] = "NXT_IDX_CTRL",
+ [VCAP_AF_PAG_OVERRIDE_MASK] = "PAG_OVERRIDE_MASK",
+ [VCAP_AF_PAG_VAL] = "PAG_VAL",
+ [VCAP_AF_PCP_A_VAL] = "PCP_A_VAL",
+ [VCAP_AF_PCP_B_VAL] = "PCP_B_VAL",
+ [VCAP_AF_PCP_C_VAL] = "PCP_C_VAL",
+ [VCAP_AF_PCP_ENA] = "PCP_ENA",
+ [VCAP_AF_PCP_VAL] = "PCP_VAL",
+ [VCAP_AF_PIPELINE_ACT] = "PIPELINE_ACT",
+ [VCAP_AF_PIPELINE_FORCE_ENA] = "PIPELINE_FORCE_ENA",
+ [VCAP_AF_PIPELINE_PT] = "PIPELINE_PT",
+ [VCAP_AF_POLICE_ENA] = "POLICE_ENA",
+ [VCAP_AF_POLICE_IDX] = "POLICE_IDX",
+ [VCAP_AF_POLICE_REMARK] = "POLICE_REMARK",
+ [VCAP_AF_POLICE_VCAP_ONLY] = "POLICE_VCAP_ONLY",
+ [VCAP_AF_POP_VAL] = "POP_VAL",
+ [VCAP_AF_PORT_MASK] = "PORT_MASK",
+ [VCAP_AF_PUSH_CUSTOMER_TAG] = "PUSH_CUSTOMER_TAG",
+ [VCAP_AF_PUSH_INNER_TAG] = "PUSH_INNER_TAG",
+ [VCAP_AF_PUSH_OUTER_TAG] = "PUSH_OUTER_TAG",
+ [VCAP_AF_QOS_ENA] = "QOS_ENA",
+ [VCAP_AF_QOS_VAL] = "QOS_VAL",
+ [VCAP_AF_REW_OP] = "REW_OP",
+ [VCAP_AF_RT_DIS] = "RT_DIS",
+ [VCAP_AF_SWAP_MACS_ENA] = "SWAP_MACS_ENA",
+ [VCAP_AF_TAG_A_DEI_SEL] = "TAG_A_DEI_SEL",
+ [VCAP_AF_TAG_A_PCP_SEL] = "TAG_A_PCP_SEL",
+ [VCAP_AF_TAG_A_TPID_SEL] = "TAG_A_TPID_SEL",
+ [VCAP_AF_TAG_A_VID_SEL] = "TAG_A_VID_SEL",
+ [VCAP_AF_TAG_B_DEI_SEL] = "TAG_B_DEI_SEL",
+ [VCAP_AF_TAG_B_PCP_SEL] = "TAG_B_PCP_SEL",
+ [VCAP_AF_TAG_B_TPID_SEL] = "TAG_B_TPID_SEL",
+ [VCAP_AF_TAG_B_VID_SEL] = "TAG_B_VID_SEL",
+ [VCAP_AF_TAG_C_DEI_SEL] = "TAG_C_DEI_SEL",
+ [VCAP_AF_TAG_C_PCP_SEL] = "TAG_C_PCP_SEL",
+ [VCAP_AF_TAG_C_TPID_SEL] = "TAG_C_TPID_SEL",
+ [VCAP_AF_TAG_C_VID_SEL] = "TAG_C_VID_SEL",
+ [VCAP_AF_TYPE] = "TYPE",
+ [VCAP_AF_UNTAG_VID_ENA] = "UNTAG_VID_ENA",
+ [VCAP_AF_VID_A_VAL] = "VID_A_VAL",
+ [VCAP_AF_VID_B_VAL] = "VID_B_VAL",
+ [VCAP_AF_VID_C_VAL] = "VID_C_VAL",
+ [VCAP_AF_VID_VAL] = "VID_VAL",
+};
+
+/* VCAPs */
+const struct vcap_info lan969x_vcaps[] = {
+ [VCAP_TYPE_IS0] = {
+ .name = "is0",
+ .rows = 256,
+ .sw_count = 12,
+ .sw_width = 52,
+ .sticky_width = 1,
+ .act_width = 103,
+ .default_cnt = 70,
+ .require_cnt_dis = 0,
+ .version = 1,
+ .keyfield_set = is0_keyfield_set,
+ .keyfield_set_size = ARRAY_SIZE(is0_keyfield_set),
+ .actionfield_set = is0_actionfield_set,
+ .actionfield_set_size = ARRAY_SIZE(is0_actionfield_set),
+ .keyfield_set_map = is0_keyfield_set_map,
+ .keyfield_set_map_size = is0_keyfield_set_map_size,
+ .actionfield_set_map = is0_actionfield_set_map,
+ .actionfield_set_map_size = is0_actionfield_set_map_size,
+ .keyfield_set_typegroups = is0_keyfield_set_typegroups,
+ .actionfield_set_typegroups = is0_actionfield_set_typegroups,
+ },
+ [VCAP_TYPE_IS2] = {
+ .name = "is2",
+ .rows = 256,
+ .sw_count = 12,
+ .sw_width = 52,
+ .sticky_width = 1,
+ .act_width = 103,
+ .default_cnt = 38,
+ .require_cnt_dis = 0,
+ .version = 1,
+ .keyfield_set = is2_keyfield_set,
+ .keyfield_set_size = ARRAY_SIZE(is2_keyfield_set),
+ .actionfield_set = is2_actionfield_set,
+ .actionfield_set_size = ARRAY_SIZE(is2_actionfield_set),
+ .keyfield_set_map = is2_keyfield_set_map,
+ .keyfield_set_map_size = is2_keyfield_set_map_size,
+ .actionfield_set_map = is2_actionfield_set_map,
+ .actionfield_set_map_size = is2_actionfield_set_map_size,
+ .keyfield_set_typegroups = is2_keyfield_set_typegroups,
+ .actionfield_set_typegroups = is2_actionfield_set_typegroups,
+ },
+ [VCAP_TYPE_ES0] = {
+ .name = "es0",
+ .rows = 1536,
+ .sw_count = 1,
+ .sw_width = 51,
+ .sticky_width = 1,
+ .act_width = 469,
+ .default_cnt = 35,
+ .require_cnt_dis = 0,
+ .version = 1,
+ .keyfield_set = es0_keyfield_set,
+ .keyfield_set_size = ARRAY_SIZE(es0_keyfield_set),
+ .actionfield_set = es0_actionfield_set,
+ .actionfield_set_size = ARRAY_SIZE(es0_actionfield_set),
+ .keyfield_set_map = es0_keyfield_set_map,
+ .keyfield_set_map_size = es0_keyfield_set_map_size,
+ .actionfield_set_map = es0_actionfield_set_map,
+ .actionfield_set_map_size = es0_actionfield_set_map_size,
+ .keyfield_set_typegroups = es0_keyfield_set_typegroups,
+ .actionfield_set_typegroups = es0_actionfield_set_typegroups,
+ },
+ [VCAP_TYPE_ES2] = {
+ .name = "es2",
+ .rows = 256,
+ .sw_count = 12,
+ .sw_width = 52,
+ .sticky_width = 1,
+ .act_width = 19,
+ .default_cnt = 39,
+ .require_cnt_dis = 0,
+ .version = 1,
+ .keyfield_set = es2_keyfield_set,
+ .keyfield_set_size = ARRAY_SIZE(es2_keyfield_set),
+ .actionfield_set = es2_actionfield_set,
+ .actionfield_set_size = ARRAY_SIZE(es2_actionfield_set),
+ .keyfield_set_map = es2_keyfield_set_map,
+ .keyfield_set_map_size = es2_keyfield_set_map_size,
+ .actionfield_set_map = es2_actionfield_set_map,
+ .actionfield_set_map_size = es2_actionfield_set_map_size,
+ .keyfield_set_typegroups = es2_keyfield_set_typegroups,
+ .actionfield_set_typegroups = es2_actionfield_set_typegroups,
+ },
+};
+
+const struct vcap_statistics lan969x_vcap_stats = {
+ .name = "lan969x",
+ .count = 4,
+ .keyfield_set_names = vcap_keyfield_set_names,
+ .actionfield_set_names = vcap_actionfield_set_names,
+ .keyfield_names = vcap_keyfield_names,
+ .actionfield_names = vcap_actionfield_names,
+};
diff --git a/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_impl.c b/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_impl.c
new file mode 100644
index 000000000000..543a1f2bf6bd
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x_vcap_impl.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "vcap_api.h"
+#include "lan969x.h"
+
+const struct sparx5_vcap_inst lan969x_vcap_inst_cfg[] = {
+ {
+ .vtype = VCAP_TYPE_IS0, /* CLM-0 */
+ .vinst = 0,
+ .map_id = 1,
+ .lookups = SPARX5_IS0_LOOKUPS,
+ .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,
+ .first_cid = SPARX5_VCAP_CID_IS0_L0,
+ .last_cid = SPARX5_VCAP_CID_IS0_L2 - 1,
+ .blockno = 2,
+ .blocks = 1,
+ .ingress = true,
+ },
+ {
+ .vtype = VCAP_TYPE_IS0, /* CLM-1 */
+ .vinst = 1,
+ .map_id = 2,
+ .lookups = SPARX5_IS0_LOOKUPS,
+ .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,
+ .first_cid = SPARX5_VCAP_CID_IS0_L2,
+ .last_cid = SPARX5_VCAP_CID_IS0_L4 - 1,
+ .blockno = 3,
+ .blocks = 1,
+ .ingress = true,
+ },
+ {
+ .vtype = VCAP_TYPE_IS0, /* CLM-2 */
+ .vinst = 2,
+ .map_id = 3,
+ .lookups = SPARX5_IS0_LOOKUPS,
+ .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,
+ .first_cid = SPARX5_VCAP_CID_IS0_L4,
+ .last_cid = SPARX5_VCAP_CID_IS0_MAX,
+ .blockno = 4,
+ .blocks = 1,
+ .ingress = true,
+ },
+ {
+ .vtype = VCAP_TYPE_IS2, /* IS2-0 */
+ .vinst = 0,
+ .map_id = 4,
+ .lookups = SPARX5_IS2_LOOKUPS,
+ .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
+ .first_cid = SPARX5_VCAP_CID_IS2_L0,
+ .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1,
+ .blockno = 0,
+ .blocks = 1,
+ .ingress = true,
+ },
+ {
+ .vtype = VCAP_TYPE_IS2, /* IS2-1 */
+ .vinst = 1,
+ .map_id = 5,
+ .lookups = SPARX5_IS2_LOOKUPS,
+ .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
+ .first_cid = SPARX5_VCAP_CID_IS2_L2,
+ .last_cid = SPARX5_VCAP_CID_IS2_MAX,
+ .blockno = 1,
+ .blocks = 1,
+ .ingress = true,
+ },
+ {
+ .vtype = VCAP_TYPE_ES0,
+ .lookups = SPARX5_ES0_LOOKUPS,
+ .lookups_per_instance = SPARX5_ES0_LOOKUPS,
+ .first_cid = SPARX5_VCAP_CID_ES0_L0,
+ .last_cid = SPARX5_VCAP_CID_ES0_MAX,
+ .count = 1536,
+ .ingress = false,
+ },
+ {
+ .vtype = VCAP_TYPE_ES2,
+ .lookups = SPARX5_ES2_LOOKUPS,
+ .lookups_per_instance = SPARX5_ES2_LOOKUPS,
+ .first_cid = SPARX5_VCAP_CID_ES2_L0,
+ .last_cid = SPARX5_VCAP_CID_ES2_MAX,
+ .count = 1024,
+ .ingress = false,
+ },
+};
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
index b2a8d04ab509..5fe941c66c17 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
@@ -15,7 +15,6 @@
#define SPX5_CALBITS_PER_PORT 3 /* Bit per port in calendar register */
/* DSM calendar information */
-#define SPX5_DSM_CAL_EMPTY 0xFFFF
#define SPX5_DSM_CAL_TAXIS 8
#define SPX5_DSM_CAL_BW_LOSS 553
@@ -53,27 +52,32 @@ static u32 sparx5_target_bandwidth(struct sparx5 *sparx5)
case SPX5_TARGET_CT_7558:
case SPX5_TARGET_CT_7558TSN:
return 201000;
+ case SPX5_TARGET_CT_LAN9691VAO:
+ return 46000;
+ case SPX5_TARGET_CT_LAN9694RED:
+ case SPX5_TARGET_CT_LAN9694TSN:
+ case SPX5_TARGET_CT_LAN9694:
+ return 68000;
+ case SPX5_TARGET_CT_LAN9696RED:
+ case SPX5_TARGET_CT_LAN9696TSN:
+ case SPX5_TARGET_CT_LAN9692VAO:
+ case SPX5_TARGET_CT_LAN9696:
+ return 88000;
+ case SPX5_TARGET_CT_LAN9698RED:
+ case SPX5_TARGET_CT_LAN9698TSN:
+ case SPX5_TARGET_CT_LAN9693VAO:
+ case SPX5_TARGET_CT_LAN9698:
+ return 101000;
default:
return 0;
}
}
-/* This is used in calendar configuration */
-enum sparx5_cal_bw {
- SPX5_CAL_SPEED_NONE = 0,
- SPX5_CAL_SPEED_1G = 1,
- SPX5_CAL_SPEED_2G5 = 2,
- SPX5_CAL_SPEED_5G = 3,
- SPX5_CAL_SPEED_10G = 4,
- SPX5_CAL_SPEED_25G = 5,
- SPX5_CAL_SPEED_0G5 = 6,
- SPX5_CAL_SPEED_12G5 = 7
-};
-
static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock)
{
switch (cclock) {
case SPX5_CORE_CLOCK_250MHZ: return 83000; /* 250000 / 3 */
+ case SPX5_CORE_CLOCK_328MHZ: return 109375; /* 328000 / 3 */
case SPX5_CORE_CLOCK_500MHZ: return 166000; /* 500000 / 3 */
case SPX5_CORE_CLOCK_625MHZ: return 208000; /* 625000 / 3 */
default: return 0;
@@ -81,7 +85,7 @@ static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock)
return 0;
}
-static u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
+u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
{
switch (speed) {
case SPX5_CAL_SPEED_1G: return 1000;
@@ -94,6 +98,7 @@ static u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
default: return 0;
}
}
+EXPORT_SYMBOL_GPL(sparx5_cal_speed_to_value);
static u32 sparx5_bandwidth_to_calendar(u32 bw)
{
@@ -111,8 +116,7 @@ static u32 sparx5_bandwidth_to_calendar(u32 bw)
}
}
-static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
- u32 portno)
+enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno)
{
struct sparx5_port *port;
@@ -146,6 +150,7 @@ static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
return SPX5_CAL_SPEED_NONE;
return sparx5_bandwidth_to_calendar(port->conf.bandwidth);
}
+EXPORT_SYMBOL_GPL(sparx5_get_port_cal_speed);
/* Auto configure the QSYS calendar based on port configuration */
int sparx5_config_auto_calendar(struct sparx5 *sparx5)
@@ -526,12 +531,23 @@ check_err:
static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data)
{
- u32 idx;
- u32 cal_len = sparx5_dsm_cal_len(data->schedule), len;
+ u32 cal_len = sparx5_dsm_cal_len(data->schedule), len, idx;
+
+ if (!is_sparx5(sparx5)) {
+ u32 val, act;
+
+ val = spx5_rd(sparx5, DSM_TAXI_CAL_CFG(taxi));
+ act = DSM_TAXI_CAL_CFG_CAL_SEL_STAT_GET(val);
+
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_SEL_SET(!act),
+ DSM_TAXI_CAL_CFG_CAL_PGM_SEL,
+ sparx5, DSM_TAXI_CAL_CFG(taxi));
+ }
- spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(1),
- sparx5,
- DSM_TAXI_CAL_CFG(taxi));
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(1),
+ DSM_TAXI_CAL_CFG_CAL_PGM_ENA,
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
for (idx = 0; idx < cal_len; idx++) {
spx5_rmw(DSM_TAXI_CAL_CFG_CAL_IDX_SET(idx),
DSM_TAXI_CAL_CFG_CAL_IDX,
@@ -542,13 +558,21 @@ static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi,
sparx5,
DSM_TAXI_CAL_CFG(taxi));
}
- spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(0),
- sparx5,
- DSM_TAXI_CAL_CFG(taxi));
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(0),
+ DSM_TAXI_CAL_CFG_CAL_PGM_ENA,
+ sparx5,
+ DSM_TAXI_CAL_CFG(taxi));
len = DSM_TAXI_CAL_CFG_CAL_CUR_LEN_GET(spx5_rd(sparx5,
DSM_TAXI_CAL_CFG(taxi)));
if (len != cal_len - 1)
goto update_err;
+
+ if (!is_sparx5(sparx5)) {
+ spx5_rmw(DSM_TAXI_CAL_CFG_CAL_SWITCH_SET(1),
+ DSM_TAXI_CAL_CFG_CAL_SWITCH,
+ sparx5, DSM_TAXI_CAL_CFG(taxi));
+ }
+
return 0;
update_err:
dev_err(sparx5->dev, "Incorrect calendar length: %u\n", len);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
index 88f7509f0980..0027144a2af2 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
@@ -154,7 +154,7 @@ static bool sparx5_fdma_rx_get_frame(struct sparx5 *sparx5, struct sparx5_rx *rx
skb = rx->skb[fdma->dcb_index][fdma->db_index];
skb_put(skb, fdma_db_len_get(db_hw));
/* Now do the normal processing of the skb */
- sparx5_ifh_parse((u32 *)skb->data, &fi);
+ sparx5_ifh_parse(sparx5, (u32 *)skb->data, &fi);
/* Map to port netdev */
port = fi.src_port < sparx5->data->consts->n_ports ?
sparx5->ports[fi.src_port] :
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
index d1e9bc030c80..2f1013f870fb 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -24,10 +24,14 @@
#include <linux/types.h>
#include <linux/reset.h>
+#include "../lan969x/lan969x.h" /* for lan969x match data */
+
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_port.h"
#include "sparx5_qos.h"
+#include "sparx5_vcap_ag_api.h"
+#include "sparx5_vcap_impl.h"
const struct sparx5_regs *regs;
@@ -227,6 +231,40 @@ bool is_sparx5(struct sparx5 *sparx5)
}
}
+static void sparx5_init_features(struct sparx5 *sparx5)
+{
+ switch (sparx5->target_ct) {
+ case SPX5_TARGET_CT_7546:
+ case SPX5_TARGET_CT_7549:
+ case SPX5_TARGET_CT_7552:
+ case SPX5_TARGET_CT_7556:
+ case SPX5_TARGET_CT_7558:
+ case SPX5_TARGET_CT_7546TSN:
+ case SPX5_TARGET_CT_7549TSN:
+ case SPX5_TARGET_CT_7552TSN:
+ case SPX5_TARGET_CT_7556TSN:
+ case SPX5_TARGET_CT_7558TSN:
+ case SPX5_TARGET_CT_LAN9691VAO:
+ case SPX5_TARGET_CT_LAN9694TSN:
+ case SPX5_TARGET_CT_LAN9694RED:
+ case SPX5_TARGET_CT_LAN9692VAO:
+ case SPX5_TARGET_CT_LAN9696TSN:
+ case SPX5_TARGET_CT_LAN9696RED:
+ case SPX5_TARGET_CT_LAN9693VAO:
+ case SPX5_TARGET_CT_LAN9698TSN:
+ case SPX5_TARGET_CT_LAN9698RED:
+ sparx5->features = (SPX5_FEATURE_PSFP | SPX5_FEATURE_PTP);
+ break;
+ default:
+ break;
+ }
+}
+
+bool sparx5_has_feature(struct sparx5 *sparx5, enum sparx5_feature feature)
+{
+ return sparx5->features & feature;
+}
+
static int sparx5_create_targets(struct sparx5 *sparx5)
{
const struct sparx5_main_io_resource *iomap = sparx5->data->iomap;
@@ -475,6 +513,20 @@ static int sparx5_init_coreclock(struct sparx5 *sparx5)
else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ)
freq = 0; /* Not supported */
break;
+ case SPX5_TARGET_CT_LAN9694:
+ case SPX5_TARGET_CT_LAN9691VAO:
+ case SPX5_TARGET_CT_LAN9694TSN:
+ case SPX5_TARGET_CT_LAN9694RED:
+ case SPX5_TARGET_CT_LAN9696:
+ case SPX5_TARGET_CT_LAN9692VAO:
+ case SPX5_TARGET_CT_LAN9696TSN:
+ case SPX5_TARGET_CT_LAN9696RED:
+ case SPX5_TARGET_CT_LAN9698:
+ case SPX5_TARGET_CT_LAN9693VAO:
+ case SPX5_TARGET_CT_LAN9698TSN:
+ case SPX5_TARGET_CT_LAN9698RED:
+ freq = SPX5_CORE_CLOCK_328MHZ;
+ break;
default:
dev_err(sparx5->dev, "Target (%#04x) not supported\n",
sparx5->target_ct);
@@ -516,16 +568,19 @@ static int sparx5_init_coreclock(struct sparx5 *sparx5)
CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA |
CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA,
sparx5, CLKGEN_LCPLL1_CORE_CLK_CFG);
+ } else {
+ pol_upd_int = 820; // SPX5_CORE_CLOCK_328MHZ
}
/* Update state with chosen frequency */
sparx5->coreclock = freq;
clk_period = sparx5_clk_period(freq);
- spx5_rmw(HSCH_SYS_CLK_PER_100PS_SET(clk_period / 100),
- HSCH_SYS_CLK_PER_100PS,
- sparx5,
- HSCH_SYS_CLK_PER);
+ if (is_sparx5(sparx5))
+ spx5_rmw(HSCH_SYS_CLK_PER_100PS_SET(clk_period / 100),
+ HSCH_SYS_CLK_PER_100PS,
+ sparx5,
+ HSCH_SYS_CLK_PER);
spx5_rmw(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS,
@@ -723,7 +778,7 @@ static int sparx5_start(struct sparx5 *sparx5)
/* Start Frame DMA with fallback to register based INJ/XTR */
err = -ENXIO;
- if (sparx5->fdma_irq >= 0) {
+ if (sparx5->fdma_irq >= 0 && is_sparx5(sparx5)) {
if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0)
err = devm_request_threaded_irq(sparx5->dev,
sparx5->fdma_irq,
@@ -750,7 +805,8 @@ static int sparx5_start(struct sparx5 *sparx5)
sparx5->xtr_irq = -ENXIO;
}
- if (sparx5->ptp_irq >= 0) {
+ if (sparx5->ptp_irq >= 0 &&
+ sparx5_has_feature(sparx5, SPX5_FEATURE_PTP)) {
err = devm_request_threaded_irq(sparx5->dev, sparx5->ptp_irq,
NULL, ops->ptp_irq_handler,
IRQF_ONESHOT, "sparx5-ptp",
@@ -894,6 +950,9 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
sparx5->target_ct = (enum spx5_target_chiptype)
GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id);
+ /* Initialize the features based on the target */
+ sparx5_init_features(sparx5);
+
/* Initialize Switchcore and internal RAMs */
err = sparx5_init_switchcore(sparx5);
if (err) {
@@ -1004,6 +1063,9 @@ static const struct sparx5_consts sparx5_consts = {
.qres_max_prio_idx = 630,
.qres_max_colour_idx = 638,
.tod_pin = 4,
+ .vcaps = sparx5_vcaps,
+ .vcaps_cfg = sparx5_vcap_inst_cfg,
+ .vcap_stats = &sparx5_vcap_stats,
};
static const struct sparx5_ops sparx5_ops = {
@@ -1031,6 +1093,9 @@ static const struct sparx5_match_data sparx5_desc = {
static const struct of_device_id mchp_sparx5_match[] = {
{ .compatible = "microchip,sparx5-switch", .data = &sparx5_desc },
+#if IS_ENABLED(CONFIG_LAN969X_SWITCH)
+ { .compatible = "microchip,lan9691-switch", .data = &lan969x_desc },
+#endif
{ }
};
MODULE_DEVICE_TABLE(of, mchp_sparx5_match);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
index 364ae92969bc..d5dd953b0a71 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -26,16 +26,28 @@
/* Target chip type */
enum spx5_target_chiptype {
- SPX5_TARGET_CT_7546 = 0x7546, /* SparX-5-64 Enterprise */
- SPX5_TARGET_CT_7549 = 0x7549, /* SparX-5-90 Enterprise */
- SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */
- SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */
- SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */
- SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */
- SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */
- SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */
- SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */
- SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */
+ SPX5_TARGET_CT_7546 = 0x7546, /* SparX-5-64 Enterprise */
+ SPX5_TARGET_CT_7549 = 0x7549, /* SparX-5-90 Enterprise */
+ SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */
+ SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */
+ SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */
+ SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */
+ SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */
+ SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */
+ SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */
+ SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */
+ SPX5_TARGET_CT_LAN9694 = 0x9694, /* lan969x-40 */
+ SPX5_TARGET_CT_LAN9691VAO = 0x9691, /* lan969x-40-VAO */
+ SPX5_TARGET_CT_LAN9694TSN = 0x9695, /* lan969x-40-TSN */
+ SPX5_TARGET_CT_LAN9694RED = 0x969A, /* lan969x-40-RED */
+ SPX5_TARGET_CT_LAN9696 = 0x9696, /* lan969x-60 */
+ SPX5_TARGET_CT_LAN9692VAO = 0x9692, /* lan969x-65-VAO */
+ SPX5_TARGET_CT_LAN9696TSN = 0x9697, /* lan969x-60-TSN */
+ SPX5_TARGET_CT_LAN9696RED = 0x969B, /* lan969x-60-RED */
+ SPX5_TARGET_CT_LAN9698 = 0x9698, /* lan969x-100 */
+ SPX5_TARGET_CT_LAN9693VAO = 0x9693, /* lan969x-100-VAO */
+ SPX5_TARGET_CT_LAN9698TSN = 0x9699, /* lan969x-100-TSN */
+ SPX5_TARGET_CT_LAN9698RED = 0x969C, /* lan969x-100-RED */
};
enum sparx5_port_max_tags {
@@ -51,6 +63,23 @@ enum sparx5_vlan_port_type {
SPX5_VLAN_PORT_TYPE_S_CUSTOM /* S-port using custom type */
};
+/* This is used in calendar configuration */
+enum sparx5_cal_bw {
+ SPX5_CAL_SPEED_NONE = 0,
+ SPX5_CAL_SPEED_1G = 1,
+ SPX5_CAL_SPEED_2G5 = 2,
+ SPX5_CAL_SPEED_5G = 3,
+ SPX5_CAL_SPEED_10G = 4,
+ SPX5_CAL_SPEED_25G = 5,
+ SPX5_CAL_SPEED_0G5 = 6,
+ SPX5_CAL_SPEED_12G5 = 7
+};
+
+enum sparx5_feature {
+ SPX5_FEATURE_PSFP = BIT(0),
+ SPX5_FEATURE_PTP = BIT(1),
+};
+
#define SPX5_PORTS 65
#define SPX5_PORTS_ALL 70 /* Total number of ports */
@@ -101,6 +130,9 @@ enum sparx5_vlan_port_type {
#define SPX5_DSM_CAL_LEN 64
#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13
+#define SPX5_DSM_CAL_EMPTY 0xFFFF
+
+#define SPARX5_MAX_PTP_ID 512
struct sparx5;
@@ -192,6 +224,7 @@ struct sparx5_port {
enum sparx5_core_clockfreq {
SPX5_CORE_CLOCK_DEFAULT, /* Defaults to the highest supported frequency */
SPX5_CORE_CLOCK_250MHZ, /* 250MHZ core clock frequency */
+ SPX5_CORE_CLOCK_328MHZ, /* 328MHZ core clock frequency */
SPX5_CORE_CLOCK_500MHZ, /* 500MHZ core clock frequency */
SPX5_CORE_CLOCK_625MHZ, /* 625MHZ core clock frequency */
};
@@ -270,6 +303,9 @@ struct sparx5_consts {
u32 qres_max_prio_idx; /* Maximum QRES prio index */
u32 qres_max_colour_idx; /* Maximum QRES colour index */
u32 tod_pin; /* PTP TOD pin */
+ const struct sparx5_vcap_inst *vcaps_cfg;
+ const struct vcap_info *vcaps;
+ const struct vcap_statistics *vcap_stats;
};
struct sparx5_ops {
@@ -309,6 +345,7 @@ struct sparx5 {
struct device *dev;
u32 chip_id;
enum spx5_target_chiptype target_ct;
+ u32 features;
void __iomem *regs[NUM_TARGETS];
int port_count;
struct mutex lock; /* MAC reg lock */
@@ -376,6 +413,7 @@ struct sparx5 {
/* sparx5_main.c */
bool is_sparx5(struct sparx5 *sparx5);
+bool sparx5_has_feature(struct sparx5 *sparx5, enum sparx5_feature feature);
/* sparx5_switchdev.c */
int sparx5_register_notifier_blocks(struct sparx5 *sparx5);
@@ -388,7 +426,7 @@ struct frame_info {
};
void sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp);
-void sparx5_ifh_parse(u32 *ifh, struct frame_info *info);
+void sparx5_ifh_parse(struct sparx5 *sparx5, u32 *ifh, struct frame_info *info);
irqreturn_t sparx5_xtr_handler(int irq, void *_priv);
netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev);
int sparx5_manual_injection_mode(struct sparx5 *sparx5);
@@ -439,6 +477,8 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5);
int sparx5_config_dsm_calendar(struct sparx5 *sparx5);
int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data);
+u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed);
+enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno);
/* sparx5_ethtool.c */
@@ -456,10 +496,13 @@ static inline int sparx5_dcb_init(struct sparx5 *sparx5)
#endif
/* sparx5_netdev.c */
-void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp);
+void sparx5_set_port_ifh_timestamp(struct sparx5 *sparx5, void *ifh_hdr,
+ u64 timestamp);
void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op);
-void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type);
-void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset);
+void sparx5_set_port_ifh_pdu_type(struct sparx5 *sparx5, void *ifh_hdr,
+ u32 pdu_type);
+void sparx5_set_port_ifh_pdu_w16_offset(struct sparx5 *sparx5, void *ifh_hdr,
+ u32 pdu_w16_offset);
void sparx5_set_port_ifh(struct sparx5 *sparx5, void *ifh_hdr, u16 portno);
bool sparx5_netdevice_check(const struct net_device *dev);
struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno);
@@ -483,6 +526,9 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port,
struct sk_buff *skb);
irqreturn_t sparx5_ptp_irq_handler(int irq, void *args);
int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
+void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
+ struct timespec64 *ts,
+ u32 nsec);
/* sparx5_vcap_impl.c */
int sparx5_vcap_init(struct sparx5 *sparx5);
@@ -539,7 +585,7 @@ struct sparx5_sdlb_group *sparx5_get_sdlb_group(int idx);
int sparx5_sdlb_pup_token_get(struct sparx5 *sparx5, u32 pup_interval,
u64 rate);
-int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5);
+u64 sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5);
int sparx5_sdlb_group_get_by_rate(struct sparx5 *sparx5, u32 rate, u32 burst);
int sparx5_sdlb_group_get_by_index(struct sparx5 *sparx5, u32 idx, u32 *group);
@@ -641,6 +687,8 @@ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
switch (cclock) {
case SPX5_CORE_CLOCK_250MHZ:
return 4000;
+ case SPX5_CORE_CLOCK_328MHZ:
+ return 3048;
case SPX5_CORE_CLOCK_500MHZ:
return 2000;
case SPX5_CORE_CLOCK_625MHZ:
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
index 0e8b18bcf179..561344f19062 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
@@ -2666,6 +2666,44 @@ extern const struct sparx5_regs *regs;
#define CPU_PROC_CTRL_ACP_DISABLE_GET(x)\
FIELD_GET(CPU_PROC_CTRL_ACP_DISABLE, x)
+/* DEV1G:PHASE_DETECTOR_CTRL:PHAD_CTRL */
+#define DEV2G5_PHAD_CTRL(t, g) \
+ __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 200, g, 2, \
+ regs->gsize[GW_DEV2G5_PHASE_DETECTOR_CTRL], 0, 0, 1, 4)
+
+#define DEV2G5_PHAD_CTRL_PHAD_ENA\
+ BIT(regs->fpos[FP_DEV2G5_PHAD_CTRL_PHAD_ENA])
+#define DEV2G5_PHAD_CTRL_PHAD_ENA_SET(x)\
+ spx5_field_prep(DEV2G5_PHAD_CTRL_PHAD_ENA, x)
+#define DEV2G5_PHAD_CTRL_PHAD_ENA_GET(x)\
+ spx5_field_get(DEV2G5_PHAD_CTRL_PHAD_ENA, x)
+
+/* LAN969X ONLY */
+#define DEV2G5_PHAD_CTRL_DIV_CFG GENMASK(11, 9)
+#define DEV2G5_PHAD_CTRL_DIV_CFG_SET(x)\
+ FIELD_PREP(DEV2G5_PHAD_CTRL_DIV_CFG, x)
+#define DEV2G5_PHAD_CTRL_DIV_CFG_GET(x)\
+ FIELD_GET(DEV2G5_PHAD_CTRL_DIV_CFG, x)
+
+/* DEV1G:PHASE_DETECTOR_CTRL:PHAD_CTRL */
+#define DEV2G5_PHAD_CTRL(t, g) \
+ __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 200, g, 2, \
+ regs->gsize[GW_DEV2G5_PHASE_DETECTOR_CTRL], 0, 0, 1, 4)
+
+#define DEV2G5_PHAD_CTRL_PHAD_ENA\
+ BIT(regs->fpos[FP_DEV2G5_PHAD_CTRL_PHAD_ENA])
+#define DEV2G5_PHAD_CTRL_PHAD_ENA_SET(x)\
+ spx5_field_prep(DEV2G5_PHAD_CTRL_PHAD_ENA, x)
+#define DEV2G5_PHAD_CTRL_PHAD_ENA_GET(x)\
+ spx5_field_get(DEV2G5_PHAD_CTRL_PHAD_ENA, x)
+
+/* LAN969X ONLY */
+#define DEV2G5_PHAD_CTRL_DIV_CFG GENMASK(11, 9)
+#define DEV2G5_PHAD_CTRL_DIV_CFG_SET(x)\
+ FIELD_PREP(DEV2G5_PHAD_CTRL_DIV_CFG, x)
+#define DEV2G5_PHAD_CTRL_DIV_CFG_GET(x)\
+ FIELD_GET(DEV2G5_PHAD_CTRL_DIV_CFG, x)
+
/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */
#define DEV10G_MAC_ENA_CFG(t) \
__REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 0, 0, 1, \
@@ -2869,6 +2907,11 @@ extern const struct sparx5_regs *regs;
#define DEV10G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
FIELD_GET(DEV10G_DEV_RST_CTRL_MAC_RX_RST, x)
+/* DEV10G:DEV_CFG_STATUS:PTP_STAMPER_CFG */
+#define DEV10G_PTP_STAMPER_CFG(t) \
+ __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 436, 0, 1, 52, 20, 0, \
+ 1, 4)
+
/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */
#define DEV10G_PCS25G_CFG(t) \
__REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 488, 0, 1, 32, 0, 0, 1,\
@@ -4267,6 +4310,11 @@ extern const struct sparx5_regs *regs;
#define DEV5G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\
FIELD_GET(DEV5G_DEV_RST_CTRL_MAC_RX_RST, x)
+/* DEV10G:DEV_CFG_STATUS:PTP_STAMPER_CFG */
+#define DEV5G_PTP_STAMPER_CFG(t) \
+ __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 436, 0, 1, 52, 20, 0, 1, \
+ 4)
+
/* DSM:RAM_CTRL:RAM_INIT */
#define DSM_RAM_INIT \
__REG(TARGET_DSM, 0, 1, 0, 0, 1, 4, 0, 0, 1, 4)
@@ -4444,6 +4492,27 @@ extern const struct sparx5_regs *regs;
#define DSM_TAXI_CAL_CFG_CAL_PGM_ENA_GET(x)\
FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_ENA, x)
+/* LAN969X ONLY */
+#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT BIT(23)
+#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_SEL_STAT, x)
+#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_SEL_STAT, x)
+
+/* LAN969X ONLY */
+#define DSM_TAXI_CAL_CFG_CAL_SWITCH BIT(22)
+#define DSM_TAXI_CAL_CFG_CAL_SWITCH_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_SWITCH, x)
+#define DSM_TAXI_CAL_CFG_CAL_SWITCH_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_SWITCH, x)
+
+/* LAN969X ONLY */
+#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL BIT(21)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL_SET(x)\
+ FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_PGM_SEL, x)
+#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL_GET(x)\
+ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_SEL, x)
+
/* EACL:ES2_KEY_SELECT_PROFILE:VCAP_ES2_KEY_SEL */
#define EACL_VCAP_ES2_KEY_SEL(g, r) \
__REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_ES2_KEY_SELECT_PROFILE], \
@@ -6720,6 +6789,69 @@ extern const struct sparx5_regs *regs;
regs->gcnt[GC_PTP_PHASE_DETECTOR_CTRL], \
regs->gsize[GW_PTP_PHASE_DETECTOR_CTRL], 4, 0, 1, 4)
+/* LAN969X ONLY */
+/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_CTRL */
+#define PTP_TWOSTEP_CTRL \
+ __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 0, 0, 1, 4)
+
+#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA BIT(12)
+#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_OVWR_ENA, x)
+#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_PTP_OVWR_ENA, x)
+
+#define PTP_TWOSTEP_CTRL_PTP_NXT BIT(11)
+#define PTP_TWOSTEP_CTRL_PTP_NXT_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_NXT, x)
+#define PTP_TWOSTEP_CTRL_PTP_NXT_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_PTP_NXT, x)
+
+#define PTP_TWOSTEP_CTRL_PTP_VLD BIT(10)
+#define PTP_TWOSTEP_CTRL_PTP_VLD_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_VLD, x)
+#define PTP_TWOSTEP_CTRL_PTP_VLD_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_PTP_VLD, x)
+
+#define PTP_TWOSTEP_CTRL_STAMP_TX BIT(9)
+#define PTP_TWOSTEP_CTRL_STAMP_TX_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_STAMP_TX, x)
+#define PTP_TWOSTEP_CTRL_STAMP_TX_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_STAMP_TX, x)
+
+#define PTP_TWOSTEP_CTRL_STAMP_PORT GENMASK(8, 1)
+#define PTP_TWOSTEP_CTRL_STAMP_PORT_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_STAMP_PORT, x)
+#define PTP_TWOSTEP_CTRL_STAMP_PORT_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_STAMP_PORT, x)
+
+#define PTP_TWOSTEP_CTRL_PTP_OVFL BIT(0)
+#define PTP_TWOSTEP_CTRL_PTP_OVFL_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_OVFL, x)
+#define PTP_TWOSTEP_CTRL_PTP_OVFL_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_CTRL_PTP_OVFL, x)
+
+/* LAN969X ONLY */
+/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_STAMP_NSEC */
+#define PTP_TWOSTEP_STAMP_NSEC \
+ __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 4, 0, 1, 4)
+
+#define PTP_TWOSTEP_STAMP_NSEC_NS GENMASK(29, 0)
+#define PTP_TWOSTEP_STAMP_NSEC_NS_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_STAMP_NSEC_NS, x)
+#define PTP_TWOSTEP_STAMP_NSEC_NS_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_STAMP_NSEC_NS, x)
+
+/* LAN969X ONLY */
+/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_STAMP_SUBNS */
+#define PTP_TWOSTEP_STAMP_SUBNS \
+ __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 8, 0, 1, 4)
+
+#define PTP_TWOSTEP_STAMP_SUBNS_NS GENMASK(7, 0)
+#define PTP_TWOSTEP_STAMP_SUBNS_NS_SET(x)\
+ FIELD_PREP(PTP_TWOSTEP_STAMP_SUBNS_NS, x)
+#define PTP_TWOSTEP_STAMP_SUBNS_NS_GET(x)\
+ FIELD_GET(PTP_TWOSTEP_STAMP_SUBNS_NS, x)
+
/* QFWD:SYSTEM:SWITCH_PORT_MODE */
#define QFWD_SWITCH_PORT_MODE(r) \
__REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 0, r, \
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c
index 459a53676ae9..9806729e9c62 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c
@@ -24,8 +24,14 @@ static u32 sparx5_mirror_to_dir(bool ingress)
/* Get ports belonging to this mirror */
static u64 sparx5_mirror_port_get(struct sparx5 *sparx5, u32 idx)
{
- return (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32 |
- spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx));
+ u64 val;
+
+ val = spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx));
+
+ if (is_sparx5(sparx5))
+ val |= (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32;
+
+ return val;
}
/* Add port to mirror (only front ports) */
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
index d4e9986ef16a..1d34af78166a 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -64,16 +64,16 @@ void sparx5_set_port_ifh(struct sparx5 *sparx5, void *ifh_hdr, u16 portno)
/* MISC.CPU_MASK/DPORT = Destination port */
ifh_encode_bitfield(ifh_hdr, portno, 29, 8);
/* MISC.PIPELINE_PT */
- ifh_encode_bitfield(ifh_hdr, 16, 37, 5);
+ ifh_encode_bitfield(ifh_hdr, is_sparx5(sparx5) ? 16 : 17, 37, 5);
/* MISC.PIPELINE_ACT */
ifh_encode_bitfield(ifh_hdr, 1, 42, 3);
/* FWD.SRC_PORT = CPU */
ifh_encode_bitfield(ifh_hdr, sparx5_get_pgid(sparx5, SPX5_PORT_CPU_0),
- 46, 7);
+ 46, is_sparx5(sparx5) ? 7 : 6);
/* FWD.SFLOW_ID (disable SFlow sampling) */
- ifh_encode_bitfield(ifh_hdr, 124, 57, 7);
+ ifh_encode_bitfield(ifh_hdr, 124, is_sparx5(sparx5) ? 57 : 56, 7);
/* FWD.UPDATE_FCS = Enable. Enforce update of FCS. */
- ifh_encode_bitfield(ifh_hdr, 1, 67, 1);
+ ifh_encode_bitfield(ifh_hdr, 1, is_sparx5(sparx5) ? 67 : 66, 1);
}
void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op)
@@ -81,19 +81,25 @@ void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op)
ifh_encode_bitfield(ifh_hdr, rew_op, VSTAX + 32, 10);
}
-void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type)
+void sparx5_set_port_ifh_pdu_type(struct sparx5 *sparx5, void *ifh_hdr,
+ u32 pdu_type)
{
- ifh_encode_bitfield(ifh_hdr, pdu_type, 191, 4);
+ ifh_encode_bitfield(ifh_hdr, pdu_type, is_sparx5(sparx5) ? 191 : 190,
+ 4);
}
-void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset)
+void sparx5_set_port_ifh_pdu_w16_offset(struct sparx5 *sparx5, void *ifh_hdr,
+ u32 pdu_w16_offset)
{
- ifh_encode_bitfield(ifh_hdr, pdu_w16_offset, 195, 6);
+ ifh_encode_bitfield(ifh_hdr, pdu_w16_offset,
+ is_sparx5(sparx5) ? 195 : 194, 6);
}
-void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp)
+void sparx5_set_port_ifh_timestamp(struct sparx5 *sparx5, void *ifh_hdr,
+ u64 timestamp)
{
- ifh_encode_bitfield(ifh_hdr, timestamp, 232, 40);
+ ifh_encode_bitfield(ifh_hdr, timestamp, 232,
+ is_sparx5(sparx5) ? 40 : 38);
}
static int sparx5_port_open(struct net_device *ndev)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
index 5bfa86a71ac8..b6f635d85820 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
@@ -32,7 +32,7 @@ void sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp)
spx5_wr(0, sparx5, QS_XTR_FLUSH);
}
-void sparx5_ifh_parse(u32 *ifh, struct frame_info *info)
+void sparx5_ifh_parse(struct sparx5 *sparx5, u32 *ifh, struct frame_info *info)
{
u8 *xtr_hdr = (u8 *)ifh;
@@ -43,7 +43,8 @@ void sparx5_ifh_parse(u32 *ifh, struct frame_info *info)
((u32)xtr_hdr[29] << 8) |
((u32)xtr_hdr[30] << 0);
fwd = (fwd >> 5);
- info->src_port = FIELD_GET(GENMASK(7, 1), fwd);
+ info->src_port = spx5_field_get(GENMASK(is_sparx5(sparx5) ? 7 : 6, 1),
+ fwd);
/*
* Bit 270-271 are occasionally unexpectedly set by the hardware,
@@ -72,7 +73,7 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp));
/* Decode IFH (what's needed) */
- sparx5_ifh_parse(ifh, &fi);
+ sparx5_ifh_parse(sparx5, ifh, &fi);
/* Map to port netdev */
port = fi.src_port < sparx5->data->consts->n_ports ?
@@ -242,9 +243,12 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
sparx5_set_port_ifh_rew_op(ifh, SPARX5_SKB_CB(skb)->rew_op);
- sparx5_set_port_ifh_pdu_type(ifh, SPARX5_SKB_CB(skb)->pdu_type);
- sparx5_set_port_ifh_pdu_w16_offset(ifh, SPARX5_SKB_CB(skb)->pdu_w16_offset);
- sparx5_set_port_ifh_timestamp(ifh, SPARX5_SKB_CB(skb)->ts_id);
+ sparx5_set_port_ifh_pdu_type(sparx5, ifh,
+ SPARX5_SKB_CB(skb)->pdu_type);
+ sparx5_set_port_ifh_pdu_w16_offset(sparx5, ifh,
+ SPARX5_SKB_CB(skb)->pdu_w16_offset);
+ sparx5_set_port_ifh_timestamp(sparx5, ifh,
+ SPARX5_SKB_CB(skb)->ts_id);
}
skb_tx_timestamp(skb);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
index 0b38b4cb0929..1401761c6251 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
@@ -476,6 +476,9 @@ static int sparx5_port_fifo_sz(struct sparx5 *sparx5,
u32 mac_width = 8;
u32 addition = 0;
+ if (!is_sparx5(sparx5))
+ return 0;
+
switch (speed) {
case SPEED_25000:
return 0;
@@ -921,6 +924,20 @@ static int sparx5_port_config_low_set(struct sparx5 *sparx5,
sparx5,
DEV2G5_DEV_RST_CTRL(port->portno));
+ /* Enable PHAD_CTRL for better timestamping */
+ if (!is_sparx5(sparx5)) {
+ for (int i = 0; i < 2; ++i) {
+ /* Divide the port clock by three for the two
+ * phase detection registers.
+ */
+ spx5_rmw(DEV2G5_PHAD_CTRL_DIV_CFG_SET(3) |
+ DEV2G5_PHAD_CTRL_PHAD_ENA_SET(1),
+ DEV2G5_PHAD_CTRL_DIV_CFG |
+ DEV2G5_PHAD_CTRL_PHAD_ENA,
+ sparx5, DEV2G5_PHAD_CTRL(port->portno, i));
+ }
+ }
+
return 0;
}
@@ -978,6 +995,7 @@ int sparx5_port_config(struct sparx5 *sparx5,
struct sparx5_port_config *conf)
{
bool high_speed_dev = sparx5_is_baser(conf->portmode);
+ const struct sparx5_ops *ops = sparx5->data->ops;
int err, urgency, stop_wm;
err = sparx5_port_verify_speed(sparx5, port, conf);
@@ -993,6 +1011,13 @@ int sparx5_port_config(struct sparx5 *sparx5,
if (err)
return err;
+ if (!is_sparx5(sparx5) && ops->is_port_10g(port->portno) &&
+ conf->speed < SPEED_10000)
+ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(1),
+ DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA,
+ sparx5,
+ DSM_DEV_TX_STOP_WM_CFG(port->portno));
+
/* Set the DSM stop watermark */
stop_wm = sparx5_port_fifo_sz(sparx5, port->portno, conf->speed);
spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(stop_wm),
@@ -1144,6 +1169,27 @@ int sparx5_port_init(struct sparx5 *sparx5,
DEV25G_PCS25G_SD_CFG(pix));
}
+ if (!is_sparx5(sparx5)) {
+ void __iomem *inst;
+ u32 dev, tinst;
+
+ if (ops->is_port_10g(port->portno)) {
+ dev = sparx5_to_high_dev(sparx5, port->portno);
+ tinst = sparx5_port_dev_index(sparx5, port->portno);
+ inst = spx5_inst_get(sparx5, dev, tinst);
+
+ spx5_inst_wr(5, inst,
+ DEV10G_PTP_STAMPER_CFG(port->portno));
+ } else if (ops->is_port_5g(port->portno)) {
+ dev = sparx5_to_high_dev(sparx5, port->portno);
+ tinst = sparx5_port_dev_index(sparx5, port->portno);
+ inst = spx5_inst_get(sparx5, dev, tinst);
+
+ spx5_inst_wr(5, inst,
+ DEV5G_PTP_STAMPER_CFG(port->portno));
+ }
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
index 9b15e44f9e64..1c2903700a9c 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
@@ -11,8 +11,6 @@
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
-#define SPARX5_MAX_PTP_ID 512
-
#define TOD_ACC_PIN 0x4
enum {
@@ -38,6 +36,9 @@ static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5)
case SPX5_CORE_CLOCK_250MHZ:
res = 2301339409586;
break;
+ case SPX5_CORE_CLOCK_328MHZ:
+ res = 1756832768924;
+ break;
case SPX5_CORE_CLOCK_500MHZ:
res = 1150669704793;
break;
@@ -60,6 +61,9 @@ static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
case SPX5_CORE_CLOCK_250MHZ:
res = 0x1FF0000000000000;
break;
+ case SPX5_CORE_CLOCK_328MHZ:
+ res = 0x18604697DD0F9B5B;
+ break;
case SPX5_CORE_CLOCK_500MHZ:
res = 0x0FF8000000000000;
break;
@@ -269,9 +273,9 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port,
spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
}
-static void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
- struct timespec64 *ts,
- u32 nsec)
+void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
+ struct timespec64 *ts,
+ u32 nsec)
{
/* Read current PTP time to get seconds */
const struct sparx5_consts *consts = sparx5->data->consts;
@@ -299,6 +303,7 @@ static void sparx5_get_hwtimestamp(struct sparx5 *sparx5,
spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
}
+EXPORT_SYMBOL_GPL(sparx5_get_hwtimestamp);
irqreturn_t sparx5_ptp_irq_handler(int irq, void *args)
{
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
index d065f8c40d37..e580670f3992 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c
@@ -367,9 +367,10 @@ static u32 sparx5_weight_to_hw_cost(u32 weight_min, u32 weight)
static int sparx5_dwrr_conf_set(struct sparx5_port *port,
struct sparx5_dwrr *dwrr)
{
+ u32 layer = is_sparx5(port->sparx5) ? 2 : 1;
int i;
- spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(2) |
+ spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(layer) |
HSCH_HSCH_CFG_CFG_CFG_SE_IDX_SET(port->portno),
HSCH_HSCH_CFG_CFG_HSCH_LAYER | HSCH_HSCH_CFG_CFG_CFG_SE_IDX,
port->sparx5, HSCH_HSCH_CFG_CFG);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
index 1db212ce3df7..220e81b714d4 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c
@@ -4,7 +4,7 @@
* Copyright (c) 2024 Microchip Technology Inc.
*/
-/* This file is autogenerated by cml-utils 2024-09-24 14:02:24 +0200.
+/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200.
* Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b
*/
@@ -140,6 +140,7 @@ const unsigned int sparx5_gsize[GSIZE_LAST] = {
[GW_ANA_L2_COMMON] = 700,
[GW_ASM_CFG] = 1088,
[GW_CPU_CPU_REGS] = 204,
+ [GW_DEV2G5_PHASE_DETECTOR_CTRL] = 8,
[GW_FDMA_FDMA] = 428,
[GW_GCB_CHIP_REGS] = 424,
[GW_HSCH_TAS_CONFIG] = 12,
@@ -157,6 +158,8 @@ const unsigned int sparx5_fpos[FPOS_LAST] = {
[FP_CPU_PROC_CTRL_CP15S_DISABLE] = 6,
[FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE] = 5,
[FP_CPU_PROC_CTRL_L2_FLUSH_REQ] = 1,
+ [FP_DEV2G5_PHAD_CTRL_PHAD_ENA] = 7,
+ [FP_DEV2G5_PHAD_CTRL_PHAD_FAILED] = 6,
[FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE] = 7,
[FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY] = 6,
[FP_FDMA_CH_CFG_CH_INJ_PORT] = 5,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
index c4e8b581c1f3..ea28130c2341 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h
@@ -4,7 +4,7 @@
* Copyright (c) 2024 Microchip Technology Inc.
*/
-/* This file is autogenerated by cml-utils 2024-09-24 14:02:24 +0200.
+/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200.
* Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b
*/
@@ -151,6 +151,7 @@ enum sparx5_gsize_enum {
GW_ANA_L2_COMMON,
GW_ASM_CFG,
GW_CPU_CPU_REGS,
+ GW_DEV2G5_PHASE_DETECTOR_CTRL,
GW_FDMA_FDMA,
GW_GCB_CHIP_REGS,
GW_HSCH_TAS_CONFIG,
@@ -169,6 +170,8 @@ enum sparx5_fpos_enum {
FP_CPU_PROC_CTRL_CP15S_DISABLE,
FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE,
FP_CPU_PROC_CTRL_L2_FLUSH_REQ,
+ FP_DEV2G5_PHAD_CTRL_PHAD_ENA,
+ FP_DEV2G5_PHAD_CTRL_PHAD_FAILED,
FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE,
FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY,
FP_FDMA_CH_CFG_CH_INJ_PORT,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c b/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c
index df1d15600aad..98a3f44c569c 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c
@@ -25,17 +25,13 @@ struct sparx5_sdlb_group *sparx5_get_sdlb_group(int idx)
return &sdlb_groups[idx];
}
-int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5)
+u64 sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5)
{
- u32 clk_per_100ps;
u64 clk_hz;
- clk_per_100ps = HSCH_SYS_CLK_PER_100PS_GET(spx5_rd(sparx5,
- HSCH_SYS_CLK_PER));
- if (!clk_per_100ps)
- clk_per_100ps = SPX5_CLK_PER_100PS_DEFAULT;
+ clk_hz = (10 * 1000 * 1000) /
+ (sparx5_clk_period(sparx5->coreclock) / 100);
- clk_hz = (10 * 1000 * 1000) / clk_per_100ps;
return clk_hz *= 1000;
}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
index c3bbed140554..4dc1ebd5d510 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
@@ -1284,6 +1284,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
/* Setup PSFP */
if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
+ if (!sparx5_has_feature(sparx5, SPX5_FEATURE_PSFP)) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
tc_pol_idx, &sg, &fm, &sf);
if (err)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h
index 7d106f1276fe..e68f5639a40a 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h
@@ -10,6 +10,8 @@
#ifndef __SPARX5_VCAP_AG_API_H__
#define __SPARX5_VCAP_AG_API_H__
+#include "vcap_api.h"
+
/* VCAPs */
extern const struct vcap_info sparx5_vcaps[];
extern const struct vcap_statistics sparx5_vcap_stats;
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
index 967c8621c250..25066ddb8d4d 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
@@ -17,7 +17,6 @@
#define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */
#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */
-#define SPARX5_IS2_LOOKUPS 4
#define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \
(ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \
ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \
@@ -27,7 +26,6 @@
ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \
ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp))
-#define SPARX5_IS0_LOOKUPS 6
#define VCAP_IS0_KEYSEL(_ena, _etype, _ipv4, _ipv6, _mpls_uc, _mpls_mc, _mlbs) \
(ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(_ena) | \
ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(_etype) | \
@@ -37,31 +35,17 @@
ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_SET(_mpls_mc) | \
ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_SET(_mlbs))
-#define SPARX5_ES0_LOOKUPS 1
#define VCAP_ES0_KEYSEL(_key) (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(_key))
#define SPARX5_STAT_ESDX_GRN_PKTS 0x300
#define SPARX5_STAT_ESDX_YEL_PKTS 0x301
-#define SPARX5_ES2_LOOKUPS 2
#define VCAP_ES2_KEYSEL(_ena, _arp, _ipv4, _ipv6) \
(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(_ena) | \
EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(_arp) | \
EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(_ipv4) | \
EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(_ipv6))
-static struct sparx5_vcap_inst {
- enum vcap_type vtype; /* type of vcap */
- int vinst; /* instance number within the same type */
- int lookups; /* number of lookups in this vcap type */
- int lookups_per_instance; /* number of lookups in this instance */
- int first_cid; /* first chain id in this vcap */
- int last_cid; /* last chain id in this vcap */
- int count; /* number of available addresses, not in super vcap */
- int map_id; /* id in the super vcap block mapping (if applicable) */
- int blockno; /* starting block in super vcap (if applicable) */
- int blocks; /* number of blocks in super vcap (if applicable) */
- bool ingress; /* is vcap in the ingress path */
-} sparx5_vcap_inst_cfg[] = {
+const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[] = {
{
.vtype = VCAP_TYPE_IS0, /* CLM-0 */
.vinst = 0,
@@ -1793,6 +1777,7 @@ void sparx5_vcap_set_port_keyset(struct net_device *ndev,
static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
int portno, lookup;
u32 keysel;
@@ -1804,7 +1789,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5,
VCAP_IS0_PS_MPLS_FOLLOW_ETYPE,
VCAP_IS0_PS_MLBS_FOLLOW_ETYPE);
for (lookup = 0; lookup < admin->lookups; ++lookup) {
- for (portno = 0; portno < SPX5_PORTS; ++portno) {
+ for (portno = 0; portno < consts->n_ports; ++portno) {
spx5_wr(keysel, sparx5,
ANA_CL_ADV_CL_CFG(portno, lookup));
spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA,
@@ -1819,6 +1804,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5,
static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
int portno, lookup;
u32 keysel;
@@ -1829,13 +1815,13 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5,
VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
VCAP_IS2_PS_ARP_ARP);
for (lookup = 0; lookup < admin->lookups; ++lookup) {
- for (portno = 0; portno < SPX5_PORTS; ++portno) {
+ for (portno = 0; portno < consts->n_ports; ++portno) {
spx5_wr(keysel, sparx5,
ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
}
}
/* IS2 lookups are in bit 0:3 */
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf),
ANA_ACL_VCAP_S2_CFG_SEC_ENA,
sparx5,
@@ -1846,11 +1832,12 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5,
static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
int portno;
u32 keysel;
keysel = VCAP_ES0_KEYSEL(VCAP_ES0_PS_FORCE_ISDX_LOOKUPS);
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_rmw(keysel, REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA,
sparx5, REW_RTAG_ETAG_CTRL(portno));
@@ -1862,6 +1849,7 @@ static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5,
static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
int portno, lookup;
u32 keysel;
@@ -1869,7 +1857,7 @@ static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5,
VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER,
VCAP_ES2_PS_IPV6_IP_7TUPLE);
for (lookup = 0; lookup < admin->lookups; ++lookup)
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_wr(keysel, sparx5,
EACL_VCAP_ES2_KEY_SEL(portno, lookup));
}
@@ -1901,19 +1889,20 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
int portno, lookup;
switch (admin->vtype) {
case VCAP_TYPE_IS0:
for (lookup = 0; lookup < admin->lookups; ++lookup)
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(0),
ANA_CL_ADV_CL_CFG_LOOKUP_ENA,
sparx5,
ANA_CL_ADV_CL_CFG(portno, lookup));
break;
case VCAP_TYPE_IS2:
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0),
ANA_ACL_VCAP_S2_CFG_SEC_ENA,
sparx5,
@@ -1925,7 +1914,7 @@ static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,
break;
case VCAP_TYPE_ES2:
for (lookup = 0; lookup < admin->lookups; ++lookup)
- for (portno = 0; portno < SPX5_PORTS; ++portno)
+ for (portno = 0; portno < consts->n_ports; ++portno)
spx5_rmw(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(0),
EACL_VCAP_ES2_KEY_SEL_KEY_ENA,
sparx5,
@@ -2042,6 +2031,7 @@ static void sparx5_vcap_block_alloc(struct sparx5 *sparx5,
/* Allocate a vcap control and vcap instances and configure the system */
int sparx5_vcap_init(struct sparx5 *sparx5)
{
+ const struct sparx5_consts *consts = sparx5->data->consts;
const struct sparx5_vcap_inst *cfg;
struct vcap_control *ctrl;
struct vcap_admin *admin;
@@ -2063,14 +2053,14 @@ int sparx5_vcap_init(struct sparx5 *sparx5)
sparx5->vcap_ctrl = ctrl;
/* select the sparx5 VCAP model */
- ctrl->vcaps = sparx5_vcaps;
- ctrl->stats = &sparx5_vcap_stats;
+ ctrl->vcaps = consts->vcaps;
+ ctrl->stats = consts->vcap_stats;
/* Setup callbacks to allow the API to use the VCAP HW */
ctrl->ops = &sparx5_vcap_ops;
INIT_LIST_HEAD(&ctrl->list);
for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) {
- cfg = &sparx5_vcap_inst_cfg[idx];
+ cfg = &consts->vcaps_cfg[idx];
admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg);
if (IS_ERR(admin)) {
err = PTR_ERR(admin);
@@ -2085,7 +2075,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5)
list_add_tail(&admin->list, &ctrl->list);
}
dir = vcap_debugfs(sparx5->dev, sparx5->debugfs_root, ctrl);
- for (idx = 0; idx < SPX5_PORTS; ++idx)
+ for (idx = 0; idx < consts->n_ports; ++idx)
if (sparx5->ports[idx])
vcap_port_debugfs(sparx5->dev, dir, ctrl,
sparx5->ports[idx]->ndev);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h
index 2684d9199b05..d0a42406bf26 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h
@@ -16,6 +16,11 @@
#include "vcap_api.h"
#include "vcap_api_client.h"
+#define SPARX5_IS2_LOOKUPS 4
+#define SPARX5_IS0_LOOKUPS 6
+#define SPARX5_ES0_LOOKUPS 1
+#define SPARX5_ES2_LOOKUPS 2
+
#define SPARX5_VCAP_CID_IS0_L0 VCAP_CID_INGRESS_L0 /* IS0/CLM lookup 0 */
#define SPARX5_VCAP_CID_IS0_L1 VCAP_CID_INGRESS_L1 /* IS0/CLM lookup 1 */
#define SPARX5_VCAP_CID_IS0_L2 VCAP_CID_INGRESS_L2 /* IS0/CLM lookup 2 */
@@ -40,6 +45,22 @@
#define SPARX5_VCAP_CID_ES2_MAX \
(VCAP_CID_EGRESS_STAGE2_L1 + VCAP_CID_LOOKUP_SIZE - 1) /* ES2 Max */
+struct sparx5_vcap_inst {
+ enum vcap_type vtype; /* type of vcap */
+ int vinst; /* instance number within the same type */
+ int lookups; /* number of lookups in this vcap type */
+ int lookups_per_instance; /* number of lookups in this instance */
+ int first_cid; /* first chain id in this vcap */
+ int last_cid; /* last chain id in this vcap */
+ int count; /* number of available addresses, not in super vcap */
+ int map_id; /* id in the super vcap block mapping (if applicable) */
+ int blockno; /* starting block in super vcap (if applicable) */
+ int blocks; /* number of blocks in super vcap (if applicable) */
+ bool ingress; /* is vcap in the ingress path */
+};
+
+extern const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[];
+
/* IS0 port keyset selection control */
/* IS0 ethernet, IPv4, IPv6 traffic type keyset generation */
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 349f11bf8e64..c419626073f5 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -91,53 +91,34 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
{
struct mana_port_context *apc = netdev_priv(ndev);
unsigned int num_queues = apc->num_queues;
- u8 *p = data;
int i;
if (stringset != ETH_SS_STATS)
return;
- for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++) {
- memcpy(p, mana_eth_stats[i].name, ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++)
+ ethtool_puts(&data, mana_eth_stats[i].name);
for (i = 0; i < num_queues; i++) {
- sprintf(p, "rx_%d_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_%d_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_%d_xdp_drop", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_%d_xdp_tx", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "rx_%d_xdp_redirect", i);
- p += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "rx_%d_packets", i);
+ ethtool_sprintf(&data, "rx_%d_bytes", i);
+ ethtool_sprintf(&data, "rx_%d_xdp_drop", i);
+ ethtool_sprintf(&data, "rx_%d_xdp_tx", i);
+ ethtool_sprintf(&data, "rx_%d_xdp_redirect", i);
}
for (i = 0; i < num_queues; i++) {
- sprintf(p, "tx_%d_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_xdp_xmit", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_tso_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_tso_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_tso_inner_packets", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_tso_inner_bytes", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_long_pkt_fmt", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_short_pkt_fmt", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_csum_partial", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "tx_%d_mana_map_err", i);
- p += ETH_GSTRING_LEN;
+ ethtool_sprintf(&data, "tx_%d_packets", i);
+ ethtool_sprintf(&data, "tx_%d_bytes", i);
+ ethtool_sprintf(&data, "tx_%d_xdp_xmit", i);
+ ethtool_sprintf(&data, "tx_%d_tso_packets", i);
+ ethtool_sprintf(&data, "tx_%d_tso_bytes", i);
+ ethtool_sprintf(&data, "tx_%d_tso_inner_packets", i);
+ ethtool_sprintf(&data, "tx_%d_tso_inner_bytes", i);
+ ethtool_sprintf(&data, "tx_%d_long_pkt_fmt", i);
+ ethtool_sprintf(&data, "tx_%d_short_pkt_fmt", i);
+ ethtool_sprintf(&data, "tx_%d_csum_partial", i);
+ ethtool_sprintf(&data, "tx_%d_mana_map_err", i);
}
}
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index a057ec3dab97..986b1f150e3b 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -228,6 +228,32 @@ ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
return 0;
}
+static int
+ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload *f,
+ const struct flow_action_entry *a, bool mirror,
+ struct netlink_ext_ack *extack)
+{
+ const char *act_string = mirror ? "mirror" : "redirect";
+ int egress_port = ocelot->ops->netdev_to_port(a->dev);
+ enum flow_action_id offloadable_act_id;
+
+ offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT;
+
+ /* Mirroring towards foreign interfaces is handled in software */
+ if (egress_port < 0 || a->id != offloadable_act_id) {
+ if (f->common.skip_sw) {
+ NL_SET_ERR_MSG_FMT(extack,
+ "Can only %s to %s if filter also runs in software",
+ act_string, egress_port < 0 ?
+ "CPU" : "ingress of ocelot port");
+ return -EOPNOTSUPP;
+ }
+ egress_port = ocelot->num_phys_ports;
+ }
+
+ return egress_port;
+}
+
static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
bool ingress, struct flow_cls_offload *f,
struct ocelot_vcap_filter *filter)
@@ -356,6 +382,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break;
case FLOW_ACTION_REDIRECT:
+ case FLOW_ACTION_REDIRECT_INGRESS:
if (filter->block_id != VCAP_IS2) {
NL_SET_ERR_MSG_MOD(extack,
"Redirect action can only be offloaded to VCAP IS2");
@@ -366,17 +393,19 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
"Last action must be GOTO");
return -EOPNOTSUPP;
}
- egress_port = ocelot->ops->netdev_to_port(a->dev);
- if (egress_port < 0) {
- NL_SET_ERR_MSG_MOD(extack,
- "Destination not an ocelot port");
- return -EOPNOTSUPP;
- }
+
+ egress_port = ocelot_flower_parse_egress_port(ocelot, f,
+ a, false,
+ extack);
+ if (egress_port < 0)
+ return egress_port;
+
filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
filter->action.port_mask = BIT(egress_port);
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
break;
case FLOW_ACTION_MIRRED:
+ case FLOW_ACTION_MIRRED_INGRESS:
if (filter->block_id != VCAP_IS2) {
NL_SET_ERR_MSG_MOD(extack,
"Mirror action can only be offloaded to VCAP IS2");
@@ -387,12 +416,13 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
"Last action must be GOTO");
return -EOPNOTSUPP;
}
- egress_port = ocelot->ops->netdev_to_port(a->dev);
- if (egress_port < 0) {
- NL_SET_ERR_MSG_MOD(extack,
- "Destination not an ocelot port");
- return -EOPNOTSUPP;
- }
+
+ egress_port = ocelot_flower_parse_egress_port(ocelot, f,
+ a, true,
+ extack);
+ if (egress_port < 0)
+ return egress_port;
+
filter->egress_port.value = egress_port;
filter->action.mirror_ena = true;
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index 7c9540a71725..558e03301aa8 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -730,7 +730,7 @@ static void ocelot_get_stats64(struct net_device *dev,
static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr,
- u16 vid, u16 flags,
+ u16 vid, u16 flags, bool *notified,
struct netlink_ext_ack *extack)
{
struct ocelot_port_private *priv = netdev_priv(dev);
@@ -744,7 +744,7 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
- struct netlink_ext_ack *extack)
+ bool *notified, struct netlink_ext_ack *extack)
{
struct ocelot_port_private *priv = netdev_priv(dev);
struct ocelot_port *ocelot_port = &priv->port;
diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
index d215efc6cad0..f1c6c47564b1 100644
--- a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
@@ -1179,7 +1179,7 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget)
} while (u64_stats_fetch_retry(&r_vec->rx_sync, start));
dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
- net_dim(&r_vec->rx_dim, dim_sample);
+ net_dim(&r_vec->rx_dim, &dim_sample);
}
if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) {
@@ -1194,7 +1194,7 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget)
} while (u64_stats_fetch_retry(&r_vec->tx_sync, start));
dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
- net_dim(&r_vec->tx_dim, dim_sample);
+ net_dim(&r_vec->tx_dim, &dim_sample);
}
return pkts_polled;
diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
index dae5af7d1845..ebeb6ab4465c 100644
--- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
@@ -1289,7 +1289,7 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget)
} while (u64_stats_fetch_retry(&r_vec->rx_sync, start));
dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
- net_dim(&r_vec->rx_dim, dim_sample);
+ net_dim(&r_vec->rx_dim, &dim_sample);
}
if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) {
@@ -1304,7 +1304,7 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget)
} while (u64_stats_fetch_retry(&r_vec->tx_sync, start));
dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample);
- net_dim(&r_vec->tx_dim, dim_sample);
+ net_dim(&r_vec->tx_dim, &dim_sample);
}
return pkts_polled;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 6e0929af0f72..98e098c09c03 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -829,7 +829,7 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
return err;
}
- irq_set_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask);
+ irq_update_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask);
nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, r_vec->irq_vector,
r_vec->irq_entry);
@@ -840,7 +840,7 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
static void
nfp_net_cleanup_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec)
{
- irq_set_affinity_hint(r_vec->irq_vector, NULL);
+ irq_update_affinity_hint(r_vec->irq_vector, NULL);
nfp_net_napi_del(&nn->dp, r_vec);
free_irq(r_vec->irq_vector, r_vec);
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
index b93791d6b593..f5dc876eb500 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
@@ -394,6 +394,7 @@ err_out_free_irqs:
err_out_pci:
ionic_dev_teardown(ionic);
ionic_clear_pci(ionic);
+ ionic_debugfs_del_dev(ionic);
err_out:
mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
index 0eeda7e502db..2ac59564ded1 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
@@ -928,7 +928,7 @@ static void ionic_dim_update(struct ionic_qcq *qcq, int napi_mode)
dim_update_sample(qcq->cq.bound_intr->rearm_count,
pkts, bytes, &dim_sample);
- net_dim(&qcq->dim, dim_sample);
+ net_dim(&qcq->dim, &dim_sample);
}
int ionic_tx_napi(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
index 8c4cb910e09b..e7d8999049e1 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
@@ -648,18 +648,18 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
static void
netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
- int index;
+ const char *str;
+ int i;
switch (stringset) {
case ETH_SS_TEST:
- memcpy(data, *netxen_nic_gstrings_test,
- NETXEN_NIC_TEST_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < NETXEN_NIC_TEST_LEN; i++)
+ ethtool_puts(&data, netxen_nic_gstrings_test[i]);
break;
case ETH_SS_STATS:
- for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
- memcpy(data + index * ETH_GSTRING_LEN,
- netxen_nic_gstrings_stats[index].stat_string,
- ETH_GSTRING_LEN);
+ for (i = 0; i < NETXEN_NIC_STATS_LEN; i++) {
+ str = netxen_nic_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
break;
}
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index 97b059be1041..c553da16d4b1 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -272,16 +272,14 @@ static void qede_get_strings_stats_txq(struct qede_dev *edev,
{
int i;
- for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
+ for (i = 0; i < QEDE_NUM_TQSTATS; i++)
if (txq->is_xdp)
- sprintf(*buf, "%d [XDP]: %s",
- QEDE_TXQ_XDP_TO_IDX(edev, txq),
- qede_tqstats_arr[i].string);
+ ethtool_sprintf(buf, "%d [XDP]: %s",
+ QEDE_TXQ_XDP_TO_IDX(edev, txq),
+ qede_tqstats_arr[i].string);
else
- sprintf(*buf, "%d_%d: %s", txq->index, txq->cos,
- qede_tqstats_arr[i].string);
- *buf += ETH_GSTRING_LEN;
- }
+ ethtool_sprintf(buf, "%d_%d: %s", txq->index, txq->cos,
+ qede_tqstats_arr[i].string);
}
static void qede_get_strings_stats_rxq(struct qede_dev *edev,
@@ -289,11 +287,9 @@ static void qede_get_strings_stats_rxq(struct qede_dev *edev,
{
int i;
- for (i = 0; i < QEDE_NUM_RQSTATS; i++) {
- sprintf(*buf, "%d: %s", rxq->rxq_id,
- qede_rqstats_arr[i].string);
- *buf += ETH_GSTRING_LEN;
- }
+ for (i = 0; i < QEDE_NUM_RQSTATS; i++)
+ ethtool_sprintf(buf, "%d: %s", rxq->rxq_id,
+ qede_rqstats_arr[i].string);
}
static bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index)
@@ -331,26 +327,26 @@ static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
for (i = 0; i < QEDE_NUM_STATS; i++) {
if (qede_is_irrelevant_stat(edev, i))
continue;
- strcpy(buf, qede_stats_arr[i].string);
- buf += ETH_GSTRING_LEN;
+ ethtool_puts(&buf, qede_stats_arr[i].string);
}
}
static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct qede_dev *edev = netdev_priv(dev);
+ int i;
switch (stringset) {
case ETH_SS_STATS:
qede_get_strings_stats(edev, buf);
break;
case ETH_SS_PRIV_FLAGS:
- memcpy(buf, qede_private_arr,
- ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN);
+ for (i = 0; i < QEDE_PRI_FLAG_LEN; i++)
+ ethtool_puts(&buf, qede_private_arr[i]);
break;
case ETH_SS_TEST:
- memcpy(buf, qede_tests_str_arr,
- ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX);
+ for (i = 0; i < QEDE_ETHTOOL_TEST_MAX; i++)
+ ethtool_puts(&buf, qede_tests_str_arr[i]);
break;
default:
DP_VERBOSE(edev, QED_MSG_DEBUG,
@@ -508,7 +504,7 @@ static int qede_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
typeof(cmd->link_modes) *link_modes = &cmd->link_modes;
- struct ethtool_link_settings *base = &cmd->base;
+ struct ethtool_link_settings_hdr *base = &cmd->base;
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
@@ -541,7 +537,7 @@ static int qede_get_link_ksettings(struct net_device *dev,
static int qede_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
- const struct ethtool_link_settings *base = &cmd->base;
+ const struct ethtool_link_settings_hdr *base = &cmd->base;
const struct ethtool_forced_speed_map *map;
struct qede_dev *edev = netdev_priv(dev);
struct qed_link_output current_link;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index c1436e1554de..17450e05c437 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1196,60 +1196,56 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int index, i, num_stats;
+ const char *str;
switch (stringset) {
case ETH_SS_TEST:
- memcpy(data, *qlcnic_gstrings_test,
- QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < QLCNIC_TEST_LEN; i++)
+ ethtool_puts(&data, qlcnic_gstrings_test[i]);
break;
case ETH_SS_STATS:
num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings);
- for (i = 0; i < adapter->drv_tx_rings; i++) {
+ for (i = 0; i < adapter->drv_tx_rings; i++)
for (index = 0; index < num_stats; index++) {
- sprintf(data, "tx_queue_%d %s", i,
- qlcnic_tx_queue_stats_strings[index]);
- data += ETH_GSTRING_LEN;
+ str = qlcnic_tx_queue_stats_strings[index];
+ ethtool_sprintf(&data, "tx_queue_%d %s", i,
+ str);
}
- }
- for (index = 0; index < QLCNIC_STATS_LEN; index++) {
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_gstrings_stats[index].stat_string,
- ETH_GSTRING_LEN);
+ for (i = 0; i < QLCNIC_STATS_LEN; i++) {
+ str = qlcnic_gstrings_stats[i].stat_string;
+ ethtool_puts(&data, str);
}
if (qlcnic_83xx_check(adapter)) {
num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings);
- for (i = 0; i < num_stats; i++, index++)
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_83xx_tx_stats_strings[i],
- ETH_GSTRING_LEN);
+ for (i = 0; i < num_stats; i++) {
+ str = qlcnic_83xx_tx_stats_strings[i];
+ ethtool_puts(&data, str);
+ }
num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
- for (i = 0; i < num_stats; i++, index++)
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_83xx_mac_stats_strings[i],
- ETH_GSTRING_LEN);
+ for (i = 0; i < num_stats; i++) {
+ str = qlcnic_83xx_mac_stats_strings[i];
+ ethtool_puts(&data, str);
+ }
num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
- for (i = 0; i < num_stats; i++, index++)
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_83xx_rx_stats_strings[i],
- ETH_GSTRING_LEN);
+ for (i = 0; i < num_stats; i++) {
+ str = qlcnic_83xx_rx_stats_strings[i];
+ ethtool_puts(&data, str);
+ }
return;
} else {
num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
- for (i = 0; i < num_stats; i++, index++)
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_83xx_mac_stats_strings[i],
- ETH_GSTRING_LEN);
+ for (i = 0; i < num_stats; i++) {
+ str = qlcnic_83xx_mac_stats_strings[i];
+ ethtool_puts(&data, str);
+ }
}
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
- for (i = 0; i < num_stats; index++, i++) {
- memcpy(data + index * ETH_GSTRING_LEN,
- qlcnic_device_gstrings_stats[i],
- ETH_GSTRING_LEN);
- }
+ for (i = 0; i < num_stats; i++)
+ ethtool_puts(&data, qlcnic_device_gstrings_stats[i]);
}
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index b3588a1ebc25..eb69121df726 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -367,7 +367,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *netdev,
- const unsigned char *addr, u16 vid,
+ const unsigned char *addr, u16 vid, bool *notified,
struct netlink_ext_ack *extack)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -394,7 +394,7 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *netdev,
const unsigned char *addr, u16 vid, u16 flags,
- struct netlink_ext_ack *extack)
+ bool *notified, struct netlink_ext_ack *extack)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int err = 0;
diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h
index e2db944e6fa8..be4c9622618d 100644
--- a/drivers/net/ethernet/realtek/r8169.h
+++ b/drivers/net/ethernet/realtek/r8169.h
@@ -68,6 +68,7 @@ enum mac_version {
/* support for RTL_GIGA_MAC_VER_60 has been removed */
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
+ RTL_GIGA_MAC_VER_64,
RTL_GIGA_MAC_VER_65,
RTL_GIGA_MAC_VER_66,
RTL_GIGA_MAC_NONE
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 79e7b223bd5b..739707a7b40f 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -56,6 +56,7 @@
#define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw"
#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
+#define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw"
#define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw"
#define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw"
@@ -139,6 +140,7 @@ static const struct {
[RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3},
/* reserve 62 for CFG_METHOD_4 in the vendor driver */
[RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
+ [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1},
[RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2},
[RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3},
};
@@ -345,6 +347,8 @@ enum rtl8125_registers {
TxPoll_8125 = 0x90,
LEDSEL3 = 0x96,
MAC0_BKP = 0x19e0,
+ RSS_CTRL_8125 = 0x4500,
+ Q_NUM_CTRL_8125 = 0x4800,
EEE_TXIDLE_TIMER_8125 = 0x6048,
};
@@ -658,13 +662,9 @@ struct rtl8169_private {
struct work_struct work;
} wk;
- 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;
-
unsigned supports_gmii:1;
unsigned aspm_manageable:1;
unsigned dash_enabled:1;
@@ -707,6 +707,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3);
MODULE_FIRMWARE(FIRMWARE_8107E_2);
MODULE_FIRMWARE(FIRMWARE_8125A_3);
MODULE_FIRMWARE(FIRMWARE_8125B_2);
+MODULE_FIRMWARE(FIRMWARE_8125D_1);
MODULE_FIRMWARE(FIRMWARE_8126A_2);
MODULE_FIRMWARE(FIRMWARE_8126A_3);
@@ -717,22 +718,12 @@ static inline struct device *tp_to_dev(struct rtl8169_private *tp)
static void rtl_lock_config_regs(struct rtl8169_private *tp)
{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
- if (!--tp->cfg9346_usage_count)
- RTL_W8(tp, Cfg9346, Cfg9346_Lock);
- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
+ RTL_W8(tp, Cfg9346, Cfg9346_Lock);
}
static void rtl_unlock_config_regs(struct rtl8169_private *tp)
{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags);
- if (!tp->cfg9346_usage_count++)
- RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
- raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags);
+ RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
}
static void rtl_pci_commit(struct rtl8169_private *tp)
@@ -743,24 +734,32 @@ static void rtl_pci_commit(struct rtl8169_private *tp)
static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set)
{
- unsigned long flags;
u8 val;
- raw_spin_lock_irqsave(&tp->config25_lock, flags);
val = RTL_R8(tp, Config2);
RTL_W8(tp, Config2, (val & ~clear) | set);
- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
}
static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set)
{
- unsigned long flags;
u8 val;
- raw_spin_lock_irqsave(&tp->config25_lock, flags);
val = RTL_R8(tp, Config5);
RTL_W8(tp, Config5, (val & ~clear) | set);
- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
+}
+
+static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg,
+ u8 bits, bool cond)
+{
+ u8 val, old_val;
+
+ old_val = RTL_R8(tp, reg);
+ if (cond)
+ val = old_val | bits;
+ else
+ val = old_val & ~bits;
+ if (val != old_val)
+ RTL_W8(tp, reg, val);
}
static bool rtl_is_8125(struct rtl8169_private *tp)
@@ -1432,19 +1431,11 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
{
- switch (tp->mac_version) {
- case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26:
- case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30:
- case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37:
- case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
- if (enable)
- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN);
- else
- RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN);
- break;
- default:
- break;
- }
+ if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_28 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_31 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_38)
+ r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable);
}
static void rtl_reset_packet_filter(struct rtl8169_private *tp)
@@ -1553,61 +1544,40 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
{
- static const struct {
- u32 opt;
- u16 reg;
- u8 mask;
- } cfg[] = {
- { WAKE_PHY, Config3, LinkUp },
- { WAKE_UCAST, Config5, UWF },
- { WAKE_BCAST, Config5, BWF },
- { WAKE_MCAST, Config5, MWF },
- { WAKE_ANY, Config5, LanWake },
- { WAKE_MAGIC, Config3, MagicPacket }
- };
- unsigned int i, tmp = ARRAY_SIZE(cfg);
- unsigned long flags;
- u8 options;
-
rtl_unlock_config_regs(tp);
if (rtl_is_8168evl_up(tp)) {
- tmp--;
if (wolopts & WAKE_MAGIC)
rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2);
else
rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2);
} else if (rtl_is_8125(tp)) {
- tmp--;
if (wolopts & WAKE_MAGIC)
r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0));
else
r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0);
+ } else {
+ r8169_mod_reg8_cond(tp, Config3, MagicPacket,
+ wolopts & WAKE_MAGIC);
}
- raw_spin_lock_irqsave(&tp->config25_lock, flags);
- for (i = 0; i < tmp; i++) {
- options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask;
- if (wolopts & cfg[i].opt)
- options |= cfg[i].mask;
- RTL_W8(tp, cfg[i].reg, options);
- }
- raw_spin_unlock_irqrestore(&tp->config25_lock, flags);
+ r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY);
+ if (rtl_is_8125(tp))
+ r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f,
+ wolopts & WAKE_PHY ? 0x13 : 0);
+ r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST);
+ r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST);
+ r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST);
+ r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts);
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
- options = RTL_R8(tp, Config1) & ~PMEnable;
- if (wolopts)
- options |= PMEnable;
- RTL_W8(tp, Config1, options);
+ r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts);
break;
case RTL_GIGA_MAC_VER_34:
case RTL_GIGA_MAC_VER_37:
case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66:
- if (wolopts)
- rtl_mod_config2(tp, 0, PME_SIGNAL);
- else
- rtl_mod_config2(tp, PME_SIGNAL, 0);
+ r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts);
break;
default:
break;
@@ -2079,10 +2049,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp)
tp->tx_lpi_timer = timer_val;
r8168_mac_ocp_write(tp, 0xe048, timer_val);
break;
- case RTL_GIGA_MAC_VER_61:
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
- case RTL_GIGA_MAC_VER_66:
+ case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66:
tp->tx_lpi_timer = timer_val;
RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val);
break;
@@ -2225,7 +2192,7 @@ static void rtl8169_get_eth_mac_stats(struct net_device *dev,
le64_to_cpu(tp->counters->tx_broadcast64);
mac_stats->MulticastFramesReceivedOK =
le64_to_cpu(tp->counters->rx_multicast64);
- mac_stats->FrameTooLongErrors =
+ mac_stats->FrameTooLongErrors =
le32_to_cpu(tp->counters->rx_frame_too_long);
}
@@ -2293,6 +2260,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
{ 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 },
{ 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 },
+ /* 8125D family. */
+ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 },
+
/* 8125B family. */
{ 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 },
@@ -2558,9 +2528,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_61:
RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
break;
- case RTL_GIGA_MAC_VER_63:
- case RTL_GIGA_MAC_VER_65:
- case RTL_GIGA_MAC_VER_66:
+ case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66:
RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
RX_PAUSE_SLOT_ON);
break;
@@ -2575,86 +2543,31 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0;
}
-static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1);
-}
-
-static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1);
-}
-
-static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
-}
-
-static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
-}
-
-static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, MaxTxPacketSize, 0x24);
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0);
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01);
-}
-
-static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, MaxTxPacketSize, 0x3f);
- RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0);
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01);
-}
-
-static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0));
-}
-
-static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
-{
- RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0));
-}
-
static void rtl_jumbo_config(struct rtl8169_private *tp)
{
bool jumbo = tp->dev->mtu > ETH_DATA_LEN;
int readrq = 4096;
+ if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 &&
+ tp->mac_version <= RTL_GIGA_MAC_VER_26)
+ readrq = 512;
+
rtl_unlock_config_regs(tp);
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_17:
- if (jumbo) {
- readrq = 512;
- r8168b_1_hw_jumbo_enable(tp);
- } else {
- r8168b_1_hw_jumbo_disable(tp);
- }
+ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo);
break;
case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26:
- if (jumbo) {
- readrq = 512;
- r8168c_hw_jumbo_enable(tp);
- } else {
- r8168c_hw_jumbo_disable(tp);
- }
+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
+ r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo);
break;
case RTL_GIGA_MAC_VER_28:
- if (jumbo)
- r8168dp_hw_jumbo_enable(tp);
- else
- r8168dp_hw_jumbo_disable(tp);
+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
break;
case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33:
- if (jumbo)
- r8168e_hw_jumbo_enable(tp);
- else
- r8168e_hw_jumbo_disable(tp);
+ RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f);
+ r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo);
+ r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo);
break;
default:
break;
@@ -3765,8 +3678,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
rtl_pcie_state_l2l3_disable(tp);
RTL_W16(tp, 0x382, 0x221b);
- RTL_W8(tp, 0x4500, 0);
- RTL_W16(tp, 0x4800, 0);
+ RTL_W32(tp, RSS_CTRL_8125, 0);
+ RTL_W16(tp, Q_NUM_CTRL_8125, 0);
/* disable UPS */
r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000);
@@ -3872,6 +3785,12 @@ static void rtl_hw_start_8125b(struct rtl8169_private *tp)
rtl_hw_start_8125_common(tp);
}
+static void rtl_hw_start_8125d(struct rtl8169_private *tp)
+{
+ rtl_set_def_aspm_entry_latency(tp);
+ rtl_hw_start_8125_common(tp);
+}
+
static void rtl_hw_start_8126a(struct rtl8169_private *tp)
{
rtl_set_def_aspm_entry_latency(tp);
@@ -3920,6 +3839,7 @@ static void rtl_hw_config(struct rtl8169_private *tp)
[RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117,
[RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2,
[RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b,
+ [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d,
[RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a,
[RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a,
};
@@ -3937,6 +3857,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp)
/* disable interrupt coalescing */
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_61:
+ case RTL_GIGA_MAC_VER_64:
for (i = 0xa00; i < 0xb00; i += 4)
RTL_W32(tp, i, 0);
break;
@@ -5307,6 +5228,12 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
phy_support_eee(tp->phydev);
phy_support_asym_pause(tp->phydev);
+ /* mimic behavior of r8125/r8126 vendor drivers */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_61)
+ phy_set_eee_broken(tp->phydev,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
+ phy_set_eee_broken(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT);
+
/* PHY will be woken up in rtl_open() */
phy_suspend(tp->phydev);
@@ -5478,8 +5405,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1;
tp->ocp_base = OCP_STD_PHY_BASE;
- 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);
diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c
index d504abba7565..5307c6ff4e25 100644
--- a/drivers/net/ethernet/realtek/r8169_phy_config.c
+++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
@@ -89,19 +89,17 @@ static void rtl8168h_config_eee_phy(struct phy_device *phydev)
phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080);
}
-static void rtl8125a_config_eee_phy(struct phy_device *phydev)
+static void rtl8125_common_config_eee_phy(struct phy_device *phydev)
{
- rtl8168h_config_eee_phy(phydev);
-
- phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
+ phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
+ phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
}
-static void rtl8125b_config_eee_phy(struct phy_device *phydev)
+static void rtl8125_config_eee_phy(struct phy_device *phydev)
{
- phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
- phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
- phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
+ rtl8168g_config_eee_phy(phydev);
+ rtl8125_common_config_eee_phy(phydev);
}
static void rtl8169s_hw_phy_config(struct rtl8169_private *tp,
@@ -1060,15 +1058,15 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp,
rtl8168g_enable_gphy_10m(phydev);
rtl8168g_disable_aldps(phydev);
- rtl8125a_config_eee_phy(phydev);
+ rtl8125_config_eee_phy(phydev);
}
static void rtl8125b_hw_phy_config(struct rtl8169_private *tp,
struct phy_device *phydev)
{
r8169_apply_firmware(tp);
+ rtl8168g_enable_gphy_10m(phydev);
- phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800);
phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090);
phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001);
@@ -1100,13 +1098,27 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp,
rtl8125_legacy_force_mode(phydev);
rtl8168g_disable_aldps(phydev);
- rtl8125b_config_eee_phy(phydev);
+ rtl8125_config_eee_phy(phydev);
+}
+
+static void rtl8125d_hw_phy_config(struct rtl8169_private *tp,
+ struct phy_device *phydev)
+{
+ r8169_apply_firmware(tp);
+ rtl8168g_enable_gphy_10m(phydev);
+ rtl8125_legacy_force_mode(phydev);
+ rtl8168g_disable_aldps(phydev);
+ rtl8125_config_eee_phy(phydev);
}
static void rtl8126a_hw_phy_config(struct rtl8169_private *tp,
struct phy_device *phydev)
{
r8169_apply_firmware(tp);
+ rtl8168g_enable_gphy_10m(phydev);
+ rtl8125_legacy_force_mode(phydev);
+ rtl8168g_disable_aldps(phydev);
+ rtl8125_common_config_eee_phy(phydev);
}
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
@@ -1159,6 +1171,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
[RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config,
[RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config,
[RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config,
+ [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config,
[RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config,
[RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config,
};
diff --git a/drivers/net/ethernet/realtek/rtase/rtase.h b/drivers/net/ethernet/realtek/rtase/rtase.h
index 583c33930f88..942f1e531a85 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase.h
+++ b/drivers/net/ethernet/realtek/rtase/rtase.h
@@ -170,7 +170,7 @@ enum rtase_registers {
RTASE_INT_MITI_TX = 0x0A00,
RTASE_INT_MITI_RX = 0x0A80,
- RTASE_VLAN_ENTRY_0 = 0xAC80,
+ RTASE_VLAN_ENTRY_0 = 0xAC80,
};
enum rtase_desc_status_bit {
diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index f8777b7663d3..874994d9ceb9 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -2115,7 +2115,7 @@ static int rtase_init_one(struct pci_dev *pdev,
ret = rtase_alloc_interrupt(pdev, tp);
if (ret < 0) {
dev_err(&pdev->dev, "unable to alloc MSIX/MSI\n");
- goto err_out_1;
+ goto err_out_del_napi;
}
rtase_init_netdev_ops(dev);
@@ -2148,7 +2148,7 @@ static int rtase_init_one(struct pci_dev *pdev,
GFP_KERNEL);
if (!tp->tally_vaddr) {
ret = -ENOMEM;
- goto err_out;
+ goto err_out_free_dma;
}
rtase_tally_counter_clear(tp);
@@ -2159,13 +2159,13 @@ static int rtase_init_one(struct pci_dev *pdev,
ret = register_netdev(dev);
if (ret != 0)
- goto err_out;
+ goto err_out_free_dma;
netdev_dbg(dev, "%pM, IRQ %d\n", dev->dev_addr, dev->irq);
return 0;
-err_out:
+err_out_free_dma:
if (tp->tally_vaddr) {
dma_free_coherent(&pdev->dev,
sizeof(*tp->tally_vaddr),
@@ -2175,7 +2175,7 @@ err_out:
tp->tally_vaddr = NULL;
}
-err_out_1:
+err_out_del_napi:
for (i = 0; i < tp->int_nums; i++) {
ivec = &tp->int_vector[i];
netif_napi_del(&ivec->napi);
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index de131fc5fa0b..452009ed7a43 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -1751,7 +1751,7 @@ static void efx_ef10_get_stat_mask(struct efx_nic *efx, unsigned long *mask)
#endif
}
-static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 *names)
+static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 **names)
{
DECLARE_BITMAP(mask, EF10_STAT_COUNT);
diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.c b/drivers/net/ethernet/sfc/ef100_ethtool.c
index 5c2551369812..6c3b74000d3b 100644
--- a/drivers/net/ethernet/sfc/ef100_ethtool.c
+++ b/drivers/net/ethernet/sfc/ef100_ethtool.c
@@ -59,6 +59,7 @@ const struct ethtool_ops ef100_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_per_ctx_key = true,
+ .cap_rss_rxnfc_adds = true,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 6da06931187d..62e674d6ff60 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -583,7 +583,7 @@ static const struct efx_hw_stat_desc ef100_stat_desc[EF100_STAT_COUNT] = {
EFX_GENERIC_SW_STAT(rx_noskb_drops),
};
-static size_t ef100_describe_stats(struct efx_nic *efx, u8 *names)
+static size_t ef100_describe_stats(struct efx_nic *efx, u8 **names)
{
DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {};
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 90bb7db15519..650136dfc642 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -418,14 +418,6 @@ unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs)
return usecs * 1000 / efx->timer_quantum_ns;
}
-unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks)
-{
- /* We must round up when converting ticks to microseconds
- * because we round down when converting the other way.
- */
- return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000);
-}
-
/* Set interrupt moderation parameters */
int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive,
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 7a6cab883d66..45e191686625 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -168,7 +168,6 @@ extern const struct ethtool_ops efx_ethtool_ops;
/* Global */
unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs);
-unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks);
int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive,
bool rx_may_override_tx);
diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c
index 13cf647051af..c88ec3e24836 100644
--- a/drivers/net/ethernet/sfc/efx_common.c
+++ b/drivers/net/ethernet/sfc/efx_common.c
@@ -635,22 +635,6 @@ int __efx_reconfigure_port(struct efx_nic *efx)
return rc;
}
-/* Reinitialise the MAC to pick up new PHY settings, even if the port is
- * disabled.
- */
-int efx_reconfigure_port(struct efx_nic *efx)
-{
- int rc;
-
- EFX_ASSERT_RESET_SERIALISED(efx);
-
- mutex_lock(&efx->mac_lock);
- rc = __efx_reconfigure_port(efx);
- mutex_unlock(&efx->mac_lock);
-
- return rc;
-}
-
/**************************************************************************
*
* Device reset and suspend
diff --git a/drivers/net/ethernet/sfc/efx_common.h b/drivers/net/ethernet/sfc/efx_common.h
index 2c54dac3e662..19a8ca530969 100644
--- a/drivers/net/ethernet/sfc/efx_common.h
+++ b/drivers/net/ethernet/sfc/efx_common.h
@@ -40,7 +40,6 @@ void efx_destroy_reset_workqueue(void);
void efx_start_monitor(struct efx_nic *efx);
int __efx_reconfigure_port(struct efx_nic *efx);
-int efx_reconfigure_port(struct efx_nic *efx);
#define EFX_ASSERT_RESET_SERIALISED(efx) \
do { \
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index bb1930818beb..83d715544f7f 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -263,6 +263,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_per_ctx_key = true,
+ .cap_rss_rxnfc_adds = true,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,
diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
index ae32e08540fa..2d734496733f 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/ethtool_common.c
@@ -395,7 +395,7 @@ int efx_ethtool_fill_self_tests(struct efx_nic *efx,
return n;
}
-static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
+static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 **strings)
{
size_t n_stats = 0;
struct efx_channel *channel;
@@ -403,24 +403,22 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
efx_for_each_channel(channel, efx) {
if (efx_channel_has_tx_queues(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "tx-%u.tx_packets",
- channel->tx_queue[0].queue /
- EFX_MAX_TXQ_PER_CHANNEL);
+ if (!strings)
+ continue;
- strings += ETH_GSTRING_LEN;
- }
+ ethtool_sprintf(strings, "tx-%u.tx_packets",
+ channel->tx_queue[0].queue /
+ EFX_MAX_TXQ_PER_CHANNEL);
}
}
efx_for_each_channel(channel, efx) {
if (efx_channel_has_rx_queue(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "rx-%d.rx_packets", channel->channel);
- strings += ETH_GSTRING_LEN;
- }
+ if (!strings)
+ continue;
+
+ ethtool_sprintf(strings, "rx-%d.rx_packets",
+ channel->channel);
}
}
if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) {
@@ -428,11 +426,11 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) {
n_stats++;
- if (strings) {
- snprintf(strings, ETH_GSTRING_LEN,
- "tx-xdp-cpu-%hu.tx_packets", xdp);
- strings += ETH_GSTRING_LEN;
- }
+ if (!strings)
+ continue;
+
+ ethtool_sprintf(strings, "tx-xdp-cpu-%hu.tx_packets",
+ xdp);
}
}
@@ -464,15 +462,11 @@ void efx_ethtool_get_strings(struct net_device *net_dev,
switch (string_set) {
case ETH_SS_STATS:
- strings += (efx->type->describe_stats(efx, strings) *
- ETH_GSTRING_LEN);
+ efx->type->describe_stats(efx, &strings);
for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++)
- strscpy(strings + i * ETH_GSTRING_LEN,
- efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);
- strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;
- strings += (efx_describe_per_queue_stats(efx, strings) *
- ETH_GSTRING_LEN);
- efx_ptp_describe_stats(efx, strings);
+ ethtool_puts(&strings, efx_sw_stat_desc[i].name);
+ efx_describe_per_queue_stats(efx, &strings);
+ efx_ptp_describe_stats(efx, &strings);
break;
case ETH_SS_TEST:
efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);
diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c
index 8925745f1c17..b07f7e4e2877 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.c
+++ b/drivers/net/ethernet/sfc/falcon/efx.c
@@ -1886,14 +1886,6 @@ unsigned int ef4_usecs_to_ticks(struct ef4_nic *efx, unsigned int usecs)
return usecs * 1000 / efx->timer_quantum_ns;
}
-unsigned int ef4_ticks_to_usecs(struct ef4_nic *efx, unsigned int ticks)
-{
- /* We must round up when converting ticks to microseconds
- * because we round down when converting the other way.
- */
- return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000);
-}
-
/* Set interrupt moderation parameters */
int ef4_init_irq_moderation(struct ef4_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive,
diff --git a/drivers/net/ethernet/sfc/falcon/efx.h b/drivers/net/ethernet/sfc/falcon/efx.h
index d3b4646545fa..52508f2c8cb2 100644
--- a/drivers/net/ethernet/sfc/falcon/efx.h
+++ b/drivers/net/ethernet/sfc/falcon/efx.h
@@ -198,7 +198,6 @@ int ef4_try_recovery(struct ef4_nic *efx);
/* Global */
void ef4_schedule_reset(struct ef4_nic *efx, enum reset_type type);
unsigned int ef4_usecs_to_ticks(struct ef4_nic *efx, unsigned int usecs);
-unsigned int ef4_ticks_to_usecs(struct ef4_nic *efx, unsigned int ticks);
int ef4_init_irq_moderation(struct ef4_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive,
bool rx_may_override_tx);
diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c
index f4db683b80f7..04766448a545 100644
--- a/drivers/net/ethernet/sfc/falcon/ethtool.c
+++ b/drivers/net/ethernet/sfc/falcon/ethtool.c
@@ -353,7 +353,7 @@ static int ef4_ethtool_fill_self_tests(struct ef4_nic *efx,
return n;
}
-static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 *strings)
+static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 **strings)
{
size_t n_stats = 0;
struct ef4_channel *channel;
@@ -361,24 +361,22 @@ static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 *strings)
ef4_for_each_channel(channel, efx) {
if (ef4_channel_has_tx_queues(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "tx-%u.tx_packets",
- channel->tx_queue[0].queue /
- EF4_TXQ_TYPES);
+ if (!strings)
+ continue;
- strings += ETH_GSTRING_LEN;
- }
+ ethtool_sprintf(strings, "tx-%u.tx_packets",
+ channel->tx_queue[0].queue /
+ EF4_TXQ_TYPES);
}
}
ef4_for_each_channel(channel, efx) {
if (ef4_channel_has_rx_queue(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "rx-%d.rx_packets", channel->channel);
- strings += ETH_GSTRING_LEN;
- }
+ if (!strings)
+ continue;
+
+ ethtool_sprintf(strings, "rx-%d.rx_packets",
+ channel->channel);
}
}
return n_stats;
@@ -409,14 +407,10 @@ static void ef4_ethtool_get_strings(struct net_device *net_dev,
switch (string_set) {
case ETH_SS_STATS:
- strings += (efx->type->describe_stats(efx, strings) *
- ETH_GSTRING_LEN);
+ efx->type->describe_stats(efx, &strings);
for (i = 0; i < EF4_ETHTOOL_SW_STAT_COUNT; i++)
- strscpy(strings + i * ETH_GSTRING_LEN,
- ef4_sw_stat_desc[i].name, ETH_GSTRING_LEN);
- strings += EF4_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;
- strings += (ef4_describe_per_queue_stats(efx, strings) *
- ETH_GSTRING_LEN);
+ ethtool_puts(&strings, ef4_sw_stat_desc[i].name);
+ ef4_describe_per_queue_stats(efx, &strings);
break;
case ETH_SS_TEST:
ef4_ethtool_fill_self_tests(efx, NULL, strings, NULL);
diff --git a/drivers/net/ethernet/sfc/falcon/falcon.c b/drivers/net/ethernet/sfc/falcon/falcon.c
index 36114ce88034..4af56333ea49 100644
--- a/drivers/net/ethernet/sfc/falcon/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon/falcon.c
@@ -2564,7 +2564,7 @@ static void falcon_remove_nic(struct ef4_nic *efx)
efx->nic_data = NULL;
}
-static size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 *names)
+static size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 **names)
{
return ef4_nic_describe_stats(falcon_stat_desc, FALCON_STAT_COUNT,
falcon_stat_mask, names);
diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c
index c64623c2e80c..01017c41338e 100644
--- a/drivers/net/ethernet/sfc/falcon/farch.c
+++ b/drivers/net/ethernet/sfc/falcon/farch.c
@@ -1631,28 +1631,6 @@ void ef4_farch_rx_push_indir_table(struct ef4_nic *efx)
}
}
-/* Looks at available SRAM resources and works out how many queues we
- * can support, and where things like descriptor caches should live.
- *
- * SRAM is split up as follows:
- * 0 buftbl entries for channels
- * efx->vf_buftbl_base buftbl entries for SR-IOV
- * efx->rx_dc_base RX descriptor caches
- * efx->tx_dc_base TX descriptor caches
- */
-void ef4_farch_dimension_resources(struct ef4_nic *efx, unsigned sram_lim_qw)
-{
- unsigned vi_count;
-
- /* Account for the buffer table entries backing the datapath channels
- * and the descriptor caches for those channels.
- */
- vi_count = max(efx->n_channels, efx->n_tx_channels * EF4_TXQ_TYPES);
-
- efx->tx_dc_base = sram_lim_qw - vi_count * TX_DC_ENTRIES;
- efx->rx_dc_base = efx->tx_dc_base - vi_count * RX_DC_ENTRIES;
-}
-
u32 ef4_farch_fpga_ver(struct ef4_nic *efx)
{
ef4_oword_t altera_build;
diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h
index a2c7139f2b32..7ab0db44720d 100644
--- a/drivers/net/ethernet/sfc/falcon/net_driver.h
+++ b/drivers/net/ethernet/sfc/falcon/net_driver.h
@@ -1057,7 +1057,7 @@ struct ef4_nic_type {
void (*finish_flush)(struct ef4_nic *efx);
void (*prepare_flr)(struct ef4_nic *efx);
void (*finish_flr)(struct ef4_nic *efx);
- size_t (*describe_stats)(struct ef4_nic *efx, u8 *names);
+ size_t (*describe_stats)(struct ef4_nic *efx, u8 **names);
size_t (*update_stats)(struct ef4_nic *efx, u64 *full_stats,
struct rtnl_link_stats64 *core_stats);
void (*start_stats)(struct ef4_nic *efx);
diff --git a/drivers/net/ethernet/sfc/falcon/nic.c b/drivers/net/ethernet/sfc/falcon/nic.c
index 78c851b5a56f..a6304686bc90 100644
--- a/drivers/net/ethernet/sfc/falcon/nic.c
+++ b/drivers/net/ethernet/sfc/falcon/nic.c
@@ -444,18 +444,15 @@ void ef4_nic_get_regs(struct ef4_nic *efx, void *buf)
* bits in the first @count bits of @mask for which a name is defined.
*/
size_t ef4_nic_describe_stats(const struct ef4_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names)
+ const unsigned long *mask, u8 **names)
{
size_t visible = 0;
size_t index;
for_each_set_bit(index, mask, count) {
if (desc[index].name) {
- if (names) {
- strscpy(names, desc[index].name,
- ETH_GSTRING_LEN);
- names += ETH_GSTRING_LEN;
- }
+ if (names)
+ ethtool_puts(names, desc[index].name);
++visible;
}
}
@@ -511,14 +508,3 @@ void ef4_nic_update_stats(const struct ef4_hw_stat_desc *desc, size_t count,
}
}
}
-
-void ef4_nic_fix_nodesc_drop_stat(struct ef4_nic *efx, u64 *rx_nodesc_drops)
-{
- /* if down, or this is the first update after coming up */
- if (!(efx->net_dev->flags & IFF_UP) || !efx->rx_nodesc_drops_prev_state)
- efx->rx_nodesc_drops_while_down +=
- *rx_nodesc_drops - efx->rx_nodesc_drops_total;
- efx->rx_nodesc_drops_total = *rx_nodesc_drops;
- efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP);
- *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down;
-}
diff --git a/drivers/net/ethernet/sfc/falcon/nic.h b/drivers/net/ethernet/sfc/falcon/nic.h
index ada6e036fd97..bc6ef937d0fe 100644
--- a/drivers/net/ethernet/sfc/falcon/nic.h
+++ b/drivers/net/ethernet/sfc/falcon/nic.h
@@ -477,7 +477,6 @@ void ef4_farch_finish_flr(struct ef4_nic *efx);
void falcon_start_nic_stats(struct ef4_nic *efx);
void falcon_stop_nic_stats(struct ef4_nic *efx);
int falcon_reset_xaui(struct ef4_nic *efx);
-void ef4_farch_dimension_resources(struct ef4_nic *efx, unsigned sram_lim_qw);
void ef4_farch_init_common(struct ef4_nic *efx);
void ef4_farch_rx_push_indir_table(struct ef4_nic *efx);
@@ -498,14 +497,10 @@ size_t ef4_nic_get_regs_len(struct ef4_nic *efx);
void ef4_nic_get_regs(struct ef4_nic *efx, void *buf);
size_t ef4_nic_describe_stats(const struct ef4_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names);
+ const unsigned long *mask, u8 **names);
void ef4_nic_update_stats(const struct ef4_hw_stat_desc *desc, size_t count,
const unsigned long *mask, u64 *stats,
const void *dma_buf, bool accumulate);
-void ef4_nic_fix_nodesc_drop_stat(struct ef4_nic *efx, u64 *stat);
-
-#define EF4_MAX_FLUSH_TIME 5000
-
void ef4_farch_generate_event(struct ef4_nic *efx, unsigned int evq,
ef4_qword_t *event);
diff --git a/drivers/net/ethernet/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c
index b9369483758c..e6e80b039ca2 100644
--- a/drivers/net/ethernet/sfc/falcon/tx.c
+++ b/drivers/net/ethernet/sfc/falcon/tx.c
@@ -40,14 +40,6 @@ static inline u8 *ef4_tx_get_copy_buffer(struct ef4_tx_queue *tx_queue,
return (u8 *)page_buf->addr + offset;
}
-u8 *ef4_tx_get_copy_buffer_limited(struct ef4_tx_queue *tx_queue,
- struct ef4_tx_buffer *buffer, size_t len)
-{
- if (len > EF4_TX_CB_SIZE)
- return NULL;
- return ef4_tx_get_copy_buffer(tx_queue, buffer);
-}
-
static void ef4_dequeue_buffer(struct ef4_tx_queue *tx_queue,
struct ef4_tx_buffer *buffer,
unsigned int *pkts_compl,
diff --git a/drivers/net/ethernet/sfc/falcon/tx.h b/drivers/net/ethernet/sfc/falcon/tx.h
index 2a88c59cbbbe..868ed8a861ab 100644
--- a/drivers/net/ethernet/sfc/falcon/tx.h
+++ b/drivers/net/ethernet/sfc/falcon/tx.h
@@ -15,9 +15,6 @@
unsigned int ef4_tx_limit_len(struct ef4_tx_queue *tx_queue,
dma_addr_t dma_addr, unsigned int len);
-u8 *ef4_tx_get_copy_buffer_limited(struct ef4_tx_queue *tx_queue,
- struct ef4_tx_buffer *buffer, size_t len);
-
int ef4_enqueue_skb_tso(struct ef4_tx_queue *tx_queue, struct sk_buff *skb,
bool *data_mapped);
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 10709d828a63..50f097487b14 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -76,17 +76,6 @@ void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out)
*out = EFX_DWORD_VAL(mport);
}
-void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
-{
- efx_dword_t mport;
-
- EFX_POPULATE_DWORD_3(mport,
- MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
- MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
- MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id);
- *out = EFX_DWORD_VAL(mport);
-}
-
/* Constructs an mport selector from an mport ID, because they're not the same */
void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out)
{
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index 8df30bc4f3ba..db79912c86d8 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -23,7 +23,6 @@ int efx_mae_free_mport(struct efx_nic *efx, u32 id);
void efx_mae_mport_wire(struct efx_nic *efx, u32 *out);
void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out);
-void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 76578502226e..d461b1a6ce81 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -1051,15 +1051,6 @@ efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
cookie, false);
}
-int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
- const efx_dword_t *inbuf, size_t inlen,
- size_t outlen, efx_mcdi_async_completer *complete,
- unsigned long cookie)
-{
- return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete,
- cookie, true);
-}
-
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual)
@@ -1068,14 +1059,6 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
outlen_actual, false, NULL, NULL);
}
-int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
- efx_dword_t *outbuf, size_t outlen,
- size_t *outlen_actual)
-{
- return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
- outlen_actual, true, NULL, NULL);
-}
-
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
size_t inlen, efx_dword_t *outbuf,
size_t outlen, int rc)
@@ -1982,33 +1965,6 @@ efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
}
-int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
-{
- MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
- size_t outlen;
- int rc;
-
- rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
- outbuf, sizeof(outbuf), &outlen);
- if (rc)
- goto fail;
-
- if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
- rc = -EIO;
- goto fail;
- }
-
- *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
-
- return 0;
-
-fail:
- *id_out = -1;
- netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
- return rc;
-}
-
-
int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
@@ -2021,38 +1977,6 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
return rc;
}
-int efx_mcdi_flush_rxqs(struct efx_nic *efx)
-{
- struct efx_channel *channel;
- struct efx_rx_queue *rx_queue;
- MCDI_DECLARE_BUF(inbuf,
- MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
- int rc, count;
-
- BUILD_BUG_ON(EFX_MAX_CHANNELS >
- MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
-
- count = 0;
- efx_for_each_channel(channel, efx) {
- efx_for_each_channel_rx_queue(rx_queue, channel) {
- if (rx_queue->flush_pending) {
- rx_queue->flush_pending = false;
- atomic_dec(&efx->rxq_flush_pending);
- MCDI_SET_ARRAY_DWORD(
- inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
- count, efx_rx_queue_index(rx_queue));
- count++;
- }
- }
- }
-
- rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
- MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
- WARN_ON(rc < 0);
-
- return rc;
-}
-
int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
{
int rc;
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index ea612c619874..cdb17d7c147f 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -155,9 +155,6 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual);
-int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd,
- size_t inlen, efx_dword_t *outbuf,
- size_t outlen, size_t *outlen_actual);
typedef void efx_mcdi_async_completer(struct efx_nic *efx,
unsigned long cookie, int rc,
@@ -167,11 +164,6 @@ int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
efx_mcdi_async_completer *complete,
unsigned long cookie);
-int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
- const efx_dword_t *inbuf, size_t inlen,
- size_t outlen,
- efx_mcdi_async_completer *complete,
- unsigned long cookie);
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
size_t inlen, efx_dword_t *outbuf,
@@ -410,10 +402,8 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx);
int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
int *id_out);
-int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out);
int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id);
int efx_mcdi_wol_filter_reset(struct efx_nic *efx);
-int efx_mcdi_flush_rxqs(struct efx_nic *efx);
void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev);
void efx_mcdi_mac_start_stats(struct efx_nic *efx);
void efx_mcdi_mac_stop_stats(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index b54662d32f55..620ba6ef3514 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1408,7 +1408,7 @@ struct efx_nic_type {
int (*fini_dmaq)(struct efx_nic *efx);
void (*prepare_flr)(struct efx_nic *efx);
void (*finish_flr)(struct efx_nic *efx);
- size_t (*describe_stats)(struct efx_nic *efx, u8 *names);
+ size_t (*describe_stats)(struct efx_nic *efx, u8 **names);
size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
struct rtnl_link_stats64 *core_stats);
size_t (*update_stats_atomic)(struct efx_nic *efx, u64 *full_stats,
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index a33ed473cc8a..80aa5e9c732a 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -299,18 +299,15 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf)
* bits in the first @count bits of @mask for which a name is defined.
*/
size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names)
+ const unsigned long *mask, u8 **names)
{
size_t visible = 0;
size_t index;
for_each_set_bit(index, mask, count) {
if (desc[index].name) {
- if (names) {
- strscpy(names, desc[index].name,
- ETH_GSTRING_LEN);
- names += ETH_GSTRING_LEN;
- }
+ if (names)
+ ethtool_puts(names, desc[index].name);
++visible;
}
}
diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h
index 7ec4ac7b7ff5..821d91efda19 100644
--- a/drivers/net/ethernet/sfc/nic_common.h
+++ b/drivers/net/ethernet/sfc/nic_common.h
@@ -241,7 +241,7 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf);
#define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1))
size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names);
+ const unsigned long *mask, u8 **names);
int efx_nic_copy_stats(struct efx_nic *efx, __le64 *dest);
void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
const unsigned long *mask, u64 *stats,
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index aaacdcfa54ae..4c7222bf26be 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -399,7 +399,7 @@ static const unsigned long efx_ptp_stat_mask[] = {
[0 ... BITS_TO_LONGS(PTP_STAT_COUNT) - 1] = ~0UL,
};
-size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings)
+size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 **strings)
{
if (!efx->ptp_data)
return 0;
@@ -1800,11 +1800,6 @@ int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-int efx_ptp_get_mode(struct efx_nic *efx)
-{
- return efx->ptp_data->mode;
-}
-
int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
unsigned int new_mode)
{
diff --git a/drivers/net/ethernet/sfc/ptp.h b/drivers/net/ethernet/sfc/ptp.h
index 6946203499ef..cb9b077921e8 100644
--- a/drivers/net/ethernet/sfc/ptp.h
+++ b/drivers/net/ethernet/sfc/ptp.h
@@ -26,12 +26,11 @@ int efx_ptp_get_ts_config(struct efx_nic *efx,
void efx_ptp_get_ts_info(struct efx_nic *efx,
struct kernel_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);
int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
unsigned int new_mode);
int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
-size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings);
+size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 **strings);
size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats);
void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev);
void __efx_rx_skb_attach_timestamp(struct efx_channel *channel,
diff --git a/drivers/net/ethernet/sfc/siena/ethtool_common.c b/drivers/net/ethernet/sfc/siena/ethtool_common.c
index 075fef64de68..eeee676fdca7 100644
--- a/drivers/net/ethernet/sfc/siena/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/siena/ethtool_common.c
@@ -395,7 +395,7 @@ fail:
test->flags |= ETH_TEST_FL_FAILED;
}
-static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
+static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 **strings)
{
size_t n_stats = 0;
struct efx_channel *channel;
@@ -403,24 +403,22 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
efx_for_each_channel(channel, efx) {
if (efx_channel_has_tx_queues(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "tx-%u.tx_packets",
- channel->tx_queue[0].queue /
- EFX_MAX_TXQ_PER_CHANNEL);
+ if (!strings)
+ continue;
- strings += ETH_GSTRING_LEN;
- }
+ ethtool_sprintf(strings, "tx-%u.tx_packets",
+ channel->tx_queue[0].queue /
+ EFX_MAX_TXQ_PER_CHANNEL);
}
}
efx_for_each_channel(channel, efx) {
if (efx_channel_has_rx_queue(channel)) {
n_stats++;
- if (strings != NULL) {
- snprintf(strings, ETH_GSTRING_LEN,
- "rx-%d.rx_packets", channel->channel);
- strings += ETH_GSTRING_LEN;
- }
+ if (!strings)
+ continue;
+
+ ethtool_sprintf(strings, "rx-%d.rx_packets",
+ channel->channel);
}
}
if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) {
@@ -428,11 +426,11 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) {
n_stats++;
- if (strings) {
- snprintf(strings, ETH_GSTRING_LEN,
- "tx-xdp-cpu-%hu.tx_packets", xdp);
- strings += ETH_GSTRING_LEN;
- }
+ if (!strings)
+ continue;
+
+ ethtool_sprintf(strings, "tx-xdp-cpu-%hu.tx_packets",
+ xdp);
}
}
@@ -464,15 +462,11 @@ void efx_siena_ethtool_get_strings(struct net_device *net_dev,
switch (string_set) {
case ETH_SS_STATS:
- strings += (efx->type->describe_stats(efx, strings) *
- ETH_GSTRING_LEN);
+ efx->type->describe_stats(efx, &strings);
for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++)
- strscpy(strings + i * ETH_GSTRING_LEN,
- efx_sw_stat_desc[i].name, ETH_GSTRING_LEN);
- strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN;
- strings += (efx_describe_per_queue_stats(efx, strings) *
- ETH_GSTRING_LEN);
- efx_siena_ptp_describe_stats(efx, strings);
+ ethtool_puts(&strings, efx_sw_stat_desc[i].name);
+ efx_describe_per_queue_stats(efx, &strings);
+ efx_siena_ptp_describe_stats(efx, &strings);
break;
case ETH_SS_TEST:
efx_ethtool_fill_self_tests(efx, NULL, strings, NULL);
diff --git a/drivers/net/ethernet/sfc/siena/net_driver.h b/drivers/net/ethernet/sfc/siena/net_driver.h
index 3fa7c652ae9b..9785eff10607 100644
--- a/drivers/net/ethernet/sfc/siena/net_driver.h
+++ b/drivers/net/ethernet/sfc/siena/net_driver.h
@@ -1307,7 +1307,7 @@ struct efx_nic_type {
void (*finish_flush)(struct efx_nic *efx);
void (*prepare_flr)(struct efx_nic *efx);
void (*finish_flr)(struct efx_nic *efx);
- size_t (*describe_stats)(struct efx_nic *efx, u8 *names);
+ size_t (*describe_stats)(struct efx_nic *efx, u8 **names);
size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
struct rtnl_link_stats64 *core_stats);
size_t (*update_stats_atomic)(struct efx_nic *efx, u64 *full_stats,
diff --git a/drivers/net/ethernet/sfc/siena/nic.c b/drivers/net/ethernet/sfc/siena/nic.c
index 0ea0433a6230..32fce70085e3 100644
--- a/drivers/net/ethernet/sfc/siena/nic.c
+++ b/drivers/net/ethernet/sfc/siena/nic.c
@@ -449,20 +449,20 @@ void efx_siena_get_regs(struct efx_nic *efx, void *buf)
* Returns the number of visible statistics, i.e. the number of set
* bits in the first @count bits of @mask for which a name is defined.
*/
-size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names)
+size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc,
+ size_t count, const unsigned long *mask,
+ u8 **names)
{
size_t visible = 0;
size_t index;
for_each_set_bit(index, mask, count) {
if (desc[index].name) {
- if (names) {
- strscpy(names, desc[index].name,
- ETH_GSTRING_LEN);
- names += ETH_GSTRING_LEN;
- }
++visible;
+ if (!names)
+ continue;
+
+ ethtool_puts(names, desc[index].name);
}
}
diff --git a/drivers/net/ethernet/sfc/siena/nic_common.h b/drivers/net/ethernet/sfc/siena/nic_common.h
index 3af0405eeaa4..b7fbe198008d 100644
--- a/drivers/net/ethernet/sfc/siena/nic_common.h
+++ b/drivers/net/ethernet/sfc/siena/nic_common.h
@@ -239,8 +239,9 @@ void efx_siena_get_regs(struct efx_nic *efx, void *buf);
#define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1))
-size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
- const unsigned long *mask, u8 *names);
+size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc,
+ size_t count, const unsigned long *mask,
+ u8 **names);
void efx_siena_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
const unsigned long *mask, u64 *stats,
const void *dma_buf, bool accumulate);
diff --git a/drivers/net/ethernet/sfc/siena/ptp.c b/drivers/net/ethernet/sfc/siena/ptp.c
index 85005196b4c5..062c77c92077 100644
--- a/drivers/net/ethernet/sfc/siena/ptp.c
+++ b/drivers/net/ethernet/sfc/siena/ptp.c
@@ -393,7 +393,7 @@ static const unsigned long efx_ptp_stat_mask[] = {
[0 ... BITS_TO_LONGS(PTP_STAT_COUNT) - 1] = ~0UL,
};
-size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 *strings)
+size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 **strings)
{
if (!efx->ptp_data)
return 0;
diff --git a/drivers/net/ethernet/sfc/siena/ptp.h b/drivers/net/ethernet/sfc/siena/ptp.h
index b6133e7c5608..54840036ab67 100644
--- a/drivers/net/ethernet/sfc/siena/ptp.h
+++ b/drivers/net/ethernet/sfc/siena/ptp.h
@@ -28,7 +28,7 @@ int efx_siena_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
unsigned int new_mode);
int efx_siena_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
void efx_siena_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
-size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 *strings);
+size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 **strings);
size_t efx_siena_ptp_update_stats(struct efx_nic *efx, u64 *stats);
void efx_siena_time_sync_event(struct efx_channel *channel, efx_qword_t *ev);
void __efx_siena_rx_skb_attach_timestamp(struct efx_channel *channel,
diff --git a/drivers/net/ethernet/sfc/siena/siena.c b/drivers/net/ethernet/sfc/siena/siena.c
index ca33dc08e555..49f0c8a1a90a 100644
--- a/drivers/net/ethernet/sfc/siena/siena.c
+++ b/drivers/net/ethernet/sfc/siena/siena.c
@@ -545,7 +545,7 @@ static const unsigned long siena_stat_mask[] = {
[0 ... BITS_TO_LONGS(SIENA_STAT_COUNT) - 1] = ~0UL,
};
-static size_t siena_describe_nic_stats(struct efx_nic *efx, u8 *names)
+static size_t siena_describe_nic_stats(struct efx_nic *efx, u8 **names)
{
return efx_siena_describe_stats(siena_stat_desc, SIENA_STAT_COUNT,
siena_stat_mask, names);
diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c
index 822ec6564b2d..4dff19b6ef17 100644
--- a/drivers/net/ethernet/sfc/tx.c
+++ b/drivers/net/ethernet/sfc/tx.c
@@ -49,14 +49,6 @@ static inline u8 *efx_tx_get_copy_buffer(struct efx_tx_queue *tx_queue,
return (u8 *)page_buf->addr + offset;
}
-u8 *efx_tx_get_copy_buffer_limited(struct efx_tx_queue *tx_queue,
- struct efx_tx_buffer *buffer, size_t len)
-{
- if (len > EFX_TX_CB_SIZE)
- return NULL;
- return efx_tx_get_copy_buffer(tx_queue, buffer);
-}
-
static void efx_tx_maybe_stop_queue(struct efx_tx_queue *txq1)
{
/* We need to consider all queues that the net core sees as one */
diff --git a/drivers/net/ethernet/sfc/tx.h b/drivers/net/ethernet/sfc/tx.h
index f2c4d2f89919..f882749af8c3 100644
--- a/drivers/net/ethernet/sfc/tx.h
+++ b/drivers/net/ethernet/sfc/tx.h
@@ -15,9 +15,6 @@
unsigned int efx_tx_limit_len(struct efx_tx_queue *tx_queue,
dma_addr_t dma_addr, unsigned int len);
-u8 *efx_tx_get_copy_buffer_limited(struct efx_tx_queue *tx_queue,
- struct efx_tx_buffer *buffer, size_t len);
-
/* What TXQ type will satisfy the checksum offloads required for this skb? */
static inline unsigned int efx_tx_csum_type_skb(struct sk_buff *skb)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 05cc07b8f48c..6658536a4e17 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -228,6 +228,16 @@ config DWMAC_SUN8I
stmmac device driver. This driver is used for H3/A83T/A64
EMAC ethernet controller.
+config DWMAC_THEAD
+ tristate "T-HEAD dwmac support"
+ depends on OF && (ARCH_THEAD || COMPILE_TEST)
+ help
+ Support for ethernet controllers on T-HEAD RISC-V SoCs
+
+ This selects the T-HEAD platform specific glue layer support for
+ the stmmac device driver. This driver is used for T-HEAD TH1520
+ ethernet controller.
+
config DWMAC_IMX8
tristate "NXP IMX8 DWMAC support"
default ARCH_MXC
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c2f0e91f6bf8..2389fd261344 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_est.o \
+ stmmac_xdp.o stmmac_est.o stmmac_fpe.o \
$(stmmac-y)
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
@@ -28,6 +28,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o
obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
+obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o
obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o
obj-$(CONFIG_DWMAC_LOONGSON1) += dwmac-loongson1.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 684489156dce..1367fa5c9b8e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -549,8 +549,12 @@ extern const struct stmmac_desc_ops ndesc_ops;
struct mac_device_info;
extern const struct stmmac_hwtimestamp stmmac_ptp;
+extern const struct stmmac_hwtimestamp dwmac1000_ptp;
extern const struct stmmac_mode_ops dwmac4_ring_mode_ops;
+extern const struct ptp_clock_info stmmac_ptp_clock_ops;
+extern const struct ptp_clock_info dwmac1000_ptp_clock_ops;
+
struct mac_link {
u32 caps;
u32 speed_mask;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
index 598eff926815..b9218c07eb6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
@@ -56,6 +56,7 @@ static const struct of_device_id dwmac_generic_match[] = {
{ .compatible = "snps,dwmac-3.610"},
{ .compatible = "snps,dwmac-3.70a"},
{ .compatible = "snps,dwmac-3.710"},
+ { .compatible = "snps,dwmac-3.72a"},
{ .compatible = "snps,dwmac-4.00"},
{ .compatible = "snps,dwmac-4.10a"},
{ .compatible = "snps,dwmac"},
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
index 230e79658c54..a433526dcbe8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c
@@ -108,7 +108,12 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
if (IS_ERR(dwmac->tx_clk))
return PTR_ERR(dwmac->tx_clk);
- clk_prepare_enable(dwmac->tx_clk);
+ ret = clk_prepare_enable(dwmac->tx_clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to enable tx_clk\n");
+ return ret;
+ }
/* Check and configure TX clock rate */
rate = clk_get_rate(dwmac->tx_clk);
@@ -119,7 +124,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Failed to set tx_clk\n");
- return ret;
+ goto err_tx_clk_disable;
}
}
}
@@ -133,7 +138,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Failed to set clk_ptp_ref\n");
- return ret;
+ goto err_tx_clk_disable;
}
}
}
@@ -149,12 +154,15 @@ static int intel_eth_plat_probe(struct platform_device *pdev)
}
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- if (ret) {
- clk_disable_unprepare(dwmac->tx_clk);
- return ret;
- }
+ if (ret)
+ goto err_tx_clk_disable;
return 0;
+
+err_tx_clk_disable:
+ if (dwmac->data->tx_clk_en)
+ clk_disable_unprepare(dwmac->tx_clk);
+ return ret;
}
static void intel_eth_plat_remove(struct platform_device *pdev)
@@ -162,7 +170,8 @@ static void intel_eth_plat_remove(struct platform_device *pdev)
struct intel_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
stmmac_pltfr_remove(pdev);
- clk_disable_unprepare(dwmac->tx_clk);
+ if (dwmac->data->tx_clk_en)
+ clk_disable_unprepare(dwmac->tx_clk);
}
static struct platform_driver intel_eth_plat_driver = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index f8ca81675407..c9636832a570 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -589,9 +589,9 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
plat->mac_interface = priv_plat->phy_mode;
if (priv_plat->mac_wol)
- plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
- else
plat->flags &= ~STMMAC_FLAG_USE_PHY_WOL;
+ else
+ plat->flags |= STMMAC_FLAG_USE_PHY_WOL;
plat->riwt_off = 1;
plat->maxmtu = ETH_DATA_LEN;
plat->host_dma_width = priv_plat->variant->dma_bit_mask;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 0745117d5872..248b30d7b864 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -485,6 +485,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
plat_dat->pcs_init = socfpga_dwmac_pcs_init;
plat_dat->pcs_exit = socfpga_dwmac_pcs_exit;
plat_dat->select_pcs = socfpga_dwmac_select_pcs;
+ plat_dat->has_gmac = true;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
new file mode 100644
index 000000000000..dce84ed184e9
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * T-HEAD DWMAC platform driver
+ *
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+
+#include "stmmac_platform.h"
+
+#define GMAC_CLK_EN 0x00
+#define GMAC_TX_CLK_EN BIT(1)
+#define GMAC_TX_CLK_N_EN BIT(2)
+#define GMAC_TX_CLK_OUT_EN BIT(3)
+#define GMAC_RX_CLK_EN BIT(4)
+#define GMAC_RX_CLK_N_EN BIT(5)
+#define GMAC_EPHY_REF_CLK_EN BIT(6)
+#define GMAC_RXCLK_DELAY_CTRL 0x04
+#define GMAC_RXCLK_BYPASS BIT(15)
+#define GMAC_RXCLK_INVERT BIT(14)
+#define GMAC_RXCLK_DELAY GENMASK(4, 0)
+#define GMAC_TXCLK_DELAY_CTRL 0x08
+#define GMAC_TXCLK_BYPASS BIT(15)
+#define GMAC_TXCLK_INVERT BIT(14)
+#define GMAC_TXCLK_DELAY GENMASK(4, 0)
+#define GMAC_PLLCLK_DIV 0x0c
+#define GMAC_PLLCLK_DIV_EN BIT(31)
+#define GMAC_PLLCLK_DIV_NUM GENMASK(7, 0)
+#define GMAC_GTXCLK_SEL 0x18
+#define GMAC_GTXCLK_SEL_PLL BIT(0)
+#define GMAC_INTF_CTRL 0x1c
+#define PHY_INTF_MASK BIT(0)
+#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1)
+#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0)
+#define GMAC_TXCLK_OEN 0x20
+#define TXCLK_DIR_MASK BIT(0)
+#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0)
+#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1)
+
+#define GMAC_GMII_RGMII_RATE 125000000
+#define GMAC_MII_RATE 25000000
+
+struct thead_dwmac {
+ struct plat_stmmacenet_data *plat;
+ void __iomem *apb_base;
+ struct device *dev;
+};
+
+static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat)
+{
+ struct thead_dwmac *dwmac = plat->bsp_priv;
+ u32 phyif;
+
+ switch (plat->mac_interface) {
+ case PHY_INTERFACE_MODE_MII:
+ phyif = PHY_INTF_MII_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ phyif = PHY_INTF_RGMII;
+ break;
+ default:
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
+ plat->mac_interface);
+ return -EINVAL;
+ }
+
+ writel(phyif, dwmac->apb_base + GMAC_INTF_CTRL);
+ return 0;
+}
+
+static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat)
+{
+ struct thead_dwmac *dwmac = plat->bsp_priv;
+ u32 txclk_dir;
+
+ switch (plat->mac_interface) {
+ case PHY_INTERFACE_MODE_MII:
+ txclk_dir = TXCLK_DIR_INPUT;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ txclk_dir = TXCLK_DIR_OUTPUT;
+ break;
+ default:
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
+ plat->mac_interface);
+ return -EINVAL;
+ }
+
+ writel(txclk_dir, dwmac->apb_base + GMAC_TXCLK_OEN);
+ return 0;
+}
+
+static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
+{
+ struct plat_stmmacenet_data *plat;
+ struct thead_dwmac *dwmac = priv;
+ unsigned long rate;
+ u32 div, reg;
+
+ plat = dwmac->plat;
+
+ switch (plat->mac_interface) {
+ /* For MII, rxc/txc is provided by phy */
+ case PHY_INTERFACE_MODE_MII:
+ return;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ rate = clk_get_rate(plat->stmmac_clk);
+ if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 ||
+ rate % GMAC_MII_RATE != 0) {
+ dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate);
+ return;
+ }
+
+ writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV);
+
+ switch (speed) {
+ case SPEED_1000:
+ div = rate / GMAC_GMII_RGMII_RATE;
+ break;
+ case SPEED_100:
+ div = rate / GMAC_MII_RATE;
+ break;
+ case SPEED_10:
+ div = rate * 10 / GMAC_MII_RATE;
+ break;
+ default:
+ dev_err(dwmac->dev, "invalid speed %u\n", speed);
+ return;
+ }
+
+ reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) |
+ FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div);
+ writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV);
+ break;
+ default:
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
+ plat->mac_interface);
+ return;
+ }
+}
+
+static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
+{
+ struct thead_dwmac *dwmac = plat->bsp_priv;
+ u32 reg;
+
+ switch (plat->mac_interface) {
+ case PHY_INTERFACE_MODE_MII:
+ reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN;
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ /* use pll */
+ writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL);
+ reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN |
+ GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN;
+ break;
+
+ default:
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
+ plat->mac_interface);
+ return -EINVAL;
+ }
+
+ writel(reg, dwmac->apb_base + GMAC_CLK_EN);
+ return 0;
+}
+
+static int thead_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct thead_dwmac *dwmac = priv;
+ unsigned int reg;
+ int ret;
+
+ ret = thead_dwmac_set_phy_if(dwmac->plat);
+ if (ret)
+ return ret;
+
+ ret = thead_dwmac_set_txclk_dir(dwmac->plat);
+ if (ret)
+ return ret;
+
+ reg = readl(dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);
+ reg &= ~(GMAC_RXCLK_DELAY);
+ reg |= FIELD_PREP(GMAC_RXCLK_DELAY, 0);
+ writel(reg, dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);
+
+ reg = readl(dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);
+ reg &= ~(GMAC_TXCLK_DELAY);
+ reg |= FIELD_PREP(GMAC_TXCLK_DELAY, 0);
+ writel(reg, dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);
+
+ return thead_dwmac_enable_clk(dwmac->plat);
+}
+
+static int thead_dwmac_probe(struct platform_device *pdev)
+{
+ struct stmmac_resources stmmac_res;
+ struct plat_stmmacenet_data *plat;
+ struct thead_dwmac *dwmac;
+ void __iomem *apb;
+ int ret;
+
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to get resources\n");
+
+ plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat))
+ return dev_err_probe(&pdev->dev, PTR_ERR(plat),
+ "dt configuration failed\n");
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return -ENOMEM;
+
+ apb = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(apb))
+ return dev_err_probe(&pdev->dev, PTR_ERR(apb),
+ "failed to remap gmac apb registers\n");
+
+ dwmac->dev = &pdev->dev;
+ dwmac->plat = plat;
+ dwmac->apb_base = apb;
+ plat->bsp_priv = dwmac;
+ plat->fix_mac_speed = thead_dwmac_fix_speed;
+ plat->init = thead_dwmac_init;
+
+ return devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res);
+}
+
+static const struct of_device_id thead_dwmac_match[] = {
+ { .compatible = "thead,th1520-gmac" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, thead_dwmac_match);
+
+static struct platform_driver thead_dwmac_driver = {
+ .probe = thead_dwmac_probe,
+ .driver = {
+ .name = "thead-dwmac",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = thead_dwmac_match,
+ },
+};
+module_platform_driver(thead_dwmac_driver);
+
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_AUTHOR("Drew Fustini <drew@pdp7.com>");
+MODULE_DESCRIPTION("T-HEAD DWMAC platform driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 4296ddda8aaa..600fea8f712f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -329,5 +329,17 @@ enum rtc_control {
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
#define GMAC_EXTHASH_BASE 0x500
+/* PTP and timestamping registers */
+
+#define GMAC3_X_ATSNS GENMASK(19, 16)
+#define GMAC3_X_ATSNS_SHIFT 16
+
+#define GMAC_PTP_TCR_ATSFC BIT(24)
+#define GMAC_PTP_TCR_ATSEN0 BIT(25)
+
+#define GMAC3_X_TIMESTAMP_STATUS 0x28
+#define GMAC_PTP_ATNR 0x30
+#define GMAC_PTP_ATSR 0x34
+
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
#endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index d413d76a8936..96bcda0856ec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include "stmmac.h"
#include "stmmac_pcs.h"
+#include "stmmac_ptp.h"
#include "dwmac1000.h"
static void dwmac1000_core_init(struct mac_device_info *hw,
@@ -551,3 +552,103 @@ int dwmac1000_setup(struct stmmac_priv *priv)
return 0;
}
+
+/* DWMAC 1000 HW Timestaming ops */
+
+void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
+{
+ u64 ns;
+
+ ns = readl(ptpaddr + GMAC_PTP_ATNR);
+ ns += readl(ptpaddr + GMAC_PTP_ATSR) * NSEC_PER_SEC;
+
+ *ptp_time = ns;
+}
+
+void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv)
+{
+ struct ptp_clock_event event;
+ u32 ts_status, num_snapshot;
+ unsigned long flags;
+ u64 ptp_time;
+ int i;
+
+ /* Clears the timestamp interrupt */
+ ts_status = readl(priv->ptpaddr + GMAC3_X_TIMESTAMP_STATUS);
+
+ if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN))
+ return;
+
+ num_snapshot = (ts_status & GMAC3_X_ATSNS) >> GMAC3_X_ATSNS_SHIFT;
+
+ for (i = 0; i < num_snapshot; i++) {
+ read_lock_irqsave(&priv->ptp_lock, flags);
+ stmmac_get_ptptime(priv, priv->ptpaddr, &ptp_time);
+ read_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ptp_time;
+ ptp_clock_event(priv->ptp_clock, &event);
+ }
+}
+
+/* DWMAC 1000 ptp_clock_info ops */
+
+static void dwmac1000_timestamp_interrupt_cfg(struct stmmac_priv *priv, bool en)
+{
+ void __iomem *ioaddr = priv->ioaddr;
+
+ u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
+
+ if (en)
+ intr_mask &= ~GMAC_INT_DISABLE_TIMESTAMP;
+ else
+ intr_mask |= GMAC_INT_DISABLE_TIMESTAMP;
+
+ writel(intr_mask, ioaddr + GMAC_INT_MASK);
+}
+
+int dwmac1000_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ void __iomem *ptpaddr = priv->ptpaddr;
+ int ret = -EOPNOTSUPP;
+ u32 tcr_val;
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_EXTTS:
+ mutex_lock(&priv->aux_ts_lock);
+ tcr_val = readl(ptpaddr + PTP_TCR);
+
+ if (on) {
+ tcr_val |= GMAC_PTP_TCR_ATSEN0;
+ tcr_val |= GMAC_PTP_TCR_ATSFC;
+ priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN;
+ } else {
+ tcr_val &= ~GMAC_PTP_TCR_ATSEN0;
+ priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
+ }
+
+ netdev_dbg(priv->dev, "Auxiliary Snapshot %s.\n",
+ on ? "enabled" : "disabled");
+ writel(tcr_val, ptpaddr + PTP_TCR);
+
+ /* wait for auxts fifo clear to finish */
+ ret = readl_poll_timeout(ptpaddr + PTP_TCR, tcr_val,
+ !(tcr_val & GMAC_PTP_TCR_ATSFC),
+ 10, 10000);
+
+ mutex_unlock(&priv->aux_ts_lock);
+
+ dwmac1000_timestamp_interrupt_cfg(priv, on);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 28fff6cab812..184d41a306af 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -69,7 +69,6 @@
#define GMAC_RXQCTRL_TACPQE BIT(21)
#define GMAC_RXQCTRL_TACPQE_SHIFT 21
#define GMAC_RXQCTRL_FPRQ GENMASK(26, 24)
-#define GMAC_RXQCTRL_FPRQ_SHIFT 24
/* MAC Packet Filtering */
#define GMAC_PACKET_FILTER_PR BIT(0)
@@ -394,8 +393,8 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs,
#define MTL_OP_MODE_EHFC BIT(7)
-#define MTL_OP_MODE_RTC_MASK 0x18
-#define MTL_OP_MODE_RTC_SHIFT 3
+#define MTL_OP_MODE_RTC_MASK GENMASK(1, 0)
+#define MTL_OP_MODE_RTC_SHIFT 0
#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT)
#define MTL_OP_MODE_RTC_64 0
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index e65a65666cc1..c25781874aa7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include "stmmac.h"
+#include "stmmac_fpe.h"
#include "stmmac_pcs.h"
#include "dwmac4.h"
#include "dwmac5.h"
@@ -1261,11 +1262,6 @@ 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,
- .fpe_configure = dwmac5_fpe_configure,
- .fpe_send_mpacket = dwmac5_fpe_send_mpacket,
- .fpe_irq_status = dwmac5_fpe_irq_status,
- .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
- .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
@@ -1316,11 +1312,6 @@ 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,
- .fpe_configure = dwmac5_fpe_configure,
- .fpe_send_mpacket = dwmac5_fpe_send_mpacket,
- .fpe_irq_status = dwmac5_fpe_irq_status,
- .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
- .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 7c895e0ae71f..0cb84a0041a4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -203,8 +203,12 @@ static void _dwmac4_dump_dma_regs(struct stmmac_priv *priv,
readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, channel));
reg_space[DMA_CHAN_RX_CONTROL(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, channel));
+ reg_space[DMA_CHAN_TX_BASE_ADDR_HI(default_addrs, channel) / 4] =
+ readl(ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(dwmac4_addrs, channel));
reg_space[DMA_CHAN_TX_BASE_ADDR(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(dwmac4_addrs, channel));
+ reg_space[DMA_CHAN_RX_BASE_ADDR_HI(default_addrs, channel) / 4] =
+ readl(ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(dwmac4_addrs, channel));
reg_space[DMA_CHAN_RX_BASE_ADDR(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(dwmac4_addrs, channel));
reg_space[DMA_CHAN_TX_END_ADDR(default_addrs, channel) / 4] =
@@ -225,8 +229,12 @@ static void _dwmac4_dump_dma_regs(struct stmmac_priv *priv,
readl(ioaddr + DMA_CHAN_CUR_TX_DESC(dwmac4_addrs, channel));
reg_space[DMA_CHAN_CUR_RX_DESC(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_DESC(dwmac4_addrs, channel));
+ reg_space[DMA_CHAN_CUR_TX_BUF_ADDR_HI(default_addrs, channel) / 4] =
+ readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR_HI(dwmac4_addrs, channel));
reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(dwmac4_addrs, channel));
+ reg_space[DMA_CHAN_CUR_RX_BUF_ADDR_HI(default_addrs, channel) / 4] =
+ readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR_HI(dwmac4_addrs, channel));
reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(default_addrs, channel) / 4] =
readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(dwmac4_addrs, channel));
reg_space[DMA_CHAN_STATUS(default_addrs, channel) / 4] =
@@ -266,7 +274,7 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
} else {
pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
mtl_rx_op &= ~MTL_OP_MODE_RSF;
- mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
+ mtl_rx_op &= ~MTL_OP_MODE_RTC_MASK;
if (mode <= 32)
mtl_rx_op |= MTL_OP_MODE_RTC_32;
else if (mode <= 64)
@@ -335,7 +343,7 @@ static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv,
} else {
pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
mtl_tx_op &= ~MTL_OP_MODE_TSF;
- mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
+ mtl_tx_op &= ~MTL_OP_MODE_TTC_MASK;
/* Set the transmit threshold */
if (mode <= 32)
mtl_tx_op |= MTL_OP_MODE_TTC_32;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
index 17d9120db5fe..4f980dcd3958 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
@@ -127,7 +127,9 @@ static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs,
#define DMA_CHAN_SLOT_CTRL_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x3c)
#define DMA_CHAN_CUR_TX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x44)
#define DMA_CHAN_CUR_RX_DESC(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x4c)
+#define DMA_CHAN_CUR_TX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x50)
#define DMA_CHAN_CUR_TX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x54)
+#define DMA_CHAN_CUR_RX_BUF_ADDR_HI(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x58)
#define DMA_CHAN_CUR_RX_BUF_ADDR(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x5c)
#define DMA_CHAN_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x60)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 0d185e54eb7e..57c03d491774 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -185,8 +185,6 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
x->rx_buf_unav_irq++;
if (unlikely(intr_status & DMA_CHAN_STATUS_RPS))
x->rx_process_stopped_irq++;
- if (unlikely(intr_status & DMA_CHAN_STATUS_RWT))
- x->rx_watchdog_irq++;
if (unlikely(intr_status & DMA_CHAN_STATUS_ETI))
x->tx_early_irq++;
if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) {
@@ -198,6 +196,10 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
ret = tx_hard_error;
}
}
+
+ if (unlikely(intr_status & DMA_CHAN_STATUS_RWT))
+ x->rx_watchdog_irq++;
+
/* TX/RX NORMAL interrupts */
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
u64_stats_update_begin(&stats->syncp);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 08add508db84..1c431b918719 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -572,153 +572,3 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
writel(val, ioaddr + MAC_PPS_CONTROL);
return 0;
}
-
-void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
- u32 num_txq, u32 num_rxq,
- bool tx_enable, bool pmac_enable)
-{
- u32 value;
-
- if (tx_enable) {
- cfg->fpe_csr = EFPE;
- value = readl(ioaddr + GMAC_RXQ_CTRL1);
- value &= ~GMAC_RXQCTRL_FPRQ;
- value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
- writel(value, ioaddr + GMAC_RXQ_CTRL1);
- } else {
- cfg->fpe_csr = 0;
- }
- writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
-
- value = readl(ioaddr + GMAC_INT_EN);
-
- if (pmac_enable) {
- if (!(value & GMAC_INT_FPE_EN)) {
- /* Dummy read to clear any pending masked interrupts */
- readl(ioaddr + MAC_FPE_CTRL_STS);
-
- value |= GMAC_INT_FPE_EN;
- }
- } else {
- value &= ~GMAC_INT_FPE_EN;
- }
-
- writel(value, ioaddr + GMAC_INT_EN);
-}
-
-int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
-{
- u32 value;
- int status;
-
- status = FPE_EVENT_UNKNOWN;
-
- /* Reads from the MAC_FPE_CTRL_STS register should only be performed
- * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
- */
- value = readl(ioaddr + MAC_FPE_CTRL_STS);
-
- if (value & TRSP) {
- status |= FPE_EVENT_TRSP;
- netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
- }
-
- if (value & TVER) {
- status |= FPE_EVENT_TVER;
- netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
- }
-
- if (value & RRSP) {
- status |= FPE_EVENT_RRSP;
- netdev_dbg(dev, "FPE: Respond mPacket is received\n");
- }
-
- if (value & RVER) {
- status |= FPE_EVENT_RVER;
- netdev_dbg(dev, "FPE: Verify mPacket is received\n");
- }
-
- return status;
-}
-
-void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
- enum stmmac_mpacket_type type)
-{
- u32 value = cfg->fpe_csr;
-
- if (type == MPACKET_VERIFY)
- value |= SVER;
- else if (type == MPACKET_RESPONSE)
- value |= SRSP;
-
- writel(value, ioaddr + MAC_FPE_CTRL_STS);
-}
-
-int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr)
-{
- return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS));
-}
-
-void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
-{
- u32 value;
-
- value = readl(ioaddr + MTL_FPE_CTRL_STS);
- writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
- ioaddr + MTL_FPE_CTRL_STS);
-}
-
-#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
-#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
-
-int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
- struct netlink_ext_ack *extack, u32 pclass)
-{
- u32 val, offset, count, queue_weight, preemptible_txqs = 0;
- struct stmmac_priv *priv = netdev_priv(ndev);
- u32 num_tc = ndev->num_tc;
-
- if (!pclass)
- goto update_mapping;
-
- /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
- *
- * Synopsys Databook:
- * "The number of Tx DMA channels is equal to the number of Tx queues,
- * and is direct one-to-one mapping."
- */
- for (u32 tc = 0; tc < num_tc; tc++) {
- count = ndev->tc_to_txq[tc].count;
- offset = ndev->tc_to_txq[tc].offset;
-
- if (pclass & BIT(tc))
- preemptible_txqs |= GENMASK(offset + count - 1, offset);
-
- /* This is 1:1 mapping, go to next TC */
- if (count == 1)
- continue;
-
- if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
- NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
- return -EINVAL;
- }
-
- queue_weight = priv->plat->tx_queues_cfg[offset].weight;
-
- for (u32 i = 1; i < count; i++) {
- if (priv->plat->tx_queues_cfg[offset + i].weight !=
- queue_weight) {
- NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
- queue_weight, tc);
- return -EINVAL;
- }
- }
- }
-
-update_mapping:
- val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
- writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
- priv->ioaddr + MTL_FPE_CTRL_STS);
-
- return 0;
-}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 6c6eb6790e83..00b151b3b688 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -11,15 +11,6 @@
#define PRTYEN BIT(1)
#define TMOUTEN BIT(0)
-#define MAC_FPE_CTRL_STS 0x00000234
-#define TRSP BIT(19)
-#define TVER BIT(18)
-#define RRSP BIT(17)
-#define RVER BIT(16)
-#define SRSP BIT(2)
-#define SVER BIT(1)
-#define EFPE BIT(0)
-
#define MAC_PPS_CONTROL 0x00000b70
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
#define PPS_MINIDX(x) ((x) * 8)
@@ -39,12 +30,6 @@
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
-#define MTL_FPE_CTRL_STS 0x00000c90
-/* Preemption Classification */
-#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
-/* Additional Fragment Size of preempted frames */
-#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
-
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
#define RXPI BIT(31)
#define NPE GENMASK(23, 16)
@@ -108,16 +93,5 @@ 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);
-void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
- u32 num_txq, u32 num_rxq,
- bool tx_enable, bool pmac_enable);
-void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
- struct stmmac_fpe_cfg *cfg,
- enum stmmac_mpacket_type type);
-int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
-int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
-void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
-int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
- struct netlink_ext_ack *extack, u32 pclass);
#endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 6a2c7d22df1e..a04a79003692 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -84,8 +84,7 @@
#define XGMAC_MCBCQEN BIT(15)
#define XGMAC_MCBCQ GENMASK(11, 8)
#define XGMAC_MCBCQ_SHIFT 8
-#define XGMAC_RQ GENMASK(7, 4)
-#define XGMAC_RQ_SHIFT 4
+#define XGMAC_FPRQ GENMASK(7, 4)
#define XGMAC_UPQ GENMASK(3, 0)
#define XGMAC_UPQ_SHIFT 0
#define XGMAC_RXQ_CTRL2 0x000000a8
@@ -96,6 +95,7 @@
#define XGMAC_LPIIS BIT(5)
#define XGMAC_PMTIS BIT(4)
#define XGMAC_INT_EN 0x000000b4
+#define XGMAC_FPEIE BIT(15)
#define XGMAC_TSIE BIT(12)
#define XGMAC_LPIIE BIT(5)
#define XGMAC_PMTIE BIT(4)
@@ -193,8 +193,6 @@
#define XGMAC_MDIO_ADDR 0x00000200
#define XGMAC_MDIO_DATA 0x00000204
#define XGMAC_MDIO_C22P 0x00000220
-#define XGMAC_FPE_CTRL_STS 0x00000280
-#define XGMAC_EFPE BIT(0)
#define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8)
#define XGMAC_ADDR_MAX 32
#define XGMAC_AE BIT(31)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index f519d43738b0..9a60a6e8f633 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -8,6 +8,7 @@
#include <linux/crc32.h>
#include <linux/iopoll.h>
#include "stmmac.h"
+#include "stmmac_fpe.h"
#include "stmmac_ptp.h"
#include "dwxlgmac2.h"
#include "dwxgmac2.h"
@@ -1504,32 +1505,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
writel(value, ioaddr + XGMAC_RX_CONFIG);
}
-static void dwxgmac3_fpe_configure(void __iomem *ioaddr,
- struct stmmac_fpe_cfg *cfg,
- u32 num_txq, u32 num_rxq,
- bool tx_enable, bool pmac_enable)
-{
- u32 value;
-
- if (!tx_enable) {
- value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
-
- value &= ~XGMAC_EFPE;
-
- writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
- return;
- }
-
- value = readl(ioaddr + XGMAC_RXQ_CTRL1);
- value &= ~XGMAC_RQ;
- value |= (num_rxq - 1) << XGMAC_RQ_SHIFT;
- writel(value, ioaddr + XGMAC_RXQ_CTRL1);
-
- value = readl(ioaddr + XGMAC_FPE_CTRL_STS);
- value |= XGMAC_EFPE;
- writel(value, ioaddr + XGMAC_FPE_CTRL_STS);
-}
-
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac,
@@ -1570,7 +1545,7 @@ 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,
- .fpe_configure = dwxgmac3_fpe_configure,
+ .fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class,
};
static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode,
@@ -1627,7 +1602,7 @@ 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,
- .fpe_configure = dwxgmac3_fpe_configure,
+ .fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class,
};
int dwxgmac2_setup(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 88cce28b2f98..a72d336a8350 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -6,6 +6,7 @@
#include "common.h"
#include "stmmac.h"
+#include "stmmac_fpe.h"
#include "stmmac_ptp.h"
#include "stmmac_est.h"
@@ -112,6 +113,7 @@ static const struct stmmac_hwif_entry {
const void *dma;
const void *mac;
const void *hwtimestamp;
+ const void *ptp;
const void *mode;
const void *tc;
const void *mmc;
@@ -132,7 +134,8 @@ static const struct stmmac_hwif_entry {
.desc = NULL,
.dma = &dwmac100_dma_ops,
.mac = &dwmac100_ops,
- .hwtimestamp = &stmmac_ptp,
+ .hwtimestamp = &dwmac1000_ptp,
+ .ptp = &dwmac1000_ptp_clock_ops,
.mode = NULL,
.tc = NULL,
.mmc = &dwmac_mmc_ops,
@@ -150,7 +153,8 @@ static const struct stmmac_hwif_entry {
.desc = NULL,
.dma = &dwmac1000_dma_ops,
.mac = &dwmac1000_ops,
- .hwtimestamp = &stmmac_ptp,
+ .hwtimestamp = &dwmac1000_ptp,
+ .ptp = &dwmac1000_ptp_clock_ops,
.mode = NULL,
.tc = NULL,
.mmc = &dwmac_mmc_ops,
@@ -170,6 +174,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwmac4_dma_ops,
.mac = &dwmac4_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwmac4_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -185,11 +190,13 @@ static const struct stmmac_hwif_entry {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
.est_off = EST_GMAC4_OFFSET,
+ .fpe_reg = &dwmac5_fpe_reg,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac4_dma_ops,
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -205,11 +212,13 @@ static const struct stmmac_hwif_entry {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
.est_off = EST_GMAC4_OFFSET,
+ .fpe_reg = &dwmac5_fpe_reg,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac410_dma_ops,
.mac = &dwmac410_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -225,11 +234,13 @@ static const struct stmmac_hwif_entry {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
.est_off = EST_GMAC4_OFFSET,
+ .fpe_reg = &dwmac5_fpe_reg,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac410_dma_ops,
.mac = &dwmac510_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
@@ -246,11 +257,13 @@ static const struct stmmac_hwif_entry {
.ptp_off = PTP_XGMAC_OFFSET,
.mmc_off = MMC_XGMAC_OFFSET,
.est_off = EST_XGMAC_OFFSET,
+ .fpe_reg = &dwxgmac3_fpe_reg,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxgmac210_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwxgmac_tc_ops,
.mmc = &dwxgmac_mmc_ops,
@@ -267,11 +280,13 @@ static const struct stmmac_hwif_entry {
.ptp_off = PTP_XGMAC_OFFSET,
.mmc_off = MMC_XGMAC_OFFSET,
.est_off = EST_XGMAC_OFFSET,
+ .fpe_reg = &dwxgmac3_fpe_reg,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
.mac = &dwxlgmac2_ops,
.hwtimestamp = &stmmac_ptp,
+ .ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwxgmac_tc_ops,
.mmc = &dwxgmac_mmc_ops,
@@ -353,8 +368,11 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
mac->est = mac->est ? : entry->est;
priv->hw = mac;
+ priv->fpe_cfg.reg = entry->regs.fpe_reg;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
+ memcpy(&priv->ptp_clock_ops, entry->ptp,
+ sizeof(struct ptp_clock_info));
if (entry->est)
priv->estaddr = priv->ioaddr + entry->regs.est_off;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index d5a9f01ecac5..64f8ed67dcc4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -420,15 +420,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);
- void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
- u32 num_txq, u32 num_rxq,
- bool tx_enable, bool pmac_enable);
- void (*fpe_send_mpacket)(void __iomem *ioaddr,
- struct stmmac_fpe_cfg *cfg,
- enum stmmac_mpacket_type type);
- int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
- int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
- void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
int (*fpe_map_preemption_class)(struct net_device *ndev,
struct netlink_ext_ack *extack,
u32 pclass);
@@ -530,16 +521,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_fpe_configure(__priv, __args...) \
- stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
-#define stmmac_fpe_send_mpacket(__priv, __args...) \
- stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args)
-#define stmmac_fpe_irq_status(__priv, __args...) \
- stmmac_do_callback(__priv, mac, fpe_irq_status, __args)
-#define stmmac_fpe_get_add_frag_size(__priv, __args...) \
- stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
-#define stmmac_fpe_set_add_frag_size(__priv, __args...) \
- stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
@@ -678,6 +659,7 @@ struct stmmac_est_ops {
stmmac_do_void_callback(__priv, est, irq_status, __args)
struct stmmac_regs_off {
+ const struct stmmac_fpe_reg *fpe_reg;
u32 ptp_off;
u32 mmc_off;
u32 est_off;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index ea135203ff2e..1d86439b8a14 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -146,21 +146,13 @@ struct stmmac_channel {
u32 index;
};
-/* FPE link-partner hand-shaking mPacket type */
-enum stmmac_mpacket_type {
- MPACKET_VERIFY = 0,
- MPACKET_RESPONSE = 1,
-};
-
-#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
-#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
-
struct stmmac_fpe_cfg {
/* Serialize access to MAC Merge state between ethtool requests
* and link state updates.
*/
spinlock_t lock;
+ const struct stmmac_fpe_reg *reg;
u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */
enum ethtool_mm_verify_status status;
@@ -420,7 +412,6 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
-void stmmac_fpe_apply(struct stmmac_priv *priv);
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 2a37592a6281..1d77389ce953 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -17,9 +17,9 @@
#include <linux/net_tstamp.h>
#include "stmmac.h"
+#include "stmmac_fpe.h"
#include "dwmac_dma.h"
#include "dwxgmac2.h"
-#include "dwmac5.h"
#define REG_SPACE_SIZE 0x1060
#define GMAC4_REG_SPACE_SIZE 0x116C
@@ -1271,7 +1271,7 @@ static int stmmac_get_mm(struct net_device *ndev,
unsigned long flags;
u32 frag_size;
- if (!priv->dma_cap.fpesel)
+ if (!stmmac_fpe_supported(priv))
return -EOPNOTSUPP;
spin_lock_irqsave(&priv->fpe_cfg.lock, flags);
@@ -1294,7 +1294,7 @@ static int stmmac_get_mm(struct net_device *ndev,
else
state->tx_active = false;
- frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr);
+ frag_size = stmmac_fpe_get_add_frag_size(priv);
state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size);
spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags);
@@ -1329,7 +1329,7 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
if (!cfg->verify_enabled)
fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
- stmmac_fpe_set_add_frag_size(priv, priv->ioaddr, frag_size);
+ stmmac_fpe_set_add_frag_size(priv, frag_size);
stmmac_fpe_apply(priv);
spin_unlock_irqrestore(&fpe_cfg->lock, flags);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
new file mode 100644
index 000000000000..3a4bee029c7f
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
@@ -0,0 +1,413 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
+ * stmmac FPE(802.3 Qbu) handling
+ */
+#include "stmmac.h"
+#include "stmmac_fpe.h"
+#include "dwmac4.h"
+#include "dwmac5.h"
+#include "dwxgmac2.h"
+
+#define GMAC5_MAC_FPE_CTRL_STS 0x00000234
+#define XGMAC_MAC_FPE_CTRL_STS 0x00000280
+
+#define GMAC5_MTL_FPE_CTRL_STS 0x00000c90
+#define XGMAC_MTL_FPE_CTRL_STS 0x00001090
+/* Preemption Classification */
+#define FPE_MTL_PREEMPTION_CLASS GENMASK(15, 8)
+/* Additional Fragment Size of preempted frames */
+#define FPE_MTL_ADD_FRAG_SZ GENMASK(1, 0)
+
+#define STMMAC_MAC_FPE_CTRL_STS_TRSP BIT(19)
+#define STMMAC_MAC_FPE_CTRL_STS_TVER BIT(18)
+#define STMMAC_MAC_FPE_CTRL_STS_RRSP BIT(17)
+#define STMMAC_MAC_FPE_CTRL_STS_RVER BIT(16)
+#define STMMAC_MAC_FPE_CTRL_STS_SRSP BIT(2)
+#define STMMAC_MAC_FPE_CTRL_STS_SVER BIT(1)
+#define STMMAC_MAC_FPE_CTRL_STS_EFPE BIT(0)
+
+/* FPE link-partner hand-shaking mPacket type */
+enum stmmac_mpacket_type {
+ MPACKET_VERIFY = 0,
+ MPACKET_RESPONSE = 1,
+};
+
+struct stmmac_fpe_reg {
+ const u32 mac_fpe_reg; /* offset of MAC_FPE_CTRL_STS */
+ const u32 mtl_fpe_reg; /* offset of MTL_FPE_CTRL_STS */
+ const u32 rxq_ctrl1_reg; /* offset of MAC_RxQ_Ctrl1 */
+ const u32 fprq_mask; /* Frame Preemption Residue Queue */
+ const u32 int_en_reg; /* offset of MAC_Interrupt_Enable */
+ const u32 int_en_bit; /* Frame Preemption Interrupt Enable */
+};
+
+bool stmmac_fpe_supported(struct stmmac_priv *priv)
+{
+ return priv->dma_cap.fpesel && priv->fpe_cfg.reg &&
+ priv->hw->mac->fpe_map_preemption_class;
+}
+
+static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable,
+ bool pmac_enable)
+{
+ struct stmmac_fpe_cfg *cfg = &priv->fpe_cfg;
+ const struct stmmac_fpe_reg *reg = cfg->reg;
+ u32 num_rxq = priv->plat->rx_queues_to_use;
+ void __iomem *ioaddr = priv->ioaddr;
+ u32 value;
+
+ if (tx_enable) {
+ cfg->fpe_csr = STMMAC_MAC_FPE_CTRL_STS_EFPE;
+ value = readl(ioaddr + reg->rxq_ctrl1_reg);
+ value &= ~reg->fprq_mask;
+ /* Keep this SHIFT, FIELD_PREP() expects a constant mask :-/ */
+ value |= (num_rxq - 1) << __ffs(reg->fprq_mask);
+ writel(value, ioaddr + reg->rxq_ctrl1_reg);
+ } else {
+ cfg->fpe_csr = 0;
+ }
+ writel(cfg->fpe_csr, ioaddr + reg->mac_fpe_reg);
+
+ value = readl(ioaddr + reg->int_en_reg);
+
+ if (pmac_enable) {
+ if (!(value & reg->int_en_bit)) {
+ /* Dummy read to clear any pending masked interrupts */
+ readl(ioaddr + reg->mac_fpe_reg);
+
+ value |= reg->int_en_bit;
+ }
+ } else {
+ value &= ~reg->int_en_bit;
+ }
+
+ writel(value, ioaddr + reg->int_en_reg);
+}
+
+static void stmmac_fpe_send_mpacket(struct stmmac_priv *priv,
+ enum stmmac_mpacket_type type)
+{
+ const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
+ void __iomem *ioaddr = priv->ioaddr;
+ u32 value = priv->fpe_cfg.fpe_csr;
+
+ if (type == MPACKET_VERIFY)
+ value |= STMMAC_MAC_FPE_CTRL_STS_SVER;
+ else if (type == MPACKET_RESPONSE)
+ value |= STMMAC_MAC_FPE_CTRL_STS_SRSP;
+
+ writel(value, ioaddr + reg->mac_fpe_reg);
+}
+
+static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
+{
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+
+ /* This is interrupt context, just spin_lock() */
+ spin_lock(&fpe_cfg->lock);
+
+ if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
+ goto unlock_out;
+
+ /* LP has sent verify mPacket */
+ if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
+ stmmac_fpe_send_mpacket(priv, MPACKET_RESPONSE);
+
+ /* Local has sent verify mPacket */
+ if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
+ fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
+
+ /* LP has sent response mPacket */
+ if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
+ fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
+
+unlock_out:
+ spin_unlock(&fpe_cfg->lock);
+}
+
+void stmmac_fpe_irq_status(struct stmmac_priv *priv)
+{
+ const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
+ void __iomem *ioaddr = priv->ioaddr;
+ struct net_device *dev = priv->dev;
+ int status = FPE_EVENT_UNKNOWN;
+ u32 value;
+
+ /* Reads from the MAC_FPE_CTRL_STS register should only be performed
+ * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
+ */
+ value = readl(ioaddr + reg->mac_fpe_reg);
+
+ if (value & STMMAC_MAC_FPE_CTRL_STS_TRSP) {
+ status |= FPE_EVENT_TRSP;
+ netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n");
+ }
+
+ if (value & STMMAC_MAC_FPE_CTRL_STS_TVER) {
+ status |= FPE_EVENT_TVER;
+ netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n");
+ }
+
+ if (value & STMMAC_MAC_FPE_CTRL_STS_RRSP) {
+ status |= FPE_EVENT_RRSP;
+ netdev_dbg(dev, "FPE: Respond mPacket is received\n");
+ }
+
+ if (value & STMMAC_MAC_FPE_CTRL_STS_RVER) {
+ status |= FPE_EVENT_RVER;
+ netdev_dbg(dev, "FPE: Verify mPacket is received\n");
+ }
+
+ stmmac_fpe_event_status(priv, status);
+}
+
+/**
+ * stmmac_fpe_verify_timer - Timer for MAC Merge verification
+ * @t: timer_list struct containing private info
+ *
+ * Verify the MAC Merge capability in the local TX direction, by
+ * transmitting Verify mPackets up to 3 times. Wait until link
+ * partner responds with a Response mPacket, otherwise fail.
+ */
+static void stmmac_fpe_verify_timer(struct timer_list *t)
+{
+ struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
+ struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
+ fpe_cfg);
+ unsigned long flags;
+ bool rearm = false;
+
+ spin_lock_irqsave(&fpe_cfg->lock, flags);
+
+ switch (fpe_cfg->status) {
+ case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
+ case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
+ if (fpe_cfg->verify_retries != 0) {
+ stmmac_fpe_send_mpacket(priv, MPACKET_VERIFY);
+ rearm = true;
+ } else {
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
+ }
+
+ fpe_cfg->verify_retries--;
+ break;
+
+ case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
+ stmmac_fpe_configure(priv, true, true);
+ break;
+
+ default:
+ break;
+ }
+
+ if (rearm) {
+ mod_timer(&fpe_cfg->verify_timer,
+ jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
+ }
+
+ spin_unlock_irqrestore(&fpe_cfg->lock, flags);
+}
+
+static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
+{
+ if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
+ fpe_cfg->verify_enabled &&
+ fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
+ fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
+ timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
+ mod_timer(&fpe_cfg->verify_timer, jiffies);
+ }
+}
+
+void stmmac_fpe_init(struct stmmac_priv *priv)
+{
+ priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
+ priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
+ priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+ timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
+ spin_lock_init(&priv->fpe_cfg.lock);
+
+ if ((!priv->fpe_cfg.reg || !priv->hw->mac->fpe_map_preemption_class) &&
+ priv->dma_cap.fpesel)
+ dev_info(priv->device, "FPE is not supported by driver.\n");
+}
+
+void stmmac_fpe_apply(struct stmmac_priv *priv)
+{
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+
+ /* If verification is disabled, configure FPE right away.
+ * Otherwise let the timer code do it.
+ */
+ if (!fpe_cfg->verify_enabled) {
+ stmmac_fpe_configure(priv, fpe_cfg->tx_enabled,
+ fpe_cfg->pmac_enabled);
+ } else {
+ fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
+ fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
+
+ if (netif_running(priv->dev))
+ stmmac_fpe_verify_timer_arm(fpe_cfg);
+ }
+}
+
+void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
+{
+ struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
+ unsigned long flags;
+
+ timer_shutdown_sync(&fpe_cfg->verify_timer);
+
+ spin_lock_irqsave(&fpe_cfg->lock, flags);
+
+ if (is_up && fpe_cfg->pmac_enabled) {
+ /* VERIFY process requires pmac enabled when NIC comes up */
+ stmmac_fpe_configure(priv, false, true);
+
+ /* New link => maybe new partner => new verification process */
+ stmmac_fpe_apply(priv);
+ } else {
+ /* No link => turn off EFPE */
+ stmmac_fpe_configure(priv, false, false);
+ }
+
+ spin_unlock_irqrestore(&fpe_cfg->lock, flags);
+}
+
+int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv)
+{
+ const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
+ void __iomem *ioaddr = priv->ioaddr;
+
+ return FIELD_GET(FPE_MTL_ADD_FRAG_SZ, readl(ioaddr + reg->mtl_fpe_reg));
+}
+
+void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size)
+{
+ const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg;
+ void __iomem *ioaddr = priv->ioaddr;
+ u32 value;
+
+ value = readl(ioaddr + reg->mtl_fpe_reg);
+ writel(u32_replace_bits(value, add_frag_size, FPE_MTL_ADD_FRAG_SZ),
+ ioaddr + reg->mtl_fpe_reg);
+}
+
+#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
+#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
+
+int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
+ struct netlink_ext_ack *extack, u32 pclass)
+{
+ u32 val, offset, count, queue_weight, preemptible_txqs = 0;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int num_tc = netdev_get_num_tc(ndev);
+
+ if (!pclass)
+ goto update_mapping;
+
+ /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
+ *
+ * Synopsys Databook:
+ * "The number of Tx DMA channels is equal to the number of Tx queues,
+ * and is direct one-to-one mapping."
+ */
+ for (u32 tc = 0; tc < num_tc; tc++) {
+ count = ndev->tc_to_txq[tc].count;
+ offset = ndev->tc_to_txq[tc].offset;
+
+ if (pclass & BIT(tc))
+ preemptible_txqs |= GENMASK(offset + count - 1, offset);
+
+ /* This is 1:1 mapping, go to next TC */
+ if (count == 1)
+ continue;
+
+ if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
+ NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
+ return -EINVAL;
+ }
+
+ queue_weight = priv->plat->tx_queues_cfg[offset].weight;
+
+ for (u32 i = 1; i < count; i++) {
+ if (priv->plat->tx_queues_cfg[offset + i].weight !=
+ queue_weight) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
+ queue_weight, tc);
+ return -EINVAL;
+ }
+ }
+ }
+
+update_mapping:
+ val = readl(priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS);
+ writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS),
+ priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS);
+
+ return 0;
+}
+
+int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
+ struct netlink_ext_ack *extack, u32 pclass)
+{
+ u32 val, offset, count, preemptible_txqs = 0;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int num_tc = netdev_get_num_tc(ndev);
+
+ if (!num_tc) {
+ /* Restore default TC:Queue mapping */
+ for (u32 i = 0; i < priv->plat->tx_queues_to_use; i++) {
+ val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
+ writel(u32_replace_bits(val, i, XGMAC_Q2TCMAP),
+ priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
+ }
+ }
+
+ /* Synopsys Databook:
+ * "All Queues within a traffic class are selected in a round robin
+ * fashion (when packets are available) when the traffic class is
+ * selected by the scheduler for packet transmission. This is true for
+ * any of the scheduling algorithms."
+ */
+ for (u32 tc = 0; tc < num_tc; tc++) {
+ count = ndev->tc_to_txq[tc].count;
+ offset = ndev->tc_to_txq[tc].offset;
+
+ if (pclass & BIT(tc))
+ preemptible_txqs |= GENMASK(offset + count - 1, offset);
+
+ for (u32 i = 0; i < count; i++) {
+ val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
+ writel(u32_replace_bits(val, tc, XGMAC_Q2TCMAP),
+ priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
+ }
+ }
+
+ val = readl(priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS);
+ writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS),
+ priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS);
+
+ return 0;
+}
+
+const struct stmmac_fpe_reg dwmac5_fpe_reg = {
+ .mac_fpe_reg = GMAC5_MAC_FPE_CTRL_STS,
+ .mtl_fpe_reg = GMAC5_MTL_FPE_CTRL_STS,
+ .rxq_ctrl1_reg = GMAC_RXQ_CTRL1,
+ .fprq_mask = GMAC_RXQCTRL_FPRQ,
+ .int_en_reg = GMAC_INT_EN,
+ .int_en_bit = GMAC_INT_FPE_EN,
+};
+
+const struct stmmac_fpe_reg dwxgmac3_fpe_reg = {
+ .mac_fpe_reg = XGMAC_MAC_FPE_CTRL_STS,
+ .mtl_fpe_reg = XGMAC_MTL_FPE_CTRL_STS,
+ .rxq_ctrl1_reg = XGMAC_RXQ_CTRL1,
+ .fprq_mask = XGMAC_FPRQ,
+ .int_en_reg = XGMAC_INT_EN,
+ .int_en_bit = XGMAC_FPEIE,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
new file mode 100644
index 000000000000..b884eac7142d
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2024 Furong Xu <0x1207@gmail.com>
+ * stmmac FPE(802.3 Qbu) handling
+ */
+#ifndef _STMMAC_FPE_H_
+#define _STMMAC_FPE_H_
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3
+#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128
+
+struct stmmac_priv;
+
+void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up);
+bool stmmac_fpe_supported(struct stmmac_priv *priv);
+void stmmac_fpe_init(struct stmmac_priv *priv);
+void stmmac_fpe_apply(struct stmmac_priv *priv);
+void stmmac_fpe_irq_status(struct stmmac_priv *priv);
+int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv);
+void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size);
+
+int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
+ struct netlink_ext_ack *extack, u32 pclass);
+int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
+ struct netlink_ext_ack *extack, u32 pclass);
+
+extern const struct stmmac_fpe_reg dwmac5_fpe_reg;
+extern const struct stmmac_fpe_reg dwxgmac3_fpe_reg;
+
+#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 5ef52ef2698f..0f59aa982604 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -18,9 +18,22 @@
#include "dwmac4.h"
#include "stmmac.h"
+#define STMMAC_HWTS_CFG_MASK (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \
+ PTP_TCR_TSINIT | PTP_TCR_TSUPDT | \
+ PTP_TCR_TSCTRLSSR | PTP_TCR_SNAPTYPSEL_1 | \
+ PTP_TCR_TSIPV4ENA | PTP_TCR_TSIPV6ENA | \
+ PTP_TCR_TSEVNTENA | PTP_TCR_TSMSTRENA | \
+ PTP_TCR_TSVER2ENA | PTP_TCR_TSIPENA | \
+ PTP_TCR_TSTRIG | PTP_TCR_TSENALL)
+
static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
{
- writel(data, ioaddr + PTP_TCR);
+ u32 regval = readl(ioaddr + PTP_TCR);
+
+ regval &= ~STMMAC_HWTS_CFG_MASK;
+ regval |= data;
+
+ writel(regval, ioaddr + PTP_TCR);
}
static void config_sub_second_increment(void __iomem *ioaddr,
@@ -269,3 +282,14 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
.timestamp_interrupt = timestamp_interrupt,
.hwtstamp_correct_latency = hwtstamp_correct_latency,
};
+
+const struct stmmac_hwtimestamp dwmac1000_ptp = {
+ .config_hw_tstamping = config_hw_tstamping,
+ .init_systime = init_systime,
+ .config_sub_second_increment = config_sub_second_increment,
+ .config_addend = config_addend,
+ .adjust_systime = adjust_systime,
+ .get_systime = get_systime,
+ .get_ptptime = dwmac1000_get_ptptime,
+ .timestamp_interrupt = dwmac1000_timestamp_interrupt,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d3895d7eecfc..3cdc3910f3a0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -43,6 +43,7 @@
#include <net/pkt_cls.h>
#include <net/xdp_sock_drv.h>
#include "stmmac_ptp.h"
+#include "stmmac_fpe.h"
#include "stmmac.h"
#include "stmmac_xdp.h"
#include <linux/reset.h>
@@ -966,35 +967,6 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
/* Nothing to do, xpcs_config() handles everything */
}
-static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
-{
- struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
- unsigned long flags;
-
- timer_shutdown_sync(&fpe_cfg->verify_timer);
-
- spin_lock_irqsave(&fpe_cfg->lock, flags);
-
- if (is_up && fpe_cfg->pmac_enabled) {
- /* VERIFY process requires pmac enabled when NIC comes up */
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- false, true);
-
- /* New link => maybe new partner => new verification process */
- stmmac_fpe_apply(priv);
- } else {
- /* No link => turn off EFPE */
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- false, false);
- }
-
- spin_unlock_irqrestore(&fpe_cfg->lock, flags);
-}
-
static void stmmac_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
@@ -1006,7 +978,7 @@ static void stmmac_mac_link_down(struct phylink_config *config,
priv->eee_enabled = stmmac_eee_init(priv);
stmmac_set_eee_pls(priv, priv->hw, false);
- if (priv->dma_cap.fpesel)
+ if (stmmac_fpe_supported(priv))
stmmac_fpe_link_state_handle(priv, false);
}
@@ -1120,7 +1092,7 @@ static void stmmac_mac_link_up(struct phylink_config *config,
stmmac_set_eee_pls(priv, priv->hw, true);
}
- if (priv->dma_cap.fpesel)
+ if (stmmac_fpe_supported(priv))
stmmac_fpe_link_state_handle(priv, true);
if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
@@ -3780,6 +3752,7 @@ static int stmmac_request_irq_single(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) {
ret = request_irq(priv->wol_irq, stmmac_interrupt,
IRQF_SHARED, dev->name, dev);
@@ -4068,7 +4041,7 @@ static int stmmac_release(struct net_device *dev)
stmmac_release_ptp(priv);
- if (priv->dma_cap.fpesel)
+ if (stmmac_fpe_supported(priv))
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
pm_runtime_put(priv->device);
@@ -4304,11 +4277,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
if (dma_mapping_error(priv->device, des))
goto dma_map_err;
- tx_q->tx_skbuff_dma[first_entry].buf = des;
- tx_q->tx_skbuff_dma[first_entry].len = skb_headlen(skb);
- tx_q->tx_skbuff_dma[first_entry].map_as_page = false;
- tx_q->tx_skbuff_dma[first_entry].buf_type = STMMAC_TXBUF_T_SKB;
-
if (priv->dma_cap.addr64 <= 32) {
first->des0 = cpu_to_le32(des);
@@ -4327,6 +4295,23 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
stmmac_tso_allocator(priv, des, tmp_pay_len, (nfrags == 0), queue);
+ /* In case two or more DMA transmit descriptors are allocated for this
+ * non-paged SKB data, the DMA buffer address should be saved to
+ * tx_q->tx_skbuff_dma[].buf corresponding to the last descriptor,
+ * and leave the other tx_q->tx_skbuff_dma[].buf as NULL to guarantee
+ * that stmmac_tx_clean() does not unmap the entire DMA buffer too early
+ * since the tail areas of the DMA buffer can be accessed by DMA engine
+ * sooner or later.
+ * By saving the DMA buffer address to tx_q->tx_skbuff_dma[].buf
+ * corresponding to the last descriptor, stmmac_tx_clean() will unmap
+ * this DMA buffer right after the DMA engine completely finishes the
+ * full buffer transmission.
+ */
+ tx_q->tx_skbuff_dma[tx_q->cur_tx].buf = des;
+ tx_q->tx_skbuff_dma[tx_q->cur_tx].len = skb_headlen(skb);
+ tx_q->tx_skbuff_dma[tx_q->cur_tx].map_as_page = false;
+ tx_q->tx_skbuff_dma[tx_q->cur_tx].buf_type = STMMAC_TXBUF_T_SKB;
+
/* Prepare fragments */
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -5953,35 +5938,6 @@ static int stmmac_set_features(struct net_device *netdev,
return 0;
}
-static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
-{
- struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
-
- /* This is interrupt context, just spin_lock() */
- spin_lock(&fpe_cfg->lock);
-
- if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN)
- goto unlock_out;
-
- /* LP has sent verify mPacket */
- if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER)
- stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
- MPACKET_RESPONSE);
-
- /* Local has sent verify mPacket */
- if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER &&
- fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED)
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
-
- /* LP has sent response mPacket */
- if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP &&
- fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING)
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
-
-unlock_out:
- spin_unlock(&fpe_cfg->lock);
-}
-
static void stmmac_common_interrupt(struct stmmac_priv *priv)
{
u32 rx_cnt = priv->plat->rx_queues_to_use;
@@ -6000,12 +5956,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
stmmac_est_irq_status(priv, priv, priv->dev,
&priv->xstats, tx_cnt);
- if (priv->dma_cap.fpesel) {
- int status = stmmac_fpe_irq_status(priv, priv->ioaddr,
- priv->dev);
-
- stmmac_fpe_event_status(priv, status);
- }
+ if (stmmac_fpe_supported(priv))
+ stmmac_fpe_irq_status(priv);
/* To handle GMAC own interrupts */
if ((priv->plat->has_gmac) || xmac) {
@@ -7337,90 +7289,6 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size)
return ret;
}
-/**
- * stmmac_fpe_verify_timer - Timer for MAC Merge verification
- * @t: timer_list struct containing private info
- *
- * Verify the MAC Merge capability in the local TX direction, by
- * transmitting Verify mPackets up to 3 times. Wait until link
- * partner responds with a Response mPacket, otherwise fail.
- */
-static void stmmac_fpe_verify_timer(struct timer_list *t)
-{
- struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer);
- struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv,
- fpe_cfg);
- unsigned long flags;
- bool rearm = false;
-
- spin_lock_irqsave(&fpe_cfg->lock, flags);
-
- switch (fpe_cfg->status) {
- case ETHTOOL_MM_VERIFY_STATUS_INITIAL:
- case ETHTOOL_MM_VERIFY_STATUS_VERIFYING:
- if (fpe_cfg->verify_retries != 0) {
- stmmac_fpe_send_mpacket(priv, priv->ioaddr,
- fpe_cfg, MPACKET_VERIFY);
- rearm = true;
- } else {
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
- }
-
- fpe_cfg->verify_retries--;
- break;
-
- case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED:
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- true, true);
- break;
-
- default:
- break;
- }
-
- if (rearm) {
- mod_timer(&fpe_cfg->verify_timer,
- jiffies + msecs_to_jiffies(fpe_cfg->verify_time));
- }
-
- spin_unlock_irqrestore(&fpe_cfg->lock, flags);
-}
-
-static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg)
-{
- if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled &&
- fpe_cfg->verify_enabled &&
- fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED &&
- fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) {
- timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0);
- mod_timer(&fpe_cfg->verify_timer, jiffies);
- }
-}
-
-void stmmac_fpe_apply(struct stmmac_priv *priv)
-{
- struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg;
-
- /* If verification is disabled, configure FPE right away.
- * Otherwise let the timer code do it.
- */
- if (!fpe_cfg->verify_enabled) {
- stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
- priv->plat->tx_queues_to_use,
- priv->plat->rx_queues_to_use,
- fpe_cfg->tx_enabled,
- fpe_cfg->pmac_enabled);
- } else {
- fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
- fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
-
- if (netif_running(priv->dev))
- stmmac_fpe_verify_timer_arm(fpe_cfg);
- }
-}
-
static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
{
const struct stmmac_xdp_buff *ctx = (void *)_ctx;
@@ -7699,11 +7567,7 @@ int stmmac_dvr_probe(struct device *device,
mutex_init(&priv->lock);
- priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES;
- priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS;
- priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
- timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0);
- spin_lock_init(&priv->fpe_cfg.lock);
+ stmmac_fpe_init(priv);
/* If a specific clk_csr value is passed from the platform
* this means that the CSR Clock Range selection cannot be
@@ -7878,7 +7742,7 @@ int stmmac_suspend(struct device *dev)
}
rtnl_unlock();
- if (priv->dma_cap.fpesel)
+ if (stmmac_fpe_supported(priv))
timer_shutdown_sync(&priv->fpe_cfg.verify_timer);
priv->speed = SPEED_UNKNOWN;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index ad868e8d195d..3ac32444e492 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -522,6 +522,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
if (of_device_is_compatible(np, "st,spear600-gmac") ||
of_device_is_compatible(np, "snps,dwmac-3.50a") ||
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
+ of_device_is_compatible(np, "snps,dwmac-3.72a") ||
of_device_is_compatible(np, "snps,dwmac")) {
/* Note that the max-frame-size parameter as defined in the
* ePAPR v1.1 spec is defined as max-frame-size, it's
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index a6b1de9a251d..429b2d357813 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -9,7 +9,6 @@
*******************************************************************************/
#include "stmmac.h"
#include "stmmac_ptp.h"
-#include "dwmac4.h"
/**
* stmmac_adjust_freq
@@ -265,7 +264,7 @@ static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
}
/* structure describing a PTP hardware clock */
-static struct ptp_clock_info stmmac_ptp_clock_ops = {
+const struct ptp_clock_info stmmac_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "stmmac ptp",
.max_adj = 62500000,
@@ -282,6 +281,24 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
.getcrosststamp = stmmac_getcrosststamp,
};
+/* structure describing a PTP hardware clock */
+const struct ptp_clock_info dwmac1000_ptp_clock_ops = {
+ .owner = THIS_MODULE,
+ .name = "stmmac ptp",
+ .max_adj = 62500000,
+ .n_alarm = 0,
+ .n_ext_ts = 1,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pps = 0,
+ .adjfine = stmmac_adjust_freq,
+ .adjtime = stmmac_adjust_time,
+ .gettime64 = stmmac_get_time,
+ .settime64 = stmmac_set_time,
+ .enable = dwmac1000_ptp_enable,
+ .getcrosststamp = stmmac_getcrosststamp,
+};
+
/**
* stmmac_ptp_register
* @priv: driver private structure
@@ -298,20 +315,25 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
priv->pps[i].available = true;
}
- if (priv->plat->ptp_max_adj)
- stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
-
/* Calculate the clock domain crossing (CDC) error if necessary */
priv->plat->cdc_error_adj = 0;
if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
- stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
- stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
+ /* Update the ptp clock parameters based on feature discovery, when
+ * available
+ */
+ if (priv->dma_cap.pps_out_num)
+ priv->ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num;
+
+ if (priv->dma_cap.aux_snapshot_n)
+ priv->ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n;
+
+ if (priv->plat->ptp_max_adj)
+ priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj;
rwlock_init(&priv->ptp_lock);
mutex_init(&priv->aux_ts_lock);
- priv->ptp_clock_ops = stmmac_ptp_clock_ops;
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
priv->device);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index fce3fba2ffd2..4cc70480ce0f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -94,4 +94,14 @@ enum aux_snapshot {
AUX_SNAPSHOT3 = 0x80,
};
+struct ptp_clock_info;
+struct ptp_clock_request;
+struct stmmac_priv;
+
+int dwmac1000_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on);
+
+void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time);
+void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv);
+
#endif /* __STMMAC_PTP_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 75ad2da1a37f..6a79e6a111ed 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1290,8 +1290,8 @@ const struct stmmac_tc_ops dwxgmac_tc_ops = {
.setup_cls_u32 = tc_setup_cls_u32,
.setup_cbs = tc_setup_cbs,
.setup_cls = tc_setup_cls,
- .setup_taprio = tc_setup_taprio_without_fpe,
+ .setup_taprio = tc_setup_taprio,
.setup_etf = tc_setup_etf,
.query_caps = tc_query_caps,
- .setup_mqprio = tc_setup_mqprio_unimplemented,
+ .setup_mqprio = tc_setup_dwmac510_mqprio,
};
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 6201a09fa5f0..47fb5af16796 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -337,9 +337,9 @@ static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common,
struct am65_cpsw_rx_chn *rx_chn = &common->rx_chns;
struct cppi5_host_desc_t *desc_rx;
struct device *dev = common->dev;
+ struct am65_cpsw_swdata *swdata;
dma_addr_t desc_dma;
dma_addr_t buf_dma;
- void *swdata;
desc_rx = k3_cppi_desc_pool_alloc(rx_chn->desc_pool);
if (!desc_rx) {
@@ -363,7 +363,8 @@ static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common,
cppi5_hdesc_attach_buf(desc_rx, buf_dma, AM65_CPSW_MAX_PACKET_SIZE,
buf_dma, AM65_CPSW_MAX_PACKET_SIZE);
swdata = cppi5_hdesc_get_swdata(desc_rx);
- *((void **)swdata) = page_address(page);
+ swdata->page = page;
+ swdata->flow_id = flow_idx;
return k3_udma_glue_push_rx_chn(rx_chn->rx_chn, flow_idx,
desc_rx, desc_dma);
@@ -519,36 +520,31 @@ static enum am65_cpsw_tx_buf_type am65_cpsw_nuss_buf_type(struct am65_cpsw_tx_ch
static inline void am65_cpsw_put_page(struct am65_cpsw_rx_flow *flow,
struct page *page,
- bool allow_direct,
- int desc_idx)
+ bool allow_direct)
{
page_pool_put_full_page(flow->page_pool, page, allow_direct);
- flow->pages[desc_idx] = NULL;
}
static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
{
- struct am65_cpsw_rx_flow *flow = data;
+ struct am65_cpsw_rx_chn *rx_chn = data;
struct cppi5_host_desc_t *desc_rx;
- struct am65_cpsw_rx_chn *rx_chn;
+ struct am65_cpsw_swdata *swdata;
dma_addr_t buf_dma;
+ struct page *page;
u32 buf_dma_len;
- void *page_addr;
- void **swdata;
- int desc_idx;
+ u32 flow_id;
- rx_chn = &flow->common->rx_chns;
desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
swdata = cppi5_hdesc_get_swdata(desc_rx);
- page_addr = *swdata;
+ page = swdata->page;
+ flow_id = swdata->flow_id;
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);
- desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx,
- rx_chn->dsize_log2);
- am65_cpsw_put_page(flow, virt_to_page(page_addr), false, desc_idx);
+ am65_cpsw_put_page(&rx_chn->flows[flow_id], page, false);
}
static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn,
@@ -703,14 +699,13 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
ret = -ENOMEM;
goto fail_rx;
}
- flow->pages[i] = page;
ret = am65_cpsw_nuss_rx_push(common, page, flow_idx);
if (ret < 0) {
dev_err(common->dev,
"cannot submit page to rx channel flow %d, error %d\n",
flow_idx, ret);
- am65_cpsw_put_page(flow, page, false, i);
+ am65_cpsw_put_page(flow, page, false);
goto fail_rx;
}
}
@@ -764,8 +759,8 @@ fail_tx:
fail_rx:
for (i = 0; i < common->rx_ch_num_flows; i++)
- k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, &rx_chn->flows[i],
- am65_cpsw_nuss_rx_cleanup, 0);
+ k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
+ am65_cpsw_nuss_rx_cleanup, !!i);
am65_cpsw_destroy_xdp_rxqs(common);
@@ -817,11 +812,11 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
dev_err(common->dev, "rx teardown timeout\n");
}
- for (i = 0; i < common->rx_ch_num_flows; i++) {
+ for (i = common->rx_ch_num_flows - 1; i >= 0; i--) {
napi_disable(&rx_chn->flows[i].napi_rx);
hrtimer_cancel(&rx_chn->flows[i].rx_hrtimer);
- k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, &rx_chn->flows[i],
- am65_cpsw_nuss_rx_cleanup, 0);
+ k3_udma_glue_reset_rx_chn(rx_chn->rx_chn, i, rx_chn,
+ am65_cpsw_nuss_rx_cleanup, !!i);
}
k3_udma_glue_disable_rx_chn(rx_chn->rx_chn);
@@ -1028,7 +1023,7 @@ pool_free:
static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow,
struct am65_cpsw_port *port,
struct xdp_buff *xdp,
- int desc_idx, int cpu, int *len)
+ int cpu, int *len)
{
struct am65_cpsw_common *common = flow->common;
struct net_device *ndev = port->ndev;
@@ -1090,7 +1085,7 @@ drop:
}
page = virt_to_head_page(xdp->data);
- am65_cpsw_put_page(flow, page, true, desc_idx);
+ am65_cpsw_put_page(flow, page, true);
out:
return ret;
@@ -1138,16 +1133,16 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
struct am65_cpsw_ndev_priv *ndev_priv;
struct cppi5_host_desc_t *desc_rx;
struct device *dev = common->dev;
+ struct am65_cpsw_swdata *swdata;
struct page *page, *new_page;
dma_addr_t desc_dma, buf_dma;
struct am65_cpsw_port *port;
- int headroom, desc_idx, ret;
struct net_device *ndev;
u32 flow_idx = flow->id;
struct sk_buff *skb;
struct xdp_buff xdp;
+ int headroom, ret;
void *page_addr;
- void **swdata;
u32 *psdata;
*xdp_state = AM65_CPSW_XDP_PASS;
@@ -1170,8 +1165,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
__func__, flow_idx, &desc_dma);
swdata = cppi5_hdesc_get_swdata(desc_rx);
- page_addr = *swdata;
- page = virt_to_page(page_addr);
+ page = swdata->page;
+ page_addr = page_address(page);
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);
pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
@@ -1187,9 +1182,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
- desc_idx = am65_cpsw_nuss_desc_idx(rx_chn->desc_pool, desc_rx,
- rx_chn->dsize_log2);
-
skb = am65_cpsw_build_skb(page_addr, ndev,
AM65_CPSW_MAX_PACKET_SIZE);
if (unlikely(!skb)) {
@@ -1201,7 +1193,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
xdp_init_buff(&xdp, PAGE_SIZE, &port->xdp_rxq[flow->id]);
xdp_prepare_buff(&xdp, page_addr, AM65_CPSW_HEADROOM,
pkt_len, false);
- *xdp_state = am65_cpsw_run_xdp(flow, port, &xdp, desc_idx,
+ *xdp_state = am65_cpsw_run_xdp(flow, port, &xdp,
cpu, &pkt_len);
if (*xdp_state != AM65_CPSW_XDP_PASS)
goto allocate;
@@ -1230,10 +1222,8 @@ allocate:
return -ENOMEM;
}
- flow->pages[desc_idx] = new_page;
-
if (netif_dormant(ndev)) {
- am65_cpsw_put_page(flow, new_page, true, desc_idx);
+ am65_cpsw_put_page(flow, new_page, true);
ndev->stats.rx_dropped++;
return 0;
}
@@ -1241,7 +1231,7 @@ allocate:
requeue:
ret = am65_cpsw_nuss_rx_push(common, new_page, flow_idx);
if (WARN_ON(ret < 0)) {
- am65_cpsw_put_page(flow, new_page, true, desc_idx);
+ am65_cpsw_put_page(flow, new_page, true);
ndev->stats.rx_errors++;
ndev->stats.rx_dropped++;
}
@@ -2343,10 +2333,6 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
for (i = 0; i < common->rx_ch_num_flows; i++) {
flow = &rx_chn->flows[i];
flow->page_pool = NULL;
- flow->pages = devm_kcalloc(dev, AM65_CPSW_MAX_RX_DESC,
- sizeof(*flow->pages), GFP_KERNEL);
- if (!flow->pages)
- return -ENOMEM;
}
rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, "rx", &rx_cfg);
@@ -2396,10 +2382,12 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
flow = &rx_chn->flows[i];
flow->id = i;
flow->common = common;
+ flow->irq = -EINVAL;
rx_flow_cfg.ring_rxfdq0_id = fdqring_id;
rx_flow_cfg.rx_cfg.size = max_desc_num;
- rx_flow_cfg.rxfdq_cfg.size = max_desc_num;
+ /* share same FDQ for all flows */
+ rx_flow_cfg.rxfdq_cfg.size = max_desc_num * rx_cfg.flow_id_num;
rx_flow_cfg.rxfdq_cfg.mode = common->pdata.fdqring_mode;
ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
@@ -2437,6 +2425,7 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
if (ret) {
dev_err(dev, "failure requesting rx %d irq %u, %d\n",
i, flow->irq, ret);
+ flow->irq = -EINVAL;
goto err;
}
}
@@ -3274,8 +3263,8 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
for (i = 0; i < common->rx_ch_num_flows; i++)
k3_udma_glue_reset_rx_chn(rx_chan->rx_chn, i,
- &rx_chan->flows[i],
- am65_cpsw_nuss_rx_cleanup, 0);
+ rx_chan,
+ am65_cpsw_nuss_rx_cleanup, !!i);
k3_udma_glue_disable_rx_chn(rx_chan->rx_chn);
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index 3f3e353dfe88..e7832a5cf3cc 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -101,10 +101,14 @@ struct am65_cpsw_rx_flow {
struct hrtimer rx_hrtimer;
unsigned long rx_pace_timeout;
struct page_pool *page_pool;
- struct page **pages;
char name[32];
};
+struct am65_cpsw_swdata {
+ u32 flow_id;
+ struct page *page;
+};
+
struct am65_cpsw_rx_chn {
struct device *dev;
struct device *dma_dev;
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 0556910938fa..c568c84a032b 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -16,6 +16,7 @@
#include <linux/if_hsr.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
@@ -411,6 +412,8 @@ static int prueth_perout_enable(void *clockops_data,
struct prueth_emac *emac = clockops_data;
u32 reduction_factor = 0, offset = 0;
struct timespec64 ts;
+ u64 current_cycle;
+ u64 start_offset;
u64 ns_period;
if (!on)
@@ -449,8 +452,14 @@ static int prueth_perout_enable(void *clockops_data,
writel(reduction_factor, emac->prueth->shram.va +
TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);
- writel(0, emac->prueth->shram.va +
- TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
+ current_cycle = icssg_read_time(emac->prueth->shram.va +
+ TIMESYNC_FW_WC_CYCLECOUNT_OFFSET);
+
+ /* Rounding of current_cycle count to next second */
+ start_offset = roundup(current_cycle, MSEC_PER_SEC);
+
+ hi_lo_writeq(start_offset, emac->prueth->shram.va +
+ TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);
return 0;
}
@@ -808,6 +817,47 @@ static netdev_features_t emac_ndo_fix_features(struct net_device *ndev,
return features;
}
+static int emac_ndo_vlan_rx_add_vid(struct net_device *ndev,
+ __be16 proto, u16 vid)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth *prueth = emac->prueth;
+ int untag_mask = 0;
+ int port_mask;
+
+ if (prueth->is_hsr_offload_mode) {
+ port_mask = BIT(PRUETH_PORT_HOST) | BIT(emac->port_id);
+ untag_mask = 0;
+
+ netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X\n",
+ vid, port_mask, untag_mask);
+
+ icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true);
+ icssg_set_pvid(emac->prueth, vid, emac->port_id);
+ }
+ return 0;
+}
+
+static int emac_ndo_vlan_rx_del_vid(struct net_device *ndev,
+ __be16 proto, u16 vid)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth *prueth = emac->prueth;
+ int untag_mask = 0;
+ int port_mask;
+
+ if (prueth->is_hsr_offload_mode) {
+ port_mask = BIT(PRUETH_PORT_HOST);
+ untag_mask = 0;
+
+ netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X untag_mask %X\n",
+ vid, port_mask, untag_mask);
+
+ icssg_vtbl_modify(emac, vid, port_mask, untag_mask, false);
+ }
+ return 0;
+}
+
static const struct net_device_ops emac_netdev_ops = {
.ndo_open = emac_ndo_open,
.ndo_stop = emac_ndo_stop,
@@ -820,6 +870,8 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_get_stats64 = icssg_ndo_get_stats64,
.ndo_get_phys_port_name = icssg_ndo_get_phys_port_name,
.ndo_fix_features = emac_ndo_fix_features,
+ .ndo_vlan_rx_add_vid = emac_ndo_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = emac_ndo_vlan_rx_del_vid,
};
static int prueth_netdev_init(struct prueth *prueth,
@@ -947,7 +999,7 @@ static int prueth_netdev_init(struct prueth *prueth,
ndev->netdev_ops = &emac_netdev_ops;
ndev->ethtool_ops = &icssg_ethtool_ops;
ndev->hw_features = NETIF_F_SG;
- ndev->features = ndev->hw_features;
+ ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES;
netif_napi_add(ndev, &emac->napi_rx, icssg_napi_rx_poll);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index 8722bb4a268a..f5c1d473e9f9 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -330,6 +330,18 @@ static inline int prueth_emac_slice(struct prueth_emac *emac)
extern const struct ethtool_ops icssg_ethtool_ops;
extern const struct dev_pm_ops prueth_dev_pm_ops;
+static inline u64 icssg_read_time(const void __iomem *addr)
+{
+ u32 low, high;
+
+ do {
+ high = readl(addr + 4);
+ low = readl(addr);
+ } while (high != readl(addr + 4));
+
+ return low + ((u64)high << 32);
+}
+
/* Classifier helpers */
void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac);
void icssg_class_set_host_mac_addr(struct regmap *miig_rt, const u8 *mac);
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
index 44488c153ea2..4fbe4b7cd12a 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c
@@ -2566,7 +2566,6 @@ static void gelic_wl_setup_netdev_ops(struct net_device *netdev)
netdev->ethtool_ops = &gelic_wl_ethtool_ops;
netdev->netdev_ops = &gelic_wl_netdevice_ops;
- netdev->wireless_data = &wl->wireless_data;
netdev->wireless_handlers = &gelic_wl_wext_handler_def;
}
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
index 1f203d1ae8db..dbabf538e10a 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h
@@ -276,7 +276,6 @@ struct gelic_wl_info {
u8 active_bssid[ETH_ALEN]; /* associated bssid */
unsigned int essid_len;
- struct iw_public_data wireless_data;
struct iw_statistics iwstat;
};
diff --git a/drivers/net/ethernet/vertexcom/mse102x.c b/drivers/net/ethernet/vertexcom/mse102x.c
index a04d4073def9..89dc4c401a8d 100644
--- a/drivers/net/ethernet/vertexcom/mse102x.c
+++ b/drivers/net/ethernet/vertexcom/mse102x.c
@@ -222,7 +222,7 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
struct mse102x_net_spi *mses = to_mse102x_spi(mse);
struct spi_transfer *xfer = &mses->spi_xfer;
struct spi_message *msg = &mses->spi_msg;
- struct sk_buff *tskb;
+ struct sk_buff *tskb = NULL;
int ret;
netif_dbg(mse, tx_queued, mse->ndev, "%s: skb %p, %d@%p\n",
@@ -235,7 +235,6 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
if (!tskb)
return -ENOMEM;
- dev_kfree_skb(txp);
txp = tskb;
}
@@ -257,6 +256,8 @@ static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
mse->stats.xfer_err++;
}
+ dev_kfree_skb(tskb);
+
return ret;
}
@@ -436,13 +437,15 @@ static void mse102x_tx_work(struct work_struct *work)
mse = &mses->mse102x;
while ((txb = skb_dequeue(&mse->txq))) {
+ unsigned int len = max_t(unsigned int, txb->len, ETH_ZLEN);
+
mutex_lock(&mses->lock);
ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
mutex_unlock(&mses->lock);
if (ret) {
mse->ndev->stats.tx_dropped++;
} else {
- mse->ndev->stats.tx_bytes += txb->len;
+ mse->ndev->stats.tx_bytes += len;
mse->ndev->stats.tx_packets++;
}
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 273ec5f70005..0f4b02fe6f85 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -924,13 +924,13 @@ axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)
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);
+ dmaengine_submit(dma_tx_desc);
+ dma_async_issue_pending(lp->tx_chan);
return NETDEV_TX_OK;
xmit_error_unmap_sg:
diff --git a/drivers/net/fjes/fjes_ethtool.c b/drivers/net/fjes/fjes_ethtool.c
index 19c99529566b..70c53f33d857 100644
--- a/drivers/net/fjes/fjes_ethtool.c
+++ b/drivers/net/fjes/fjes_ethtool.c
@@ -87,49 +87,31 @@ static void fjes_get_strings(struct net_device *netdev,
{
struct fjes_adapter *adapter = netdev_priv(netdev);
struct fjes_hw *hw = &adapter->hw;
- u8 *p = data;
int i;
- switch (stringset) {
- case ETH_SS_STATS:
- for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) {
- memcpy(p, fjes_gstrings_stats[i].stat_string,
- ETH_GSTRING_LEN);
- p += ETH_GSTRING_LEN;
- }
- for (i = 0; i < hw->max_epid; i++) {
- if (i == hw->my_epid)
- continue;
- sprintf(p, "ep%u_com_regist_buf_exec", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_com_unregist_buf_exec", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_send_intr_rx", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_send_intr_unshare", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_send_intr_zoneupdate", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_recv_intr_rx", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_recv_intr_unshare", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_recv_intr_stop", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_recv_intr_zoneupdate", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_tx_buffer_full", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_tx_dropped_not_shared", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_tx_dropped_ver_mismatch", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_tx_dropped_buf_size_mismatch", i);
- p += ETH_GSTRING_LEN;
- sprintf(p, "ep%u_tx_dropped_vlanid_mismatch", i);
- p += ETH_GSTRING_LEN;
- }
- break;
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++)
+ ethtool_puts(&data, fjes_gstrings_stats[i].stat_string);
+
+ for (i = 0; i < hw->max_epid; i++) {
+ if (i == hw->my_epid)
+ continue;
+ ethtool_sprintf(&data, "ep%u_com_regist_buf_exec", i);
+ ethtool_sprintf(&data, "ep%u_com_unregist_buf_exec", i);
+ ethtool_sprintf(&data, "ep%u_send_intr_rx", i);
+ ethtool_sprintf(&data, "ep%u_send_intr_unshare", i);
+ ethtool_sprintf(&data, "ep%u_send_intr_zoneupdate", i);
+ ethtool_sprintf(&data, "ep%u_recv_intr_rx", i);
+ ethtool_sprintf(&data, "ep%u_recv_intr_unshare", i);
+ ethtool_sprintf(&data, "ep%u_recv_intr_stop", i);
+ ethtool_sprintf(&data, "ep%u_recv_intr_zoneupdate", i);
+ ethtool_sprintf(&data, "ep%u_tx_buffer_full", i);
+ ethtool_sprintf(&data, "ep%u_tx_dropped_not_shared", i);
+ ethtool_sprintf(&data, "ep%u_tx_dropped_ver_mismatch", i);
+ ethtool_sprintf(&data, "ep%u_tx_dropped_buf_size_mismatch", i);
+ ethtool_sprintf(&data, "ep%u_tx_dropped_vlanid_mismatch", i);
}
}
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index a60bfb1abb7f..89a996ad8cd0 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1491,10 +1491,8 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev,
}
gtp->role = role;
- if (!data[IFLA_GTP_RESTART_COUNT])
- gtp->restart_count = 0;
- else
- gtp->restart_count = nla_get_u8(data[IFLA_GTP_RESTART_COUNT]);
+ gtp->restart_count = nla_get_u8_default(data[IFLA_GTP_RESTART_COUNT],
+ 0);
gtp->net = src_net;
@@ -1702,20 +1700,24 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
return -EINVAL;
if (data[IFLA_GTP_FD0]) {
- u32 fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
+ int fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
- sk0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp);
- if (IS_ERR(sk0))
- return PTR_ERR(sk0);
+ if (fd0 >= 0) {
+ sk0 = gtp_encap_enable_socket(fd0, UDP_ENCAP_GTP0, gtp);
+ if (IS_ERR(sk0))
+ return PTR_ERR(sk0);
+ }
}
if (data[IFLA_GTP_FD1]) {
- u32 fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
+ int fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
- sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp);
- if (IS_ERR(sk1u)) {
- gtp_encap_disable_sock(sk0);
- return PTR_ERR(sk1u);
+ if (fd1 >= 0) {
+ sk1u = gtp_encap_enable_socket(fd1, UDP_ENCAP_GTP1U, gtp);
+ if (IS_ERR(sk1u)) {
+ gtp_encap_disable_sock(sk0);
+ return PTR_ERR(sk1u);
+ }
}
}
@@ -1825,10 +1827,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk,
version = nla_get_u32(info->attrs[GTPA_VERSION]);
- if (info->attrs[GTPA_FAMILY])
- family = nla_get_u8(info->attrs[GTPA_FAMILY]);
- else
- family = AF_INET;
+ family = nla_get_u8_default(info->attrs[GTPA_FAMILY], AF_INET);
#if !IS_ENABLED(CONFIG_IPV6)
if (family == AF_INET6)
@@ -2065,10 +2064,7 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net,
struct gtp_dev *gtp;
int family;
- if (nla[GTPA_FAMILY])
- family = nla_get_u8(nla[GTPA_FAMILY]);
- else
- family = AF_INET;
+ family = nla_get_u8_default(nla[GTPA_FAMILY], AF_INET);
gtp = gtp_find_dev(net, nla);
if (!gtp)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 2c1b5def4a0b..67424888ff0a 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -426,22 +426,21 @@ static int __init ifb_init_module(void)
{
int i, err;
- down_write(&pernet_ops_rwsem);
- rtnl_lock();
- err = __rtnl_link_register(&ifb_link_ops);
+ err = rtnl_link_register(&ifb_link_ops);
if (err < 0)
- goto out;
+ return err;
+
+ rtnl_net_lock(&init_net);
for (i = 0; i < numifbs && !err; i++) {
err = ifb_init_one(i);
cond_resched();
}
- if (err)
- __rtnl_link_unregister(&ifb_link_ops);
-out:
- rtnl_unlock();
- up_write(&pernet_ops_rwsem);
+ rtnl_net_unlock(&init_net);
+
+ if (err)
+ rtnl_link_unregister(&ifb_link_ops);
return err;
}
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index b1afcb8740de..fd591ddb3884 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -3,6 +3,7 @@
*/
#include <net/inet_dscp.h>
+#include <net/ip.h>
#include "ipvlan.h"
@@ -422,7 +423,7 @@ static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb)
int err, ret = NET_XMIT_DROP;
struct flowi4 fl4 = {
.flowi4_oif = dev->ifindex,
- .flowi4_tos = ip4h->tos & INET_DSCP_MASK,
+ .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h)),
.flowi4_flags = FLOWI_FLAG_ANYSRC,
.flowi4_mark = skb->mark,
.daddr = ip4h->daddr,
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 26034f80d4a4..1bc1e5993f56 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -2621,6 +2621,17 @@ static void macsec_set_head_tail_room(struct net_device *dev)
dev->needed_tailroom = real_dev->needed_tailroom + needed_tailroom;
}
+static void macsec_inherit_tso_max(struct net_device *dev)
+{
+ struct macsec_dev *macsec = macsec_priv(dev);
+
+ /* if macsec is offloaded, we need to follow the lower
+ * device's capabilities. otherwise, we can ignore them.
+ */
+ if (macsec_is_offloaded(macsec))
+ netif_inherit_tso_max(dev, macsec->real_dev);
+}
+
static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
{
enum macsec_offload prev_offload;
@@ -2666,6 +2677,10 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
macsec_set_head_tail_room(dev);
macsec->insert_tx_tag = macsec_needs_tx_tag(macsec, ops);
+ macsec_inherit_tso_max(dev);
+
+ netdev_update_features(dev);
+
return ret;
}
@@ -3521,6 +3536,10 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
#define MACSEC_FEATURES \
(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
+#define MACSEC_OFFLOAD_FEATURES \
+ (MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \
+ NETIF_F_LRO | NETIF_F_RXHASH | NETIF_F_CSUM_MASK | NETIF_F_RXCSUM)
+
static int macsec_dev_init(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
@@ -3531,7 +3550,12 @@ static int macsec_dev_init(struct net_device *dev)
if (err)
return err;
- dev->features = real_dev->features & MACSEC_FEATURES;
+ macsec_inherit_tso_max(dev);
+
+ dev->hw_features = real_dev->hw_features & MACSEC_OFFLOAD_FEATURES;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+
+ dev->features = real_dev->features & MACSEC_OFFLOAD_FEATURES;
dev->features |= NETIF_F_GSO_SOFTWARE;
dev->lltx = true;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
@@ -3561,8 +3585,12 @@ static netdev_features_t macsec_fix_features(struct net_device *dev,
{
struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->real_dev;
+ netdev_features_t mask;
+
+ mask = macsec_is_offloaded(macsec) ? MACSEC_OFFLOAD_FEATURES
+ : MACSEC_FEATURES;
- features &= (real_dev->features & MACSEC_FEATURES) |
+ features &= (real_dev->features & mask) |
NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES;
return features;
@@ -3798,8 +3826,7 @@ static void macsec_free_netdev(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
- if (macsec->secy.tx_sc.md_dst)
- metadata_dst_free(macsec->secy.tx_sc.md_dst);
+ dst_release(&macsec->secy.tx_sc.md_dst->dst);
free_percpu(macsec->stats);
free_percpu(macsec->secy.tx_sc.stats);
@@ -4300,9 +4327,9 @@ static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[],
}
}
- es = data[IFLA_MACSEC_ES] ? nla_get_u8(data[IFLA_MACSEC_ES]) : false;
- sci = data[IFLA_MACSEC_INC_SCI] ? nla_get_u8(data[IFLA_MACSEC_INC_SCI]) : false;
- scb = data[IFLA_MACSEC_SCB] ? nla_get_u8(data[IFLA_MACSEC_SCB]) : false;
+ es = nla_get_u8_default(data[IFLA_MACSEC_ES], false);
+ sci = nla_get_u8_default(data[IFLA_MACSEC_INC_SCI], false);
+ scb = nla_get_u8_default(data[IFLA_MACSEC_SCB], false);
if ((sci && (scb || es)) || (scb && es))
return -EINVAL;
@@ -4429,31 +4456,26 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *real_dev = netdev_notifier_info_to_dev(ptr);
+ struct macsec_rxh_data *rxd;
+ struct macsec_dev *m, *n;
LIST_HEAD(head);
if (!is_macsec_master(real_dev))
return NOTIFY_DONE;
+ rxd = macsec_data_rtnl(real_dev);
+
switch (event) {
case NETDEV_DOWN:
case NETDEV_UP:
- case NETDEV_CHANGE: {
- struct macsec_dev *m, *n;
- struct macsec_rxh_data *rxd;
-
- rxd = macsec_data_rtnl(real_dev);
+ case NETDEV_CHANGE:
list_for_each_entry_safe(m, n, &rxd->secys, secys) {
struct net_device *dev = m->secy.netdev;
netif_stacked_transfer_operstate(real_dev, dev);
}
break;
- }
- case NETDEV_UNREGISTER: {
- struct macsec_dev *m, *n;
- struct macsec_rxh_data *rxd;
-
- rxd = macsec_data_rtnl(real_dev);
+ case NETDEV_UNREGISTER:
list_for_each_entry_safe(m, n, &rxd->secys, secys) {
macsec_common_dellink(m->secy.netdev, &head);
}
@@ -4463,12 +4485,7 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
unregister_netdevice_many(&head);
break;
- }
- case NETDEV_CHANGEMTU: {
- struct macsec_dev *m;
- struct macsec_rxh_data *rxd;
-
- rxd = macsec_data_rtnl(real_dev);
+ case NETDEV_CHANGEMTU:
list_for_each_entry(m, &rxd->secys, secys) {
struct net_device *dev = m->secy.netdev;
unsigned int mtu = real_dev->mtu - (m->secy.icv_len +
@@ -4477,7 +4494,13 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
if (dev->mtu > mtu)
dev_set_mtu(dev, mtu);
}
- }
+ break;
+ case NETDEV_FEAT_CHANGE:
+ list_for_each_entry(m, &rxd->secys, secys) {
+ macsec_inherit_tso_max(m->secy.netdev);
+ netdev_update_features(m->secy.netdev);
+ }
+ break;
}
return NOTIFY_OK;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index edbd5afcec41..fed4fe2a4748 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1024,7 +1024,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
- u16 flags,
+ u16 flags, bool *notified,
struct netlink_ext_ack *extack)
{
struct macvlan_dev *vlan = netdev_priv(dev);
@@ -1049,7 +1049,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
- const unsigned char *addr, u16 vid,
+ const unsigned char *addr, u16 vid, bool *notified,
struct netlink_ext_ack *extack)
{
struct macvlan_dev *vlan = netdev_priv(dev);
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
index 4dc057c121f5..d2b3f5a59141 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
@@ -588,6 +588,9 @@ static int mctp_i2c_header_create(struct sk_buff *skb, struct net_device *dev,
if (len > MCTP_I2C_MAXMTU)
return -EMSGSIZE;
+ if (!daddr || !saddr)
+ return -EINVAL;
+
lldst = *((u8 *)daddr);
llsrc = *((u8 *)saddr);
@@ -877,7 +880,8 @@ static int mctp_i2c_add_netdev(struct mctp_i2c_client *mcli,
goto err;
}
- rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops);
+ rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops,
+ MCTP_PHYS_BINDING_SMBUS);
if (rc < 0) {
dev_err(&mcli->client->dev,
"register netdev \"%s\" failed %d\n",
diff --git a/drivers/net/mctp/mctp-i3c.c b/drivers/net/mctp/mctp-i3c.c
index 1bc87a062686..9adad59b8676 100644
--- a/drivers/net/mctp/mctp-i3c.c
+++ b/drivers/net/mctp/mctp-i3c.c
@@ -607,7 +607,7 @@ __must_hold(&busdevs_lock)
goto err_free_uninit;
}
- rc = mctp_register_netdev(ndev, NULL);
+ rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_I3C);
if (rc < 0) {
dev_warn(&ndev->dev, "netdev register failed: %d\n", rc);
goto err_free_netdev;
diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c
index e63720ec3238..26c9a33fd636 100644
--- a/drivers/net/mctp/mctp-serial.c
+++ b/drivers/net/mctp/mctp-serial.c
@@ -23,6 +23,7 @@
#include <linux/mctp.h>
#include <net/mctp.h>
+#include <net/mctpdevice.h>
#include <net/pkt_sched.h>
#define MCTP_SERIAL_MTU 68 /* base mtu (64) + mctp header */
@@ -470,7 +471,7 @@ static int mctp_serial_open(struct tty_struct *tty)
spin_lock_init(&dev->lock);
INIT_WORK(&dev->tx_work, mctp_serial_tx_work);
- rc = register_netdev(ndev);
+ rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_SERIAL);
if (rc)
goto free_netdev;
@@ -492,7 +493,7 @@ static void mctp_serial_close(struct tty_struct *tty)
struct mctp_serial *dev = tty->disc_data;
int idx = dev->idx;
- unregister_netdev(dev->netdev);
+ mctp_unregister_netdev(dev->netdev);
ida_free(&mctp_serial_ida, idx);
}
diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c
index e08c90ac0c6e..f67a4d4005e7 100644
--- a/drivers/net/mdio.c
+++ b/drivers/net/mdio.c
@@ -167,178 +167,6 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
}
/**
- * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET
- * @mdio: MDIO interface
- * @ecmd: Ethtool request structure
- * @npage_adv: Modes currently advertised on next pages
- * @npage_lpa: Modes advertised by link partner on next pages
- *
- * The @ecmd parameter is expected to have been cleared before calling
- * mdio45_ethtool_gset_npage().
- *
- * Since the CSRs for auto-negotiation using next pages are not fully
- * standardised, this function does not attempt to decode them. The
- * caller must pass them in.
- */
-void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
- struct ethtool_cmd *ecmd,
- u32 npage_adv, u32 npage_lpa)
-{
- int reg;
- u32 speed;
-
- BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22);
- BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45);
-
- ecmd->transceiver = XCVR_INTERNAL;
- ecmd->phy_address = mdio->prtad;
- ecmd->mdio_support =
- mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22);
-
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_CTRL2);
- switch (reg & MDIO_PMA_CTRL2_TYPE) {
- case MDIO_PMA_CTRL2_10GBT:
- case MDIO_PMA_CTRL2_1000BT:
- case MDIO_PMA_CTRL2_100BTX:
- case MDIO_PMA_CTRL2_10BT:
- ecmd->port = PORT_TP;
- ecmd->supported = SUPPORTED_TP;
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_SPEED);
- if (reg & MDIO_SPEED_10G)
- ecmd->supported |= SUPPORTED_10000baseT_Full;
- if (reg & MDIO_PMA_SPEED_1000)
- ecmd->supported |= (SUPPORTED_1000baseT_Full |
- SUPPORTED_1000baseT_Half);
- if (reg & MDIO_PMA_SPEED_100)
- ecmd->supported |= (SUPPORTED_100baseT_Full |
- SUPPORTED_100baseT_Half);
- if (reg & MDIO_PMA_SPEED_10)
- ecmd->supported |= (SUPPORTED_10baseT_Full |
- SUPPORTED_10baseT_Half);
- ecmd->advertising = ADVERTISED_TP;
- break;
-
- case MDIO_PMA_CTRL2_10GBCX4:
- ecmd->port = PORT_OTHER;
- ecmd->supported = 0;
- ecmd->advertising = 0;
- break;
-
- case MDIO_PMA_CTRL2_10GBKX4:
- case MDIO_PMA_CTRL2_10GBKR:
- case MDIO_PMA_CTRL2_1000BKX:
- ecmd->port = PORT_OTHER;
- ecmd->supported = SUPPORTED_Backplane;
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_PMA_EXTABLE);
- if (reg & MDIO_PMA_EXTABLE_10GBKX4)
- ecmd->supported |= SUPPORTED_10000baseKX4_Full;
- if (reg & MDIO_PMA_EXTABLE_10GBKR)
- ecmd->supported |= SUPPORTED_10000baseKR_Full;
- if (reg & MDIO_PMA_EXTABLE_1000BKX)
- ecmd->supported |= SUPPORTED_1000baseKX_Full;
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_PMA_10GBR_FECABLE);
- if (reg & MDIO_PMA_10GBR_FECABLE_ABLE)
- ecmd->supported |= SUPPORTED_10000baseR_FEC;
- ecmd->advertising = ADVERTISED_Backplane;
- break;
-
- /* All the other defined modes are flavours of optical */
- default:
- ecmd->port = PORT_FIBRE;
- ecmd->supported = SUPPORTED_FIBRE;
- ecmd->advertising = ADVERTISED_FIBRE;
- break;
- }
-
- if (mdio->mmds & MDIO_DEVS_AN) {
- ecmd->supported |= SUPPORTED_Autoneg;
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
- MDIO_CTRL1);
- if (reg & MDIO_AN_CTRL1_ENABLE) {
- ecmd->autoneg = AUTONEG_ENABLE;
- ecmd->advertising |=
- ADVERTISED_Autoneg |
- mdio45_get_an(mdio, MDIO_AN_ADVERTISE) |
- npage_adv;
- } else {
- ecmd->autoneg = AUTONEG_DISABLE;
- }
- } else {
- ecmd->autoneg = AUTONEG_DISABLE;
- }
-
- if (ecmd->autoneg) {
- u32 modes = 0;
- int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad,
- MDIO_MMD_AN, MDIO_STAT1);
-
- /* If AN is complete and successful, report best common
- * mode, otherwise report best advertised mode. */
- if (an_stat & MDIO_AN_STAT1_COMPLETE) {
- ecmd->lp_advertising =
- mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa;
- if (an_stat & MDIO_AN_STAT1_LPABLE)
- ecmd->lp_advertising |= ADVERTISED_Autoneg;
- modes = ecmd->advertising & ecmd->lp_advertising;
- }
- if ((modes & ~ADVERTISED_Autoneg) == 0)
- modes = ecmd->advertising;
-
- if (modes & (ADVERTISED_10000baseT_Full |
- ADVERTISED_10000baseKX4_Full |
- ADVERTISED_10000baseKR_Full)) {
- speed = SPEED_10000;
- ecmd->duplex = DUPLEX_FULL;
- } else if (modes & (ADVERTISED_1000baseT_Full |
- ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseKX_Full)) {
- speed = SPEED_1000;
- ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half);
- } else if (modes & (ADVERTISED_100baseT_Full |
- ADVERTISED_100baseT_Half)) {
- speed = SPEED_100;
- ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
- } else {
- speed = SPEED_10;
- ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
- }
- } else {
- /* Report forced settings */
- reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_CTRL1);
- speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1)
- * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
- ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX ||
- speed == SPEED_10000);
- }
-
- ethtool_cmd_speed_set(ecmd, speed);
-
- /* 10GBASE-T MDI/MDI-X */
- if (ecmd->port == PORT_TP
- && (ethtool_cmd_speed(ecmd) == SPEED_10000)) {
- switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
- MDIO_PMA_10GBT_SWAPPOL)) {
- case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
- ecmd->eth_tp_mdix = ETH_TP_MDI;
- break;
- case 0:
- ecmd->eth_tp_mdix = ETH_TP_MDI_X;
- break;
- default:
- /* It's complicated... */
- ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
- break;
- }
- }
-}
-EXPORT_SYMBOL(mdio45_ethtool_gset_npage);
-
-/**
* mdio45_ethtool_ksettings_get_npage - get settings for ETHTOOL_GLINKSETTINGS
* @mdio: MDIO interface
* @cmd: Ethtool request structure
diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c
index 41e80f78b316..16c382c42227 100644
--- a/drivers/net/netdevsim/fib.c
+++ b/drivers/net/netdevsim/fib.c
@@ -1377,10 +1377,12 @@ static ssize_t nsim_nexthop_bucket_activity_write(struct file *file,
if (pos != 0)
return -EINVAL;
- if (size > sizeof(buf))
+ if (size > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, user_buf, size))
return -EFAULT;
+ buf[size] = 0;
+
if (sscanf(buf, "%u %hu", &nhid, &bucket_index) != 2)
return -EINVAL;
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index cad85bb0cf54..0be47fed4efc 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -663,7 +663,11 @@ static void nsim_setup(struct net_device *dev)
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_TSO;
- dev->hw_features |= NETIF_F_HW_TC;
+ dev->hw_features |= NETIF_F_HW_TC |
+ NETIF_F_SG |
+ NETIF_F_FRAGLIST |
+ NETIF_F_HW_CSUM |
+ NETIF_F_TSO;
dev->max_mtu = ETH_MAX_MTU;
dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD;
}
diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c
index cd8360b9bbde..bb07725d1c72 100644
--- a/drivers/net/netkit.c
+++ b/drivers/net/netkit.c
@@ -351,12 +351,7 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev,
if (data[IFLA_NETKIT_PEER_INFO]) {
attr = data[IFLA_NETKIT_PEER_INFO];
ifmp = nla_data(attr);
- err = rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack);
- if (err < 0)
- return err;
- err = netkit_validate(peer_tb, NULL, extack);
- if (err < 0)
- return err;
+ rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack);
tbp = peer_tb;
}
if (data[IFLA_NETKIT_SCRUB])
@@ -391,9 +386,6 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev,
return -EOPNOTSUPP;
net = rtnl_link_get_net(src_net, tbp);
- if (IS_ERR(net))
- return PTR_ERR(net);
-
peer = rtnl_create_link(net, ifname, ifname_assign_type,
&netkit_link_ops, tbp, extack);
if (IS_ERR(peer)) {
@@ -978,6 +970,7 @@ static struct rtnl_link_ops netkit_link_ops = {
.fill_info = netkit_fill_info,
.policy = netkit_policy,
.validate = netkit_validate,
+ .peer_type = IFLA_NETKIT_PEER_INFO,
.maxtype = IFLA_NETKIT_MAX,
};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index ee3ea0b56d48..15828f4710a9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -266,22 +266,7 @@ config MAXLINEAR_GPHY
Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
GPY241, GPY245 PHYs.
-config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
- help
- Supports the MediaTek Gigabit Ethernet PHYs.
-
-config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
- depends on NVMEM_MTK_EFUSE
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-
- Include support for built-in Ethernet PHYs which are present in
- the MT7981 and MT7988 SoCs. These PHYs need calibration data
- present in the SoCs efuse and will dynamically calibrate VCM
- (common-mode voltage) during startup.
+source "drivers/net/phy/mediatek/Kconfig"
config MICREL_PHY
tristate "Micrel PHYs"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 90f886844381..e6145153e837 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o
obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
-obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
+obj-y += mediatek/
obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 2e1a46e121d9..a2a862bae2ed 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -801,10 +801,8 @@ static void adin_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++) {
- strscpy(&data[i * ETH_GSTRING_LEN],
- adin_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++)
+ ethtool_puts(&data, adin_hw_stats[i].string);
}
static int adin_read_mmd_stat_regs(struct phy_device *phydev,
diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c
index 38d0dd5c80a4..bb56a66d2a48 100644
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -54,6 +54,12 @@
#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0)
#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
+#define MDIO_AN_RESVD_VEND_PROV 0xc410
+#define MDIO_AN_RESVD_VEND_PROV_MDIX_AUTO 0
+#define MDIO_AN_RESVD_VEND_PROV_MDIX_MDI 1
+#define MDIO_AN_RESVD_VEND_PROV_MDIX_MDIX 2
+#define MDIO_AN_RESVD_VEND_PROV_MDIX_MASK GENMASK(1, 0)
+
#define MDIO_AN_TX_VEND_STATUS1 0xc800
#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1)
#define MDIO_AN_TX_VEND_STATUS1_10BASET 0
@@ -64,6 +70,9 @@
#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5
#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0)
+#define MDIO_AN_RESVD_VEND_STATUS1 0xc810
+#define MDIO_AN_RESVD_VEND_STATUS1_MDIX BIT(8)
+
#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00
#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1)
@@ -155,12 +164,40 @@ static void aqr107_get_stats(struct phy_device *phydev,
}
}
+static int aqr_set_mdix(struct phy_device *phydev, int mdix)
+{
+ u16 val = 0;
+
+ switch (mdix) {
+ case ETH_TP_MDI:
+ val = MDIO_AN_RESVD_VEND_PROV_MDIX_MDI;
+ break;
+ case ETH_TP_MDI_X:
+ val = MDIO_AN_RESVD_VEND_PROV_MDIX_MDIX;
+ break;
+ case ETH_TP_MDI_AUTO:
+ case ETH_TP_MDI_INVALID:
+ default:
+ val = MDIO_AN_RESVD_VEND_PROV_MDIX_AUTO;
+ break;
+ }
+
+ return phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_RESVD_VEND_PROV,
+ MDIO_AN_RESVD_VEND_PROV_MDIX_MASK, val);
+}
+
static int aqr_config_aneg(struct phy_device *phydev)
{
bool changed = false;
u16 reg;
int ret;
+ ret = aqr_set_mdix(phydev, phydev->mdix_ctrl);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+
if (phydev->autoneg == AUTONEG_DISABLE)
return genphy_c45_pma_setup_forced(phydev);
@@ -278,6 +315,21 @@ static int aqr_read_status(struct phy_device *phydev)
val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF);
}
+ val = genphy_c45_aneg_done(phydev);
+ if (val < 0)
+ return val;
+ if (val) {
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RESVD_VEND_STATUS1);
+ if (val < 0)
+ return val;
+ if (val & MDIO_AN_RESVD_VEND_STATUS1_MDIX)
+ phydev->mdix = ETH_TP_MDI_X;
+ else
+ phydev->mdix = ETH_TP_MDI;
+ } else {
+ phydev->mdix = ETH_TP_MDI_INVALID;
+ }
+
return genphy_c45_read_status(phydev);
}
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index 6c52f7dda514..5198d66dbbc0 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -523,8 +523,7 @@ void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
unsigned int i;
for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
+ ethtool_puts(&data, bcm_phy_hw_stats[i].string);
}
EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
@@ -1137,7 +1136,7 @@ int bcm_config_lre_aneg(struct phy_device *phydev, bool changed)
{
int err;
- if (genphy_config_eee_advert(phydev))
+ if (genphy_c45_an_config_eee_aneg(phydev) > 0)
changed = true;
err = bcm_setup_lre_master_slave(phydev);
diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c
index 3ab64e04a01c..cf8b6d0bfaa9 100644
--- a/drivers/net/phy/dp83822.c
+++ b/drivers/net/phy/dp83822.c
@@ -506,7 +506,7 @@ static int dp83822_config_init(struct phy_device *phydev)
return dp83822_config_wol(phydev, &dp83822->wol);
}
-static int dp83826_config_rmii_mode(struct phy_device *phydev)
+static int dp8382x_config_rmii_mode(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
const char *of_val;
@@ -544,7 +544,7 @@ static int dp83826_config_init(struct phy_device *phydev)
if (ret)
return ret;
- ret = dp83826_config_rmii_mode(phydev);
+ ret = dp8382x_config_rmii_mode(phydev);
if (ret)
return ret;
} else {
@@ -585,9 +585,14 @@ static int dp83826_config_init(struct phy_device *phydev)
return dp83822_config_wol(phydev, &dp83822->wol);
}
-static int dp8382x_config_init(struct phy_device *phydev)
+static int dp83825_config_init(struct phy_device *phydev)
{
struct dp83822_private *dp83822 = phydev->priv;
+ int ret;
+
+ ret = dp8382x_config_rmii_mode(phydev);
+ if (ret)
+ return ret;
return dp83822_config_wol(phydev, &dp83822->wol);
}
@@ -782,14 +787,14 @@ static int dp83822_resume(struct phy_device *phydev)
.resume = dp83822_resume, \
}
-#define DP83826_PHY_DRIVER(_id, _name) \
+#define DP83825_PHY_DRIVER(_id, _name) \
{ \
PHY_ID_MATCH_MODEL(_id), \
.name = (_name), \
/* PHY_BASIC_FEATURES */ \
- .probe = dp83826_probe, \
+ .probe = dp8382x_probe, \
.soft_reset = dp83822_phy_reset, \
- .config_init = dp83826_config_init, \
+ .config_init = dp83825_config_init, \
.get_wol = dp83822_get_wol, \
.set_wol = dp83822_set_wol, \
.config_intr = dp83822_config_intr, \
@@ -798,14 +803,14 @@ static int dp83822_resume(struct phy_device *phydev)
.resume = dp83822_resume, \
}
-#define DP8382X_PHY_DRIVER(_id, _name) \
+#define DP83826_PHY_DRIVER(_id, _name) \
{ \
PHY_ID_MATCH_MODEL(_id), \
.name = (_name), \
/* PHY_BASIC_FEATURES */ \
- .probe = dp8382x_probe, \
+ .probe = dp83826_probe, \
.soft_reset = dp83822_phy_reset, \
- .config_init = dp8382x_config_init, \
+ .config_init = dp83826_config_init, \
.get_wol = dp83822_get_wol, \
.set_wol = dp83822_set_wol, \
.config_intr = dp83822_config_intr, \
@@ -816,12 +821,12 @@ static int dp83822_resume(struct phy_device *phydev)
static struct phy_driver dp83822_driver[] = {
DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"),
- DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),
+ DP83825_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),
+ DP83825_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),
+ DP83825_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),
+ DP83825_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),
DP83826_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"),
DP83826_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"),
- DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),
- DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),
- DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),
};
module_phy_driver(dp83822_driver);
diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c
index 937061acfc61..351411f0aa6f 100644
--- a/drivers/net/phy/dp83848.c
+++ b/drivers/net/phy/dp83848.c
@@ -147,6 +147,8 @@ MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
/* IRQ related */ \
.config_intr = dp83848_config_intr, \
.handle_interrupt = dp83848_handle_interrupt, \
+ \
+ .flags = PHY_RST_AFTER_CLK_EN, \
}
static struct phy_driver dp83848_driver[] = {
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index a00a667454a9..ee438b71a0b4 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -540,8 +540,7 @@ static void ip101g_get_strings(struct phy_device *phydev, u8 *data)
int i;
for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++)
- strscpy(data + i * ETH_GSTRING_LEN,
- ip101g_hw_stats[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, ip101g_hw_stats[i].name);
}
static u64 ip101g_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 28aec37acd2c..cd50cd6a7f75 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2020,10 +2020,8 @@ static void marvell_get_strings(struct phy_device *phydev, u8 *data)
int count = marvell_get_sset_count(phydev);
int i;
- for (i = 0; i < count; i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
- marvell_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < count; i++)
+ ethtool_puts(&data, marvell_hw_stats[i].string);
}
static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data)
@@ -2031,10 +2029,8 @@ static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data)
int count = marvell_get_sset_count_simple(phydev);
int i;
- for (i = 0; i < count; i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
- marvell_hw_stats_simple[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < count; i++)
+ ethtool_puts(&data, marvell_hw_stats_simple[i].string);
}
static u64 marvell_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
new file mode 100644
index 000000000000..2a8ac5aed0f8
--- /dev/null
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config MTK_NET_PHYLIB
+ tristate
+
+config MEDIATEK_GE_PHY
+ tristate "MediaTek Gigabit Ethernet PHYs"
+ select MTK_NET_PHYLIB
+ help
+ Supports the MediaTek non-built-in Gigabit Ethernet PHYs.
+
+ Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531.
+ You may find mt7530 inside mt7621. This driver shares some
+ common operations with MediaTek SoC built-in Gigabit
+ Ethernet PHYs.
+
+config MEDIATEK_GE_SOC_PHY
+ tristate "MediaTek SoC Ethernet PHYs"
+ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
+ depends on NVMEM_MTK_EFUSE
+ select MTK_NET_PHYLIB
+ help
+ Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
+
+ Include support for built-in Ethernet PHYs which are present in
+ the MT7981 and MT7988 SoCs. These PHYs need calibration data
+ present in the SoCs efuse and will dynamically calibrate VCM
+ (common-mode voltage) during startup.
diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile
new file mode 100644
index 000000000000..814879d0abe5
--- /dev/null
+++ b/drivers/net/phy/mediatek/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
+obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
+obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c
index a931832b1418..38dc898eaf7b 100644
--- a/drivers/net/phy/mediatek-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -8,6 +8,8 @@
#include <linux/phy.h>
#include <linux/regmap.h>
+#include "mtk.h"
+
#define MTK_GPHY_ID_MT7981 0x03a29461
#define MTK_GPHY_ID_MT7988 0x03a29481
@@ -210,41 +212,6 @@
#define MTK_PHY_DA_TX_R50_PAIR_D 0x540
/* Registers on MDIO_MMD_VEND2 */
-#define MTK_PHY_LED0_ON_CTRL 0x24
-#define MTK_PHY_LED1_ON_CTRL 0x26
-#define MTK_PHY_LED_ON_MASK GENMASK(6, 0)
-#define MTK_PHY_LED_ON_LINK1000 BIT(0)
-#define MTK_PHY_LED_ON_LINK100 BIT(1)
-#define MTK_PHY_LED_ON_LINK10 BIT(2)
-#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\
- MTK_PHY_LED_ON_LINK100 |\
- MTK_PHY_LED_ON_LINK1000)
-#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
-#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
-#define MTK_PHY_LED_ON_POLARITY BIT(14)
-#define MTK_PHY_LED_ON_ENABLE BIT(15)
-
-#define MTK_PHY_LED0_BLINK_CTRL 0x25
-#define MTK_PHY_LED1_BLINK_CTRL 0x27
-#define MTK_PHY_LED_BLINK_1000TX BIT(0)
-#define MTK_PHY_LED_BLINK_1000RX BIT(1)
-#define MTK_PHY_LED_BLINK_100TX BIT(2)
-#define MTK_PHY_LED_BLINK_100RX BIT(3)
-#define MTK_PHY_LED_BLINK_10TX BIT(4)
-#define MTK_PHY_LED_BLINK_10RX BIT(5)
-#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\
- MTK_PHY_LED_BLINK_100RX |\
- MTK_PHY_LED_BLINK_1000RX)
-#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\
- MTK_PHY_LED_BLINK_100TX |\
- MTK_PHY_LED_BLINK_1000TX)
-#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
-#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-
#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1)
#define MTK_PHY_RG_BG_RASEL 0x115
@@ -299,29 +266,11 @@ enum CAL_MODE {
SW_M
};
-#define MTK_PHY_LED_STATE_FORCE_ON 0
-#define MTK_PHY_LED_STATE_FORCE_BLINK 1
-#define MTK_PHY_LED_STATE_NETDEV 2
-
-struct mtk_socphy_priv {
- unsigned long led_state;
-};
-
struct mtk_socphy_shared {
u32 boottrap;
struct mtk_socphy_priv priv[4];
};
-static int mtk_socphy_read_page(struct phy_device *phydev)
-{
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-}
-
-static int mtk_socphy_write_page(struct phy_device *phydev, int page)
-{
- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-}
-
/* One calibration cycle consists of:
* 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
* until AD_CAL_COMP is ready to output calibration result.
@@ -1172,76 +1121,23 @@ static int mt798x_phy_config_init(struct phy_device *phydev)
return mt798x_phy_calibration(phydev);
}
-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
- bool on)
-{
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
- if (on)
- changed = !test_and_set_bit(bit_on, &priv->led_state);
- else
- changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-
- changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_ON_CTRL :
- MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_MASK,
- on ? MTK_PHY_LED_ON_FORCE_ON : 0);
- else
- return 0;
-}
-
-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
- bool blinking)
-{
- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
- (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- bool changed;
-
- if (blinking)
- changed = !test_and_set_bit(bit_blink, &priv->led_state);
- else
- changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-
- changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
- (index ? 16 : 0), &priv->led_state);
- if (changed)
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_BLINK_CTRL :
- MTK_PHY_LED0_BLINK_CTRL,
- blinking ?
- MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
- else
- return 0;
-}
-
static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off)
{
bool blinking = false;
- int err = 0;
-
- if (index > 1)
- return -EINVAL;
+ int err;
- if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
- blinking = true;
- *delay_on = 50;
- *delay_off = 50;
- }
+ err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+ if (err < 0)
+ return err;
- err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+ err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
if (err)
return err;
- return mt798x_phy_hw_led_on_set(phydev, index, false);
+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+ false);
}
static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
@@ -1249,11 +1145,12 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
{
int err;
- err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+ err = mtk_phy_hw_led_blink_set(phydev, index, false);
if (err)
return err;
- return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+ return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+ (value != LED_OFF));
}
static const unsigned long supported_triggers =
@@ -1269,155 +1166,26 @@ static const unsigned long supported_triggers =
static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- if (index > 1)
- return -EINVAL;
-
- /* All combinations of the supported triggers are allowed */
- if (rules & ~supported_triggers)
- return -EOPNOTSUPP;
-
- return 0;
-};
+ return mtk_phy_led_hw_is_supported(phydev, index, rules,
+ supported_triggers);
+}
static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
unsigned long *rules)
{
- unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
- (index ? 16 : 0);
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
- unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- int on, blink;
-
- if (index > 1)
- return -EINVAL;
-
- on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-
- if (on < 0)
- return -EIO;
-
- blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
- index ? MTK_PHY_LED1_BLINK_CTRL :
- MTK_PHY_LED0_BLINK_CTRL);
- if (blink < 0)
- return -EIO;
-
- if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
- MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
- (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
- set_bit(bit_netdev, &priv->led_state);
- else
- clear_bit(bit_netdev, &priv->led_state);
-
- if (on & MTK_PHY_LED_ON_FORCE_ON)
- set_bit(bit_on, &priv->led_state);
- else
- clear_bit(bit_on, &priv->led_state);
-
- if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
- set_bit(bit_blink, &priv->led_state);
- else
- clear_bit(bit_blink, &priv->led_state);
-
- if (!rules)
- return 0;
-
- if (on & MTK_PHY_LED_ON_LINK)
- *rules |= BIT(TRIGGER_NETDEV_LINK);
-
- if (on & MTK_PHY_LED_ON_LINK10)
- *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-
- if (on & MTK_PHY_LED_ON_LINK100)
- *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-
- if (on & MTK_PHY_LED_ON_LINK1000)
- *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-
- if (on & MTK_PHY_LED_ON_FDX)
- *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-
- if (on & MTK_PHY_LED_ON_HDX)
- *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-
- if (blink & MTK_PHY_LED_BLINK_RX)
- *rules |= BIT(TRIGGER_NETDEV_RX);
-
- if (blink & MTK_PHY_LED_BLINK_TX)
- *rules |= BIT(TRIGGER_NETDEV_TX);
-
- return 0;
+ return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
};
static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
unsigned long rules)
{
- unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
- struct mtk_socphy_priv *priv = phydev->priv;
- u16 on = 0, blink = 0;
- int ret;
-
- if (index > 1)
- return -EINVAL;
-
- if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
- on |= MTK_PHY_LED_ON_FDX;
-
- if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
- on |= MTK_PHY_LED_ON_HDX;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK10;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK100;
-
- if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
- on |= MTK_PHY_LED_ON_LINK1000;
-
- if (rules & BIT(TRIGGER_NETDEV_RX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
- (((on & MTK_PHY_LED_ON_LINK10) ?
- MTK_PHY_LED_BLINK_10RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ?
- MTK_PHY_LED_BLINK_100RX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ?
- MTK_PHY_LED_BLINK_1000RX : 0)) :
- MTK_PHY_LED_BLINK_RX;
- }
-
- if (rules & BIT(TRIGGER_NETDEV_TX)) {
- blink |= (on & MTK_PHY_LED_ON_LINK) ?
- (((on & MTK_PHY_LED_ON_LINK10) ?
- MTK_PHY_LED_BLINK_10TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK100) ?
- MTK_PHY_LED_BLINK_100TX : 0) |
- ((on & MTK_PHY_LED_ON_LINK1000) ?
- MTK_PHY_LED_BLINK_1000TX : 0)) :
- MTK_PHY_LED_BLINK_TX;
- }
-
- if (blink || on)
- set_bit(bit_netdev, &priv->led_state);
- else
- clear_bit(bit_netdev, &priv->led_state);
-
- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_ON_CTRL :
- MTK_PHY_LED0_ON_CTRL,
- MTK_PHY_LED_ON_FDX |
- MTK_PHY_LED_ON_HDX |
- MTK_PHY_LED_ON_LINK,
- on);
-
- if (ret)
- return ret;
-
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
- MTK_PHY_LED1_BLINK_CTRL :
- MTK_PHY_LED0_BLINK_CTRL, blink);
+ return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
+ MTK_GPHY_LED_ON_SET,
+ MTK_GPHY_LED_RX_BLINK_SET,
+ MTK_GPHY_LED_TX_BLINK_SET);
};
static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
@@ -1492,14 +1260,6 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev)
return 0;
}
-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
-{
- int i;
-
- for (i = 0; i < 2; ++i)
- mt798x_phy_led_hw_control_get(phydev, i, NULL);
-}
-
static int mt7988_phy_probe(struct phy_device *phydev)
{
struct mtk_socphy_shared *shared;
@@ -1525,7 +1285,7 @@ static int mt7988_phy_probe(struct phy_device *phydev)
phydev->priv = priv;
- mt798x_phy_leds_state_init(phydev);
+ mtk_phy_leds_state_init(phydev);
err = mt7988_phy_fix_leds_polarities(phydev);
if (err)
@@ -1552,7 +1312,7 @@ static int mt7981_phy_probe(struct phy_device *phydev)
phydev->priv = priv;
- mt798x_phy_leds_state_init(phydev);
+ mtk_phy_leds_state_init(phydev);
return mt798x_phy_calibration(phydev);
}
@@ -1567,8 +1327,8 @@ static struct phy_driver mtk_socphy_driver[] = {
.probe = mt7981_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_socphy_read_page,
- .write_page = mtk_socphy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
.led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
@@ -1584,8 +1344,8 @@ static struct phy_driver mtk_socphy_driver[] = {
.probe = mt7988_phy_probe,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_socphy_read_page,
- .write_page = mtk_socphy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
.led_blink_set = mt798x_phy_led_blink_set,
.led_brightness_set = mt798x_phy_led_brightness_set,
.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek/mtk-ge.c
index 54ea64a37ab3..ed2617bc20f4 100644
--- a/drivers/net/phy/mediatek-ge.c
+++ b/drivers/net/phy/mediatek/mtk-ge.c
@@ -3,6 +3,11 @@
#include <linux/module.h>
#include <linux/phy.h>
+#include "mtk.h"
+
+#define MTK_GPHY_ID_MT7530 0x03a29412
+#define MTK_GPHY_ID_MT7531 0x03a29441
+
#define MTK_EXT_PAGE_ACCESS 0x1f
#define MTK_PHY_PAGE_STANDARD 0x0000
#define MTK_PHY_PAGE_EXTENDED 0x0001
@@ -11,16 +16,6 @@
#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30
#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5
-static int mtk_gephy_read_page(struct phy_device *phydev)
-{
- return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
-}
-
-static int mtk_gephy_write_page(struct phy_device *phydev, int page)
-{
- return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
-}
-
static void mtk_gephy_config_init(struct phy_device *phydev)
{
/* Enable HW auto downshift */
@@ -67,7 +62,7 @@ static int mt7531_phy_config_init(struct phy_device *phydev)
static struct phy_driver mtk_gephy_driver[] = {
{
- PHY_ID_MATCH_EXACT(0x03a29412),
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530),
.name = "MediaTek MT7530 PHY",
.config_init = mt7530_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
@@ -77,11 +72,11 @@ static struct phy_driver mtk_gephy_driver[] = {
.handle_interrupt = genphy_handle_interrupt_no_ack,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_gephy_read_page,
- .write_page = mtk_gephy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
{
- PHY_ID_MATCH_EXACT(0x03a29441),
+ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531),
.name = "MediaTek MT7531 PHY",
.config_init = mt7531_phy_config_init,
/* Interrupts are handled by the switch, not the PHY
@@ -91,16 +86,16 @@ static struct phy_driver mtk_gephy_driver[] = {
.handle_interrupt = genphy_handle_interrupt_no_ack,
.suspend = genphy_suspend,
.resume = genphy_resume,
- .read_page = mtk_gephy_read_page,
- .write_page = mtk_gephy_write_page,
+ .read_page = mtk_phy_read_page,
+ .write_page = mtk_phy_write_page,
},
};
module_phy_driver(mtk_gephy_driver);
static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
- { PHY_ID_MATCH_EXACT(0x03a29441) },
- { PHY_ID_MATCH_EXACT(0x03a29412) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) },
+ { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) },
{ }
};
diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c
new file mode 100644
index 000000000000..98a09d670e9c
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+
+#include "mtk.h"
+
+int mtk_phy_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_read_page);
+
+int mtk_phy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_write_page);
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers)
+{
+ if (index > 1)
+ return -EINVAL;
+
+ /* All combinations of the supported triggers are allowed */
+ if (rules & ~supported_triggers)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
+
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules, u16 on_set,
+ u16 rx_blink_set, u16 tx_blink_set)
+{
+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+ (index ? 16 : 0);
+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+ int on, blink;
+
+ if (index > 1)
+ return -EINVAL;
+
+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+
+ if (on < 0)
+ return -EIO;
+
+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ index ? MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL);
+ if (blink < 0)
+ return -EIO;
+
+ if ((on & (on_set | MTK_PHY_LED_ON_FDX |
+ MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+ (blink & (rx_blink_set | tx_blink_set)))
+ set_bit(bit_netdev, &priv->led_state);
+ else
+ clear_bit(bit_netdev, &priv->led_state);
+
+ if (on & MTK_PHY_LED_ON_FORCE_ON)
+ set_bit(bit_on, &priv->led_state);
+ else
+ clear_bit(bit_on, &priv->led_state);
+
+ if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+ set_bit(bit_blink, &priv->led_state);
+ else
+ clear_bit(bit_blink, &priv->led_state);
+
+ if (!rules)
+ return 0;
+
+ if (on & on_set)
+ *rules |= BIT(TRIGGER_NETDEV_LINK);
+
+ if (on & MTK_PHY_LED_ON_LINK10)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+
+ if (on & MTK_PHY_LED_ON_LINK100)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+
+ if (on & MTK_PHY_LED_ON_FDX)
+ *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+
+ if (on & MTK_PHY_LED_ON_HDX)
+ *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+
+ if (blink & rx_blink_set)
+ *rules |= BIT(TRIGGER_NETDEV_RX);
+
+ if (blink & tx_blink_set)
+ *rules |= BIT(TRIGGER_NETDEV_TX);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
+
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+ unsigned long rules, u16 on_set,
+ u16 rx_blink_set, u16 tx_blink_set)
+{
+ unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+ u16 on = 0, blink = 0;
+ int ret;
+
+ if (index > 1)
+ return -EINVAL;
+
+ if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+ on |= MTK_PHY_LED_ON_FDX;
+
+ if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+ on |= MTK_PHY_LED_ON_HDX;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK10;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK100;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK1000;
+
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
+ on |= MTK_PHY_LED_ON_LINK2500;
+
+ if (rules & BIT(TRIGGER_NETDEV_RX)) {
+ if (on & on_set) {
+ if (on & MTK_PHY_LED_ON_LINK10)
+ blink |= MTK_PHY_LED_BLINK_10RX;
+ if (on & MTK_PHY_LED_ON_LINK100)
+ blink |= MTK_PHY_LED_BLINK_100RX;
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ blink |= MTK_PHY_LED_BLINK_1000RX;
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ blink |= MTK_PHY_LED_BLINK_2500RX;
+ } else {
+ blink |= rx_blink_set;
+ }
+ }
+
+ if (rules & BIT(TRIGGER_NETDEV_TX)) {
+ if (on & on_set) {
+ if (on & MTK_PHY_LED_ON_LINK10)
+ blink |= MTK_PHY_LED_BLINK_10TX;
+ if (on & MTK_PHY_LED_ON_LINK100)
+ blink |= MTK_PHY_LED_BLINK_100TX;
+ if (on & MTK_PHY_LED_ON_LINK1000)
+ blink |= MTK_PHY_LED_BLINK_1000TX;
+ if (on & MTK_PHY_LED_ON_LINK2500)
+ blink |= MTK_PHY_LED_BLINK_2500TX;
+ } else {
+ blink |= tx_blink_set;
+ }
+ }
+
+ if (blink || on)
+ set_bit(bit_netdev, &priv->led_state);
+ else
+ clear_bit(bit_netdev, &priv->led_state);
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+ MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
+ on);
+
+ if (ret)
+ return ret;
+
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL, blink);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
+
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+ unsigned long *delay_off, bool *blinking)
+{
+ if (index > 1)
+ return -EINVAL;
+
+ if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+ *blinking = true;
+ *delay_on = 50;
+ *delay_off = 50;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
+
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+ u16 led_on_mask, bool on)
+{
+ unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+ bool changed;
+
+ if (on)
+ changed = !test_and_set_bit(bit_on, &priv->led_state);
+ else
+ changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+
+ changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+ (index ? 16 : 0), &priv->led_state);
+ if (changed)
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_ON_CTRL :
+ MTK_PHY_LED0_ON_CTRL,
+ led_on_mask,
+ on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
+
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
+{
+ unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+ (index ? 16 : 0);
+ struct mtk_socphy_priv *priv = phydev->priv;
+ bool changed;
+
+ if (blinking)
+ changed = !test_and_set_bit(bit_blink, &priv->led_state);
+ else
+ changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+
+ changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+ (index ? 16 : 0), &priv->led_state);
+ if (changed)
+ return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+ MTK_PHY_LED1_BLINK_CTRL :
+ MTK_PHY_LED0_BLINK_CTRL,
+ blinking ?
+ MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
+
+void mtk_phy_leds_state_init(struct phy_device *phydev)
+{
+ int i;
+
+ for (i = 0; i < 2; ++i)
+ phydev->drv->led_hw_control_get(phydev, i, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
+
+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
+MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h
new file mode 100644
index 000000000000..63d9fe179b8f
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Common definition for Mediatek Ethernet PHYs
+ * Author: SkyLake Huang <SkyLake.Huang@mediatek.com>
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_EPHY_H_
+#define _MTK_EPHY_H_
+
+#define MTK_EXT_PAGE_ACCESS 0x1f
+
+/* Registers on MDIO_MMD_VEND2 */
+#define MTK_PHY_LED0_ON_CTRL 0x24
+#define MTK_PHY_LED1_ON_CTRL 0x26
+#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0)
+#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0)
+#define MTK_PHY_LED_ON_LINK1000 BIT(0)
+#define MTK_PHY_LED_ON_LINK100 BIT(1)
+#define MTK_PHY_LED_ON_LINK10 BIT(2)
+#define MTK_PHY_LED_ON_LINKDOWN BIT(3)
+#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */
+#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */
+#define MTK_PHY_LED_ON_FORCE_ON BIT(6)
+#define MTK_PHY_LED_ON_LINK2500 BIT(7)
+#define MTK_PHY_LED_ON_POLARITY BIT(14)
+#define MTK_PHY_LED_ON_ENABLE BIT(15)
+
+#define MTK_PHY_LED0_BLINK_CTRL 0x25
+#define MTK_PHY_LED1_BLINK_CTRL 0x27
+#define MTK_PHY_LED_BLINK_1000TX BIT(0)
+#define MTK_PHY_LED_BLINK_1000RX BIT(1)
+#define MTK_PHY_LED_BLINK_100TX BIT(2)
+#define MTK_PHY_LED_BLINK_100RX BIT(3)
+#define MTK_PHY_LED_BLINK_10TX BIT(4)
+#define MTK_PHY_LED_BLINK_10RX BIT(5)
+#define MTK_PHY_LED_BLINK_COLLISION BIT(6)
+#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
+#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
+#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9)
+#define MTK_PHY_LED_BLINK_2500TX BIT(10)
+#define MTK_PHY_LED_BLINK_2500RX BIT(11)
+
+#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \
+ MTK_PHY_LED_ON_LINK100 | \
+ MTK_PHY_LED_ON_LINK10)
+#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
+ MTK_PHY_LED_BLINK_100RX | \
+ MTK_PHY_LED_BLINK_10RX)
+#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \
+ MTK_PHY_LED_BLINK_100RX | \
+ MTK_PHY_LED_BLINK_10RX)
+
+#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \
+ MTK_GPHY_LED_ON_SET)
+#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
+ MTK_GPHY_LED_RX_BLINK_SET)
+#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \
+ MTK_GPHY_LED_TX_BLINK_SET)
+
+#define MTK_PHY_LED_STATE_FORCE_ON 0
+#define MTK_PHY_LED_STATE_FORCE_BLINK 1
+#define MTK_PHY_LED_STATE_NETDEV 2
+
+struct mtk_socphy_priv {
+ unsigned long led_state;
+};
+
+int mtk_phy_read_page(struct phy_device *phydev);
+int mtk_phy_write_page(struct phy_device *phydev, int page);
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules,
+ unsigned long supported_triggers);
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+ unsigned long rules, u16 on_set,
+ u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules, u16 on_set,
+ u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+ unsigned long *delay_off, bool *blinking);
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+ u16 led_on_mask, bool on);
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+ bool blinking);
+void mtk_phy_leds_state_init(struct phy_device *phydev);
+
+#endif /* _MTK_EPHY_H_ */
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 65b0a3115e14..3ef508840674 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -2004,7 +2004,7 @@ static int ksz9477_config_init(struct phy_device *phydev)
* in this switch shall be regarded as broken.
*/
if (phydev->dev_flags & MICREL_NO_EEE)
- phydev->eee_broken_modes = -1;
+ linkmode_fill(phydev->eee_broken_modes);
return kszphy_config_init(phydev);
}
@@ -2018,10 +2018,8 @@ static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
- kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
+ ethtool_puts(&data, kszphy_hw_stats[i].string);
}
static u64 kszphy_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c
index 71d6050b2833..b17bf6708003 100644
--- a/drivers/net/phy/microchip_t1.c
+++ b/drivers/net/phy/microchip_t1.c
@@ -2113,6 +2113,7 @@ static struct phy_driver microchip_t1_phy_driver[] = {
.handle_interrupt = lan887x_handle_interrupt,
.get_sqi = lan887x_get_sqi,
.get_sqi_max = lan87xx_get_sqi_max,
+ .set_loopback = genphy_c45_loopback,
}
};
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 6f74ce0ab1aa..bee381200ab8 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -139,8 +139,7 @@ static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data)
return;
for (i = 0; i < priv->nstats; i++)
- strscpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string,
- ETH_GSTRING_LEN);
+ ethtool_puts(&data, priv->hw_stats[i].string);
}
static u64 vsc85xx_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 7e328c2a29a4..ade544bc007d 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -1140,13 +1140,11 @@ static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data)
for (i = 0; i < count; i++) {
if (i < ARRAY_SIZE(common_hw_stats)) {
- strscpy(data + i * ETH_GSTRING_LEN,
- common_hw_stats[i].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, common_hw_stats[i].name);
continue;
}
idx = i - ARRAY_SIZE(common_hw_stats);
- strscpy(data + i * ETH_GSTRING_LEN,
- phy_data->stats[idx].name, ETH_GSTRING_LEN);
+ ethtool_puts(&data, phy_data->stats[idx].name);
}
}
diff --git a/drivers/net/phy/nxp-cbtx.c b/drivers/net/phy/nxp-cbtx.c
index 145703f0a406..3d25491043a3 100644
--- a/drivers/net/phy/nxp-cbtx.c
+++ b/drivers/net/phy/nxp-cbtx.c
@@ -182,7 +182,7 @@ static int cbtx_get_sset_count(struct phy_device *phydev)
static void cbtx_get_strings(struct phy_device *phydev, u8 *data)
{
- strncpy(data, "100btx_rx_err", ETH_GSTRING_LEN);
+ ethtool_puts(&data, "100btx_rx_err");
}
static void cbtx_get_stats(struct phy_device *phydev,
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 5695935fdce9..da5c15310d8c 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -680,17 +680,16 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
* @phydev: target phy_device struct
* @adv: the linkmode advertisement settings
*/
-int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
+static int genphy_c45_write_eee_adv(struct phy_device *phydev,
+ unsigned long *adv)
{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp);
int val, changed = 0;
- if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
- val = linkmode_to_mii_eee_cap1_t(adv);
+ linkmode_andnot(tmp, adv, phydev->eee_broken_modes);
- /* In eee_broken_modes are stored MDIO_AN_EEE_ADV specific raw
- * register values.
- */
- val &= ~phydev->eee_broken_modes;
+ if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
+ val = linkmode_to_mii_eee_cap1_t(tmp);
/* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1
* (Register 7.60)
@@ -708,7 +707,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
}
if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) {
- val = linkmode_to_mii_eee_cap2_t(adv);
+ val = linkmode_to_mii_eee_cap2_t(tmp);
/* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2
* (Register 7.62)
@@ -950,6 +949,7 @@ int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
return genphy_c45_write_eee_adv(phydev, phydev->advertising_eee);
}
+EXPORT_SYMBOL_GPL(genphy_c45_an_config_eee_aneg);
/**
* genphy_c45_pma_baset1_read_abilities - read supported baset1 link modes from PMA
@@ -1521,20 +1521,17 @@ EXPORT_SYMBOL(genphy_c45_eee_is_active);
int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
struct ethtool_keee *data)
{
- __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
- __ETHTOOL_DECLARE_LINK_MODE_MASK(lp) = {};
bool is_enabled;
int ret;
- ret = genphy_c45_eee_is_active(phydev, adv, lp, &is_enabled);
+ ret = genphy_c45_eee_is_active(phydev, data->advertised,
+ data->lp_advertised, &is_enabled);
if (ret < 0)
return ret;
data->eee_enabled = is_enabled;
data->eee_active = ret;
linkmode_copy(data->supported, phydev->supported_eee);
- linkmode_copy(data->advertised, adv);
- linkmode_copy(data->lp_advertised, lp);
return 0;
}
@@ -1568,11 +1565,10 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
phydev_warn(phydev, "At least some EEE link modes are not supported.\n");
return -EINVAL;
}
- } else {
- adv = phydev->supported_eee;
+ linkmode_copy(phydev->advertising_eee, adv);
+ } else if (linkmode_empty(phydev->advertising_eee)) {
+ phy_advertise_eee_all(phydev);
}
-
- linkmode_copy(phydev->advertising_eee, adv);
}
phydev->eee_enabled = data->eee_enabled;
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 4e8db12d6092..6bf3ec985f3d 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -388,28 +388,25 @@ void of_set_phy_supported(struct phy_device *phydev)
void of_set_phy_eee_broken(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
- u32 broken = 0;
+ unsigned long *modes = phydev->eee_broken_modes;
- if (!IS_ENABLED(CONFIG_OF_MDIO))
+ if (!IS_ENABLED(CONFIG_OF_MDIO) || !node)
return;
- if (!node)
- return;
+ linkmode_zero(modes);
if (of_property_read_bool(node, "eee-broken-100tx"))
- broken |= MDIO_EEE_100TX;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, modes);
if (of_property_read_bool(node, "eee-broken-1000t"))
- broken |= MDIO_EEE_1000T;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, modes);
if (of_property_read_bool(node, "eee-broken-10gt"))
- broken |= MDIO_EEE_10GT;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, modes);
if (of_property_read_bool(node, "eee-broken-1000kx"))
- broken |= MDIO_EEE_1000KX;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, modes);
if (of_property_read_bool(node, "eee-broken-10gkx4"))
- broken |= MDIO_EEE_10GKX4;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, modes);
if (of_property_read_bool(node, "eee-broken-10gkr"))
- broken |= MDIO_EEE_10GKR;
-
- phydev->eee_broken_modes = broken;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, modes);
}
/**
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 563497a3274c..bc24c9f2786b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2240,29 +2240,6 @@ static int genphy_c37_config_advert(struct phy_device *phydev)
}
/**
- * genphy_config_eee_advert - disable unwanted eee mode advertisement
- * @phydev: target phy_device struct
- *
- * Description: Writes MDIO_AN_EEE_ADV after disabling unsupported energy
- * efficent ethernet modes. Returns 0 if the PHY's advertisement hasn't
- * changed, and 1 if it has changed.
- */
-int genphy_config_eee_advert(struct phy_device *phydev)
-{
- int err;
-
- /* Nothing to disable */
- if (!phydev->eee_broken_modes)
- return 0;
-
- err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV,
- phydev->eee_broken_modes, 0);
- /* If the call failed, we assume that EEE is not supported */
- return err < 0 ? 0 : err;
-}
-EXPORT_SYMBOL(genphy_config_eee_advert);
-
-/**
* genphy_setup_forced - configures/forces speed/duplex from @phydev
* @phydev: target phy_device struct
*
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index b5870f8666ac..30a654e98352 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -78,7 +78,7 @@ struct phylink {
unsigned int pcs_neg_mode;
unsigned int pcs_state;
- bool mac_link_dropped;
+ bool link_failed;
struct sfp_bus *sfp_bus;
bool sfp_may_have_phy;
@@ -764,8 +764,8 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported,
static int phylink_parse_fixedlink(struct phylink *pl,
const struct fwnode_handle *fwnode)
{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
struct fwnode_handle *fixed_node;
- bool pause, asym_pause, autoneg;
const struct phy_setting *s;
struct gpio_desc *desc;
u32 speed;
@@ -838,22 +838,15 @@ static int phylink_parse_fixedlink(struct phylink *pl,
linkmode_copy(pl->link_config.advertising, pl->supported);
phylink_validate(pl, pl->supported, &pl->link_config);
- pause = phylink_test(pl->supported, Pause);
- asym_pause = phylink_test(pl->supported, Asym_Pause);
- autoneg = phylink_test(pl->supported, Autoneg);
s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex,
pl->supported, true);
- linkmode_zero(pl->supported);
- phylink_set(pl->supported, MII);
- if (pause)
- phylink_set(pl->supported, Pause);
-
- if (asym_pause)
- phylink_set(pl->supported, Asym_Pause);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mask);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mask);
+ linkmode_and(pl->supported, pl->supported, mask);
- if (autoneg)
- phylink_set(pl->supported, Autoneg);
+ phylink_set(pl->supported, MII);
if (s) {
__set_bit(s->bit, pl->supported);
@@ -1465,81 +1458,71 @@ static void phylink_resolve(struct work_struct *w)
cur_link_state = pl->old_link_state;
if (pl->phylink_disable_state) {
- pl->mac_link_dropped = false;
+ pl->link_failed = false;
link_state.link = false;
- } else if (pl->mac_link_dropped) {
+ } else if (pl->link_failed) {
link_state.link = false;
retrigger = true;
+ } else if (pl->cur_link_an_mode == MLO_AN_FIXED) {
+ phylink_get_fixed_state(pl, &link_state);
+ mac_config = link_state.link;
+ } else if (pl->cur_link_an_mode == MLO_AN_PHY) {
+ link_state = pl->phy_state;
+ mac_config = link_state.link;
} else {
- switch (pl->cur_link_an_mode) {
- case MLO_AN_PHY:
- link_state = pl->phy_state;
- phylink_apply_manual_flow(pl, &link_state);
- mac_config = link_state.link;
- break;
+ phylink_mac_pcs_get_state(pl, &link_state);
- case MLO_AN_FIXED:
- phylink_get_fixed_state(pl, &link_state);
- mac_config = link_state.link;
- break;
+ /* The PCS may have a latching link-fail indicator. If the link
+ * was up, bring the link down and re-trigger the resolve.
+ * Otherwise, re-read the PCS state to get the current status
+ * of the link.
+ */
+ if (!link_state.link) {
+ if (cur_link_state)
+ retrigger = true;
+ else
+ phylink_mac_pcs_get_state(pl, &link_state);
+ }
- case MLO_AN_INBAND:
- phylink_mac_pcs_get_state(pl, &link_state);
+ /* If we have a phy, the "up" state is the union of both the
+ * PHY and the MAC
+ */
+ if (pl->phydev)
+ link_state.link &= pl->phy_state.link;
- /* The PCS may have a latching link-fail indicator.
- * If the link was up, bring the link down and
- * re-trigger the resolve. Otherwise, re-read the
- * PCS state to get the current status of the link.
+ /* Only update if the PHY link is up */
+ if (pl->phydev && pl->phy_state.link) {
+ /* If the interface has changed, force a link down
+ * event if the link isn't already down, and re-resolve.
*/
- if (!link_state.link) {
- if (cur_link_state)
- retrigger = true;
- else
- phylink_mac_pcs_get_state(pl,
- &link_state);
+ if (link_state.interface != pl->phy_state.interface) {
+ retrigger = true;
+ link_state.link = false;
}
- /* If we have a phy, the "up" state is the union of
- * both the PHY and the MAC
+ link_state.interface = pl->phy_state.interface;
+
+ /* If we are doing rate matching, then the link
+ * speed/duplex comes from the PHY
*/
- if (pl->phydev)
- link_state.link &= pl->phy_state.link;
-
- /* Only update if the PHY link is up */
- if (pl->phydev && pl->phy_state.link) {
- /* If the interface has changed, force a
- * link down event if the link isn't already
- * down, and re-resolve.
- */
- if (link_state.interface !=
- pl->phy_state.interface) {
- retrigger = true;
- link_state.link = false;
- }
- link_state.interface = pl->phy_state.interface;
-
- /* If we are doing rate matching, then the
- * link speed/duplex comes from the PHY
- */
- if (pl->phy_state.rate_matching) {
- link_state.rate_matching =
- pl->phy_state.rate_matching;
- link_state.speed = pl->phy_state.speed;
- link_state.duplex =
- pl->phy_state.duplex;
- }
-
- /* If we have a PHY, we need to update with
- * the PHY flow control bits.
- */
- link_state.pause = pl->phy_state.pause;
- mac_config = true;
+ if (pl->phy_state.rate_matching) {
+ link_state.rate_matching =
+ pl->phy_state.rate_matching;
+ link_state.speed = pl->phy_state.speed;
+ link_state.duplex = pl->phy_state.duplex;
}
- phylink_apply_manual_flow(pl, &link_state);
- break;
+
+ /* If we have a PHY, we need to update with the PHY
+ * flow control bits.
+ */
+ link_state.pause = pl->phy_state.pause;
+ mac_config = true;
}
}
+ if (pl->cur_link_an_mode != MLO_AN_FIXED)
+ phylink_apply_manual_flow(pl, &link_state);
+
if (mac_config) {
if (link_state.interface != pl->link_config.interface) {
/* The interface has changed, force the link down and
@@ -1562,7 +1545,7 @@ static void phylink_resolve(struct work_struct *w)
phylink_link_up(pl, link_state);
}
if (!link_state.link && retrigger) {
- pl->mac_link_dropped = false;
+ pl->link_failed = false;
queue_work(system_power_efficient_wq, &pl->resolve);
}
mutex_unlock(&pl->state_mutex);
@@ -1818,6 +1801,8 @@ static void phylink_phy_change(struct phy_device *phydev, bool up)
pl->phy_state.pause |= MLO_PAUSE_RX;
pl->phy_state.interface = phydev->interface;
pl->phy_state.link = up;
+ if (!up)
+ pl->link_failed = true;
mutex_unlock(&pl->state_mutex);
phylink_run_resolve(pl);
@@ -2141,7 +2126,7 @@ EXPORT_SYMBOL_GPL(phylink_disconnect_phy);
static void phylink_link_changed(struct phylink *pl, bool up, const char *what)
{
if (!up)
- pl->mac_link_dropped = true;
+ pl->link_failed = true;
phylink_run_resolve(pl);
phylink_dbg(pl, "%s link %s\n", what, up ? "up" : "down");
}
@@ -2415,6 +2400,32 @@ int phylink_ethtool_set_wol(struct phylink *pl, struct ethtool_wolinfo *wol)
}
EXPORT_SYMBOL_GPL(phylink_ethtool_set_wol);
+static phy_interface_t phylink_sfp_select_interface(struct phylink *pl,
+ const unsigned long *link_modes)
+{
+ phy_interface_t interface;
+
+ interface = sfp_select_interface(pl->sfp_bus, link_modes);
+ if (interface == PHY_INTERFACE_MODE_NA) {
+ phylink_err(pl,
+ "selection of interface failed, advertisement %*pb\n",
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+ link_modes);
+ return interface;
+ }
+
+ if (!test_bit(interface, pl->config->supported_interfaces)) {
+ phylink_err(pl,
+ "selection of interface failed, SFP selected %s (%u) but MAC supports %*pbl\n",
+ phy_modes(interface), interface,
+ (int)PHY_INTERFACE_MODE_MAX,
+ pl->config->supported_interfaces);
+ return PHY_INTERFACE_MODE_NA;
+ }
+
+ return interface;
+}
+
static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask);
@@ -2597,15 +2608,10 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
* link can be configured correctly.
*/
if (pl->sfp_bus) {
- config.interface = sfp_select_interface(pl->sfp_bus,
+ config.interface = phylink_sfp_select_interface(pl,
config.advertising);
- if (config.interface == PHY_INTERFACE_MODE_NA) {
- phylink_err(pl,
- "selection of interface failed, advertisement %*pb\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS,
- config.advertising);
+ if (config.interface == PHY_INTERFACE_MODE_NA)
return -EINVAL;
- }
/* Revalidate with the selected interface */
linkmode_copy(support, pl->supported);
@@ -2775,7 +2781,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
* link will cycle.
*/
if (manual_changed) {
- pl->mac_link_dropped = true;
+ pl->link_failed = true;
phylink_run_resolve(pl);
}
@@ -3210,10 +3216,8 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode,
static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
struct phy_device *phy)
{
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
struct phylink_link_state config;
- phy_interface_t iface;
int ret;
linkmode_copy(support, phy->supported);
@@ -3234,24 +3238,21 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode,
return ret;
}
- iface = sfp_select_interface(pl->sfp_bus, config.advertising);
- if (iface == PHY_INTERFACE_MODE_NA) {
- phylink_err(pl,
- "selection of interface failed, advertisement %*pb\n",
- __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising);
+ config.interface = phylink_sfp_select_interface(pl, config.advertising);
+ if (config.interface == PHY_INTERFACE_MODE_NA)
return -EINVAL;
- }
- config.interface = iface;
- linkmode_copy(support1, support);
- ret = phylink_validate(pl, support1, &config);
- if (ret) {
- phylink_err(pl,
- "validation of %s/%s with support %*pb failed: %pe\n",
- phylink_an_mode_str(mode),
- phy_modes(config.interface),
- __ETHTOOL_LINK_MODE_MASK_NBITS, support,
- ERR_PTR(ret));
+ /* Attach the PHY so that the PHY is present when we do the major
+ * configuration step.
+ */
+ ret = phylink_attach_phy(pl, phy, config.interface);
+ if (ret < 0)
+ return ret;
+
+ /* This will validate the configuration for us. */
+ ret = phylink_bringup_phy(pl, phy, config.interface);
+ if (ret < 0) {
+ phy_detach(phy);
return ret;
}
@@ -3409,9 +3410,7 @@ static bool phylink_phy_no_inband(struct phy_device *phy)
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
{
struct phylink *pl = upstream;
- phy_interface_t interface;
u8 mode;
- int ret;
/*
* This is the new way of dealing with flow control for PHYs,
@@ -3432,20 +3431,7 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
pl->config->supported_interfaces);
/* Do the initial configuration */
- ret = phylink_sfp_config_phy(pl, mode, phy);
- if (ret < 0)
- return ret;
-
- interface = pl->link_config.interface;
- ret = phylink_attach_phy(pl, phy, interface);
- if (ret < 0)
- return ret;
-
- ret = phylink_bringup_phy(pl, phy, interface);
- if (ret)
- phy_detach(phy);
-
- return ret;
+ return phylink_sfp_config_phy(pl, mode, phy);
}
static void phylink_sfp_disconnect_phy(void *upstream,
diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c
index a05d0df6fa16..7a5039920b9f 100644
--- a/drivers/net/phy/qcom/qca83xx.c
+++ b/drivers/net/phy/qcom/qca83xx.c
@@ -42,10 +42,8 @@ static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
- strscpy(data + i * ETH_GSTRING_LEN,
- qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
- }
+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
+ ethtool_puts(&data, qca83xx_hw_stats[i].string);
}
static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index f137c82f1c0f..0c011d8f5d4d 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1076,6 +1076,7 @@ static const struct usb_device_id products[] = {
USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index a5612c799f5e..468c73974046 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -10069,6 +10069,7 @@ static const struct usb_device_id rtl8152_table[] = {
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x3062) },
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x3069) },
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x3082) },
+ { USB_DEVICE(VENDOR_ID_LENOVO, 0x3098) },
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x7205) },
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x720c) },
{ USB_DEVICE(VENDOR_ID_LENOVO, 0x7214) },
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 18148e068aa0..0d6d0d749d44 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1781,19 +1781,11 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
/*
* create and register peer first
*/
- if (data != NULL && data[VETH_INFO_PEER] != NULL) {
- struct nlattr *nla_peer;
+ if (data && data[VETH_INFO_PEER]) {
+ struct nlattr *nla_peer = data[VETH_INFO_PEER];
- nla_peer = data[VETH_INFO_PEER];
ifmp = nla_data(nla_peer);
- err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
- if (err < 0)
- return err;
-
- err = veth_validate(peer_tb, NULL, extack);
- if (err < 0)
- return err;
-
+ rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack);
tbp = peer_tb;
} else {
ifmp = NULL;
@@ -1809,9 +1801,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
}
net = rtnl_link_get_net(src_net, tbp);
- if (IS_ERR(net))
- return PTR_ERR(net);
-
peer = rtnl_create_link(net, ifname, name_assign_type,
&veth_link_ops, tbp, extack);
if (IS_ERR(peer)) {
@@ -1952,6 +1941,7 @@ static struct rtnl_link_ops veth_link_ops = {
.newlink = veth_newlink,
.dellink = veth_dellink,
.policy = veth_policy,
+ .peer_type = VETH_INFO_PEER,
.maxtype = VETH_INFO_MAX,
.get_link_net = veth_get_link_net,
.get_num_tx_queues = veth_get_num_queues,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 792e9eadbfc3..64c87bb48a41 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -45,9 +45,6 @@ module_param(napi_tx, bool, 0644);
#define VIRTIO_XDP_TX BIT(0)
#define VIRTIO_XDP_REDIR BIT(1)
-#define VIRTIO_XDP_FLAG BIT(0)
-#define VIRTIO_ORPHAN_FLAG BIT(1)
-
/* RX packet size EWMA. The average packet size is used to determine the packet
* buffer size when refilling RX rings. As the entire RX ring may be refilled
* at once, the weight is chosen so that the EWMA will be insensitive to short-
@@ -86,6 +83,7 @@ struct virtnet_sq_free_stats {
u64 bytes;
u64 napi_packets;
u64 napi_bytes;
+ u64 xsk;
};
struct virtnet_sq_stats {
@@ -298,6 +296,10 @@ struct send_queue {
/* Record whether sq is in reset state. */
bool reset;
+
+ struct xsk_buff_pool *xsk_pool;
+
+ dma_addr_t xsk_hdr_dma_addr;
};
/* Internal representation of a receive virtqueue */
@@ -356,9 +358,6 @@ struct receive_queue {
struct xdp_rxq_info xsk_rxq_info;
struct xdp_buff **xsk_buffs;
-
- /* Do dma by self */
- bool do_dma;
};
/* This structure can contain rss message with maximum settings for indirection table and keysize
@@ -368,15 +367,16 @@ struct receive_queue {
* because table sizes may be differ according to the device configuration.
*/
#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
-#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
struct virtio_net_ctrl_rss {
u32 hash_types;
u16 indirection_table_mask;
u16 unclassified_queue;
- u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+ u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
u16 max_tx_vq;
u8 hash_key_length;
u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+
+ u16 *indirection_table;
};
/* Control VQ buffers: protected by the rtnl lock */
@@ -500,6 +500,8 @@ struct virtio_net_common_hdr {
};
};
+static struct virtio_net_common_hdr xsk_hdr;
+
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp,
struct net_device *dev,
@@ -511,68 +513,127 @@ static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
struct sk_buff *curr_skb,
struct page *page, void *buf,
int len, int truesize);
+static void virtnet_xsk_completed(struct send_queue *sq, int num);
-static bool is_xdp_frame(void *ptr)
+enum virtnet_xmit_type {
+ VIRTNET_XMIT_TYPE_SKB,
+ VIRTNET_XMIT_TYPE_SKB_ORPHAN,
+ VIRTNET_XMIT_TYPE_XDP,
+ VIRTNET_XMIT_TYPE_XSK,
+};
+
+static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
{
- return (unsigned long)ptr & VIRTIO_XDP_FLAG;
+ if (!indir_table_size) {
+ rss->indirection_table = NULL;
+ return 0;
+ }
+
+ rss->indirection_table = kmalloc_array(indir_table_size, sizeof(u16), GFP_KERNEL);
+ if (!rss->indirection_table)
+ return -ENOMEM;
+
+ return 0;
}
-static void *xdp_to_ptr(struct xdp_frame *ptr)
+static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
{
- return (void *)((unsigned long)ptr | VIRTIO_XDP_FLAG);
+ kfree(rss->indirection_table);
}
-static struct xdp_frame *ptr_to_xdp(void *ptr)
+/* We use the last two bits of the pointer to distinguish the xmit type. */
+#define VIRTNET_XMIT_TYPE_MASK (BIT(0) | BIT(1))
+
+#define VIRTIO_XSK_FLAG_OFFSET 2
+
+static enum virtnet_xmit_type virtnet_xmit_ptr_unpack(void **ptr)
+{
+ unsigned long p = (unsigned long)*ptr;
+
+ *ptr = (void *)(p & ~VIRTNET_XMIT_TYPE_MASK);
+
+ return p & VIRTNET_XMIT_TYPE_MASK;
+}
+
+static void *virtnet_xmit_ptr_pack(void *ptr, enum virtnet_xmit_type type)
{
- return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG);
+ return (void *)((unsigned long)ptr | type);
}
-static bool is_orphan_skb(void *ptr)
+static int virtnet_add_outbuf(struct send_queue *sq, int num, void *data,
+ enum virtnet_xmit_type type)
{
- return (unsigned long)ptr & VIRTIO_ORPHAN_FLAG;
+ return virtqueue_add_outbuf(sq->vq, sq->sg, num,
+ virtnet_xmit_ptr_pack(data, type),
+ GFP_ATOMIC);
}
-static void *skb_to_ptr(struct sk_buff *skb, bool orphan)
+static u32 virtnet_ptr_to_xsk_buff_len(void *ptr)
{
- return (void *)((unsigned long)skb | (orphan ? VIRTIO_ORPHAN_FLAG : 0));
+ return ((unsigned long)ptr) >> VIRTIO_XSK_FLAG_OFFSET;
}
-static struct sk_buff *ptr_to_skb(void *ptr)
+static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len)
{
- return (struct sk_buff *)((unsigned long)ptr & ~VIRTIO_ORPHAN_FLAG);
+ sg_dma_address(sg) = addr;
+ sg_dma_len(sg) = len;
}
static void __free_old_xmit(struct send_queue *sq, struct netdev_queue *txq,
bool in_napi, struct virtnet_sq_free_stats *stats)
{
+ struct xdp_frame *frame;
+ struct sk_buff *skb;
unsigned int len;
void *ptr;
while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) {
- if (!is_xdp_frame(ptr)) {
- struct sk_buff *skb = ptr_to_skb(ptr);
+ switch (virtnet_xmit_ptr_unpack(&ptr)) {
+ case VIRTNET_XMIT_TYPE_SKB:
+ skb = ptr;
pr_debug("Sent skb %p\n", skb);
+ stats->napi_packets++;
+ stats->napi_bytes += skb->len;
+ napi_consume_skb(skb, in_napi);
+ break;
- if (is_orphan_skb(ptr)) {
- stats->packets++;
- stats->bytes += skb->len;
- } else {
- stats->napi_packets++;
- stats->napi_bytes += skb->len;
- }
+ case VIRTNET_XMIT_TYPE_SKB_ORPHAN:
+ skb = ptr;
+
+ stats->packets++;
+ stats->bytes += skb->len;
napi_consume_skb(skb, in_napi);
- } else {
- struct xdp_frame *frame = ptr_to_xdp(ptr);
+ break;
+
+ case VIRTNET_XMIT_TYPE_XDP:
+ frame = ptr;
stats->packets++;
stats->bytes += xdp_get_frame_len(frame);
xdp_return_frame(frame);
+ break;
+
+ case VIRTNET_XMIT_TYPE_XSK:
+ stats->bytes += virtnet_ptr_to_xsk_buff_len(ptr);
+ stats->xsk++;
+ break;
}
}
netdev_tx_completed_queue(txq, stats->napi_packets, stats->napi_bytes);
}
+static void virtnet_free_old_xmit(struct send_queue *sq,
+ struct netdev_queue *txq,
+ bool in_napi,
+ struct virtnet_sq_free_stats *stats)
+{
+ __free_old_xmit(sq, txq, in_napi, stats);
+
+ if (stats->xsk)
+ virtnet_xsk_completed(sq, stats->xsk);
+}
+
/* Converting between virtqueue no. and kernel tx/rx queue no.
* 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq
*/
@@ -856,11 +917,14 @@ ok:
static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
struct page *page = virt_to_head_page(buf);
struct virtnet_rq_dma *dma;
void *head;
int offset;
+ BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs);
+
head = page_address(page);
dma = head;
@@ -885,10 +949,13 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)
{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
void *buf;
+ BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs);
+
buf = virtqueue_get_buf_ctx(rq->vq, len, ctx);
- if (buf && rq->do_dma)
+ if (buf)
virtnet_rq_unmap(rq, buf, *len);
return buf;
@@ -896,15 +963,13 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)
static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)
{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
struct virtnet_rq_dma *dma;
dma_addr_t addr;
u32 offset;
void *head;
- if (!rq->do_dma) {
- sg_init_one(rq->sg, buf, len);
- return;
- }
+ BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs);
head = page_address(rq->alloc_frag.page);
@@ -915,60 +980,57 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)
addr = dma->addr - sizeof(*dma) + offset;
sg_init_table(rq->sg, 1);
- rq->sg[0].dma_address = addr;
- rq->sg[0].length = len;
+ sg_fill_dma(rq->sg, addr, len);
}
static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp)
{
struct page_frag *alloc_frag = &rq->alloc_frag;
+ struct virtnet_info *vi = rq->vq->vdev->priv;
struct virtnet_rq_dma *dma;
void *buf, *head;
dma_addr_t addr;
- if (unlikely(!skb_page_frag_refill(size, alloc_frag, gfp)))
- return NULL;
+ BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs);
head = page_address(alloc_frag->page);
- if (rq->do_dma) {
- dma = head;
-
- /* new pages */
- if (!alloc_frag->offset) {
- if (rq->last_dma) {
- /* Now, the new page is allocated, the last dma
- * will not be used. So the dma can be unmapped
- * if the ref is 0.
- */
- virtnet_rq_unmap(rq, rq->last_dma, 0);
- rq->last_dma = NULL;
- }
+ dma = head;
- dma->len = alloc_frag->size - sizeof(*dma);
+ /* new pages */
+ if (!alloc_frag->offset) {
+ if (rq->last_dma) {
+ /* Now, the new page is allocated, the last dma
+ * will not be used. So the dma can be unmapped
+ * if the ref is 0.
+ */
+ virtnet_rq_unmap(rq, rq->last_dma, 0);
+ rq->last_dma = NULL;
+ }
- addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1,
- dma->len, DMA_FROM_DEVICE, 0);
- if (virtqueue_dma_mapping_error(rq->vq, addr))
- return NULL;
+ dma->len = alloc_frag->size - sizeof(*dma);
- dma->addr = addr;
- dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr);
+ addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1,
+ dma->len, DMA_FROM_DEVICE, 0);
+ if (virtqueue_dma_mapping_error(rq->vq, addr))
+ return NULL;
- /* Add a reference to dma to prevent the entire dma from
- * being released during error handling. This reference
- * will be freed after the pages are no longer used.
- */
- get_page(alloc_frag->page);
- dma->ref = 1;
- alloc_frag->offset = sizeof(*dma);
+ dma->addr = addr;
+ dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr);
- rq->last_dma = dma;
- }
+ /* Add a reference to dma to prevent the entire dma from
+ * being released during error handling. This reference
+ * will be freed after the pages are no longer used.
+ */
+ get_page(alloc_frag->page);
+ dma->ref = 1;
+ alloc_frag->offset = sizeof(*dma);
- ++dma->ref;
+ rq->last_dma = dma;
}
+ ++dma->ref;
+
buf = head + alloc_frag->offset;
get_page(alloc_frag->page);
@@ -990,7 +1052,7 @@ static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf)
return;
}
- if (rq->do_dma)
+ if (!vi->big_packets || vi->mergeable_rx_bufs)
virtnet_rq_unmap(rq, buf, 0);
virtnet_rq_free_buf(vi, rq, buf);
@@ -1001,7 +1063,7 @@ static void free_old_xmit(struct send_queue *sq, struct netdev_queue *txq,
{
struct virtnet_sq_free_stats stats = {0};
- __free_old_xmit(sq, txq, in_napi, &stats);
+ virtnet_free_old_xmit(sq, txq, in_napi, &stats);
/* Avoid overhead when no packets have been processed
* happens when called speculatively from start_xmit.
@@ -1068,12 +1130,6 @@ static void check_sq_full_and_disable(struct virtnet_info *vi,
}
}
-static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len)
-{
- sg->dma_address = addr;
- sg->length = len;
-}
-
static struct xdp_buff *buf_to_xdp(struct virtnet_info *vi,
struct receive_queue *rq, void *buf, u32 len)
{
@@ -1354,7 +1410,8 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue
sg_init_table(rq->sg, 1);
sg_fill_dma(rq->sg, addr, len);
- err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, xsk_buffs[i], gfp);
+ err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1,
+ xsk_buffs[i], NULL, gfp);
if (err)
goto err;
}
@@ -1368,6 +1425,120 @@ err:
return err;
}
+static void *virtnet_xsk_to_ptr(u32 len)
+{
+ unsigned long p;
+
+ p = len << VIRTIO_XSK_FLAG_OFFSET;
+
+ return virtnet_xmit_ptr_pack((void *)p, VIRTNET_XMIT_TYPE_XSK);
+}
+
+static int virtnet_xsk_xmit_one(struct send_queue *sq,
+ struct xsk_buff_pool *pool,
+ struct xdp_desc *desc)
+{
+ struct virtnet_info *vi;
+ dma_addr_t addr;
+
+ vi = sq->vq->vdev->priv;
+
+ addr = xsk_buff_raw_get_dma(pool, desc->addr);
+ xsk_buff_raw_dma_sync_for_device(pool, addr, desc->len);
+
+ sg_init_table(sq->sg, 2);
+ sg_fill_dma(sq->sg, sq->xsk_hdr_dma_addr, vi->hdr_len);
+ sg_fill_dma(sq->sg + 1, addr, desc->len);
+
+ return virtqueue_add_outbuf_premapped(sq->vq, sq->sg, 2,
+ virtnet_xsk_to_ptr(desc->len),
+ GFP_ATOMIC);
+}
+
+static int virtnet_xsk_xmit_batch(struct send_queue *sq,
+ struct xsk_buff_pool *pool,
+ unsigned int budget,
+ u64 *kicks)
+{
+ struct xdp_desc *descs = pool->tx_descs;
+ bool kick = false;
+ u32 nb_pkts, i;
+ int err;
+
+ budget = min_t(u32, budget, sq->vq->num_free);
+
+ nb_pkts = xsk_tx_peek_release_desc_batch(pool, budget);
+ if (!nb_pkts)
+ return 0;
+
+ for (i = 0; i < nb_pkts; i++) {
+ err = virtnet_xsk_xmit_one(sq, pool, &descs[i]);
+ if (unlikely(err)) {
+ xsk_tx_completed(sq->xsk_pool, nb_pkts - i);
+ break;
+ }
+
+ kick = true;
+ }
+
+ if (kick && virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq))
+ (*kicks)++;
+
+ return i;
+}
+
+static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool,
+ int budget)
+{
+ struct virtnet_info *vi = sq->vq->vdev->priv;
+ struct virtnet_sq_free_stats stats = {};
+ struct net_device *dev = vi->dev;
+ u64 kicks = 0;
+ int sent;
+
+ /* Avoid to wakeup napi meanless, so call __free_old_xmit instead of
+ * free_old_xmit().
+ */
+ __free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq), true, &stats);
+
+ if (stats.xsk)
+ xsk_tx_completed(sq->xsk_pool, stats.xsk);
+
+ sent = virtnet_xsk_xmit_batch(sq, pool, budget, &kicks);
+
+ if (!is_xdp_raw_buffer_queue(vi, sq - vi->sq))
+ check_sq_full_and_disable(vi, vi->dev, sq);
+
+ if (sent) {
+ struct netdev_queue *txq;
+
+ txq = netdev_get_tx_queue(vi->dev, sq - vi->sq);
+ txq_trans_cond_update(txq);
+ }
+
+ u64_stats_update_begin(&sq->stats.syncp);
+ u64_stats_add(&sq->stats.packets, stats.packets);
+ u64_stats_add(&sq->stats.bytes, stats.bytes);
+ u64_stats_add(&sq->stats.kicks, kicks);
+ u64_stats_add(&sq->stats.xdp_tx, sent);
+ u64_stats_update_end(&sq->stats.syncp);
+
+ if (xsk_uses_need_wakeup(pool))
+ xsk_set_tx_need_wakeup(pool);
+
+ return sent;
+}
+
+static void xsk_wakeup(struct send_queue *sq)
+{
+ if (napi_if_scheduled_mark_missed(&sq->napi))
+ return;
+
+ local_bh_disable();
+ virtqueue_napi_schedule(&sq->napi, sq->vq);
+ local_bh_enable();
+}
+
static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
{
struct virtnet_info *vi = netdev_priv(dev);
@@ -1381,14 +1552,19 @@ static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
sq = &vi->sq[qid];
- if (napi_if_scheduled_mark_missed(&sq->napi))
- return 0;
+ xsk_wakeup(sq);
+ return 0;
+}
- local_bh_disable();
- virtqueue_napi_schedule(&sq->napi, sq->vq);
- local_bh_enable();
+static void virtnet_xsk_completed(struct send_queue *sq, int num)
+{
+ xsk_tx_completed(sq->xsk_pool, num);
- return 0;
+ /* If this is called by rx poll, start_xmit and xdp xmit we should
+ * wakeup the tx napi to consume the xsk tx queue, because the tx
+ * interrupt may not be triggered.
+ */
+ xsk_wakeup(sq);
}
static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
@@ -1431,8 +1607,7 @@ static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
skb_frag_size(frag), skb_frag_off(frag));
}
- err = virtqueue_add_outbuf(sq->vq, sq->sg, nr_frags + 1,
- xdp_to_ptr(xdpf), GFP_ATOMIC);
+ err = virtnet_add_outbuf(sq, nr_frags + 1, xdpf, VIRTNET_XMIT_TYPE_XDP);
if (unlikely(err))
return -ENOSPC; /* Caller handle free/refcnt */
@@ -1505,8 +1680,8 @@ static int virtnet_xdp_xmit(struct net_device *dev,
}
/* Free up any pending old buffers before queueing new ones. */
- __free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq),
- false, &stats);
+ virtnet_free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq),
+ false, &stats);
for (i = 0; i < n; i++) {
struct xdp_frame *xdpf = frames[i];
@@ -2423,6 +2598,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
len = SKB_DATA_ALIGN(len) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ if (unlikely(!skb_page_frag_refill(len, &rq->alloc_frag, gfp)))
+ return -ENOMEM;
+
buf = virtnet_rq_alloc(rq, len, gfp);
if (unlikely(!buf))
return -ENOMEM;
@@ -2431,10 +2609,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
virtnet_rq_init_one_sg(rq, buf, vi->hdr_len + GOOD_PACKET_LEN);
- err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
+ err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1, buf, ctx, gfp);
if (err < 0) {
- if (rq->do_dma)
- virtnet_rq_unmap(rq, buf, 0);
+ virtnet_rq_unmap(rq, buf, 0);
put_page(virt_to_head_page(buf));
}
@@ -2525,6 +2702,12 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
*/
len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room);
+ if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp)))
+ return -ENOMEM;
+
+ if (!alloc_frag->offset && len + room + sizeof(struct virtnet_rq_dma) > alloc_frag->size)
+ len -= sizeof(struct virtnet_rq_dma);
+
buf = virtnet_rq_alloc(rq, len + room, gfp);
if (unlikely(!buf))
return -ENOMEM;
@@ -2546,10 +2729,9 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
virtnet_rq_init_one_sg(rq, buf, len);
ctx = mergeable_len_to_ctx(len + room, headroom);
- err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
+ err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1, buf, ctx, gfp);
if (err < 0) {
- if (rq->do_dma)
- virtnet_rq_unmap(rq, buf, 0);
+ virtnet_rq_unmap(rq, buf, 0);
put_page(virt_to_head_page(buf));
}
@@ -2706,7 +2888,7 @@ static int virtnet_receive_packets(struct virtnet_info *vi,
}
} else {
while (packets < budget &&
- (buf = virtnet_rq_get_buf(rq, &len, NULL)) != NULL) {
+ (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
receive_buf(vi, rq, buf, len, NULL, xdp_xmit, stats);
packets++;
}
@@ -2804,7 +2986,7 @@ static void virtnet_rx_dim_update(struct virtnet_info *vi, struct receive_queue
u64_stats_read(&rq->stats.bytes),
&cur_sample);
- net_dim(&rq->dim, cur_sample);
+ net_dim(&rq->dim, &cur_sample);
rq->packets_in_napi = 0;
}
@@ -2956,7 +3138,7 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
struct virtnet_info *vi = sq->vq->vdev->priv;
unsigned int index = vq2txq(sq->vq);
struct netdev_queue *txq;
- int opaque;
+ int opaque, xsk_done = 0;
bool done;
if (unlikely(is_xdp_raw_buffer_queue(vi, index))) {
@@ -2968,7 +3150,11 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
txq = netdev_get_tx_queue(vi->dev, index);
__netif_tx_lock(txq, raw_smp_processor_id());
virtqueue_disable_cb(sq->vq);
- free_old_xmit(sq, txq, !!budget);
+
+ if (sq->xsk_pool)
+ xsk_done = virtnet_xsk_xmit(sq, sq->xsk_pool, budget);
+ else
+ free_old_xmit(sq, txq, !!budget);
if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) {
if (netif_tx_queue_stopped(txq)) {
@@ -2979,6 +3165,11 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
netif_tx_wake_queue(txq);
}
+ if (xsk_done >= budget) {
+ __netif_tx_unlock(txq);
+ return budget;
+ }
+
opaque = virtqueue_enable_cb_prepare(sq->vq);
done = napi_complete_done(napi, 0);
@@ -3046,8 +3237,9 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
return num_sg;
num_sg++;
}
- return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg,
- skb_to_ptr(skb, orphan), GFP_ATOMIC);
+
+ return virtnet_add_outbuf(sq, num_sg, skb,
+ orphan ? VIRTNET_XMIT_TYPE_SKB_ORPHAN : VIRTNET_XMIT_TYPE_SKB);
}
static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -3374,15 +3566,59 @@ static void virtnet_ack_link_announce(struct virtnet_info *vi)
dev_warn(&vi->dev->dev, "Failed to ack link announce.\n");
}
+static bool virtnet_commit_rss_command(struct virtnet_info *vi);
+
+static void virtnet_rss_update_by_qpairs(struct virtnet_info *vi, u16 queue_pairs)
+{
+ u32 indir_val = 0;
+ int i = 0;
+
+ for (; i < vi->rss_indir_table_size; ++i) {
+ indir_val = ethtool_rxfh_indir_default(i, queue_pairs);
+ vi->rss.indirection_table[i] = indir_val;
+ }
+ vi->rss.max_tx_vq = queue_pairs;
+}
+
static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
{
struct virtio_net_ctrl_mq *mq __free(kfree) = NULL;
- struct scatterlist sg;
+ struct virtio_net_ctrl_rss old_rss;
struct net_device *dev = vi->dev;
+ struct scatterlist sg;
if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
return 0;
+ /* Firstly check if we need update rss. Do updating if both (1) rss enabled and
+ * (2) no user configuration.
+ *
+ * During rss command processing, device updates queue_pairs using rss.max_tx_vq. That is,
+ * the device updates queue_pairs together with rss, so we can skip the sperate queue_pairs
+ * update (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET below) and return directly.
+ */
+ if (vi->has_rss && !netif_is_rxfh_configured(dev)) {
+ memcpy(&old_rss, &vi->rss, sizeof(old_rss));
+ if (rss_indirection_table_alloc(&vi->rss, vi->rss_indir_table_size)) {
+ vi->rss.indirection_table = old_rss.indirection_table;
+ return -ENOMEM;
+ }
+
+ virtnet_rss_update_by_qpairs(vi, queue_pairs);
+
+ if (!virtnet_commit_rss_command(vi)) {
+ /* restore ctrl_rss if commit_rss_command failed */
+ rss_indirection_table_free(&vi->rss);
+ memcpy(&vi->rss, &old_rss, sizeof(old_rss));
+
+ dev_warn(&dev->dev, "Fail to set num of queue pairs to %d, because committing RSS failed\n",
+ queue_pairs);
+ return -EINVAL;
+ }
+ rss_indirection_table_free(&old_rss);
+ goto succ;
+ }
+
mq = kzalloc(sizeof(*mq), GFP_KERNEL);
if (!mq)
return -ENOMEM;
@@ -3395,12 +3631,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
dev_warn(&dev->dev, "Fail to set num of queue pairs to %d\n",
queue_pairs);
return -EINVAL;
- } else {
- vi->curr_queue_pairs = queue_pairs;
- /* virtnet_open() will refill when device is going to up. */
- if (dev->flags & IFF_UP)
- schedule_delayed_work(&vi->refill, 0);
}
+succ:
+ vi->curr_queue_pairs = queue_pairs;
+ /* virtnet_open() will refill when device is going to up. */
+ if (dev->flags & IFF_UP)
+ schedule_delayed_work(&vi->refill, 0);
return 0;
}
@@ -3828,11 +4064,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
/* prepare sgs */
sg_init_table(sgs, 4);
- sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
+ sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
sg_set_buf(&sgs[0], &vi->rss, sg_buf_size);
- sg_buf_size = sizeof(uint16_t) * (vi->rss.indirection_table_mask + 1);
- sg_set_buf(&sgs[1], vi->rss.indirection_table, sg_buf_size);
+ if (vi->has_rss) {
+ sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
+ sg_set_buf(&sgs[1], vi->rss.indirection_table, sg_buf_size);
+ } else {
+ sg_set_buf(&sgs[1], &vi->rss.hash_cfg_reserved, sizeof(uint16_t));
+ }
sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
- offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
@@ -3856,21 +4096,14 @@ err:
static void virtnet_init_default_rss(struct virtnet_info *vi)
{
- u32 indir_val = 0;
- int i = 0;
-
vi->rss.hash_types = vi->rss_hash_types_supported;
vi->rss_hash_types_saved = vi->rss_hash_types_supported;
vi->rss.indirection_table_mask = vi->rss_indir_table_size
? vi->rss_indir_table_size - 1 : 0;
vi->rss.unclassified_queue = 0;
- for (; i < vi->rss_indir_table_size; ++i) {
- indir_val = ethtool_rxfh_indir_default(i, vi->curr_queue_pairs);
- vi->rss.indirection_table[i] = indir_val;
- }
+ virtnet_rss_update_by_qpairs(vi, vi->curr_queue_pairs);
- vi->rss.max_tx_vq = vi->has_rss ? vi->curr_queue_pairs : 0;
vi->rss.hash_key_length = vi->rss_key_size;
netdev_rss_key_fill(vi->rss.key, vi->rss_key_size);
@@ -5011,7 +5244,7 @@ static int virtnet_set_coalesce(struct net_device *dev,
struct netlink_ext_ack *extack)
{
struct virtnet_info *vi = netdev_priv(dev);
- int ret, queue_number, napi_weight;
+ int ret, queue_number, napi_weight, i;
bool update_napi = false;
/* Can't change NAPI weight if the link is up */
@@ -5040,6 +5273,14 @@ static int virtnet_set_coalesce(struct net_device *dev,
return ret;
if (update_napi) {
+ /* xsk xmit depends on the tx napi. So if xsk is active,
+ * prevent modifications to tx napi.
+ */
+ for (i = queue_number; i < vi->max_queue_pairs; i++) {
+ if (vi->sq[i].xsk_pool)
+ return -EBUSY;
+ }
+
for (; queue_number < vi->max_queue_pairs; queue_number++)
vi->sq[queue_number].napi.weight = napi_weight;
}
@@ -5488,6 +5729,29 @@ unreg:
return err;
}
+static int virtnet_sq_bind_xsk_pool(struct virtnet_info *vi,
+ struct send_queue *sq,
+ struct xsk_buff_pool *pool)
+{
+ int err, qindex;
+
+ qindex = sq - vi->sq;
+
+ virtnet_tx_pause(vi, sq);
+
+ err = virtqueue_reset(sq->vq, virtnet_sq_free_unused_buf);
+ if (err) {
+ netdev_err(vi->dev, "reset tx fail: tx queue index: %d err: %d\n", qindex, err);
+ pool = NULL;
+ }
+
+ sq->xsk_pool = pool;
+
+ virtnet_tx_resume(vi, sq);
+
+ return err;
+}
+
static int virtnet_xsk_pool_enable(struct net_device *dev,
struct xsk_buff_pool *pool,
u16 qid)
@@ -5496,6 +5760,7 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
struct receive_queue *rq;
struct device *dma_dev;
struct send_queue *sq;
+ dma_addr_t hdr_dma;
int err, size;
if (vi->hdr_len > xsk_pool_get_headroom(pool))
@@ -5533,6 +5798,11 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
if (!rq->xsk_buffs)
return -ENOMEM;
+ hdr_dma = virtqueue_dma_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len,
+ DMA_TO_DEVICE, 0);
+ if (virtqueue_dma_mapping_error(sq->vq, hdr_dma))
+ return -ENOMEM;
+
err = xsk_pool_dma_map(pool, dma_dev, 0);
if (err)
goto err_xsk_map;
@@ -5541,11 +5811,24 @@ static int virtnet_xsk_pool_enable(struct net_device *dev,
if (err)
goto err_rq;
+ err = virtnet_sq_bind_xsk_pool(vi, sq, pool);
+ if (err)
+ goto err_sq;
+
+ /* Now, we do not support tx offload(such as tx csum), so all the tx
+ * virtnet hdr is zero. So all the tx packets can share a single hdr.
+ */
+ sq->xsk_hdr_dma_addr = hdr_dma;
+
return 0;
+err_sq:
+ virtnet_rq_bind_xsk_pool(vi, rq, NULL);
err_rq:
xsk_pool_dma_unmap(pool, 0);
err_xsk_map:
+ virtqueue_dma_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len,
+ DMA_TO_DEVICE, 0);
return err;
}
@@ -5554,19 +5837,24 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
struct virtnet_info *vi = netdev_priv(dev);
struct xsk_buff_pool *pool;
struct receive_queue *rq;
+ struct send_queue *sq;
int err;
if (qid >= vi->curr_queue_pairs)
return -EINVAL;
+ sq = &vi->sq[qid];
rq = &vi->rq[qid];
pool = rq->xsk_pool;
err = virtnet_rq_bind_xsk_pool(vi, rq, NULL);
+ err |= virtnet_sq_bind_xsk_pool(vi, sq, NULL);
xsk_pool_dma_unmap(pool, 0);
+ virtqueue_dma_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr,
+ vi->hdr_len, DMA_TO_DEVICE, 0);
kvfree(rq->xsk_buffs);
return err;
@@ -5916,7 +6204,7 @@ static void free_receive_page_frags(struct virtnet_info *vi)
int i;
for (i = 0; i < vi->max_queue_pairs; i++)
if (vi->rq[i].alloc_frag.page) {
- if (vi->rq[i].do_dma && vi->rq[i].last_dma)
+ if (vi->rq[i].last_dma)
virtnet_rq_unmap(&vi->rq[i], vi->rq[i].last_dma, 0);
put_page(vi->rq[i].alloc_frag.page);
}
@@ -5924,10 +6212,26 @@ static void free_receive_page_frags(struct virtnet_info *vi)
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
{
- if (!is_xdp_frame(buf))
+ struct virtnet_info *vi = vq->vdev->priv;
+ struct send_queue *sq;
+ int i = vq2rxq(vq);
+
+ sq = &vi->sq[i];
+
+ switch (virtnet_xmit_ptr_unpack(&buf)) {
+ case VIRTNET_XMIT_TYPE_SKB:
+ case VIRTNET_XMIT_TYPE_SKB_ORPHAN:
dev_kfree_skb(buf);
- else
- xdp_return_frame(ptr_to_xdp(buf));
+ break;
+
+ case VIRTNET_XMIT_TYPE_XDP:
+ xdp_return_frame(buf);
+ break;
+
+ case VIRTNET_XMIT_TYPE_XSK:
+ xsk_tx_completed(sq->xsk_pool, 1);
+ break;
+ }
}
static void free_unused_bufs(struct virtnet_info *vi)
@@ -6375,7 +6679,8 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->hw_features |= NETIF_F_GRO_HW;
dev->vlan_features = dev->features;
- dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT;
+ dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
+ NETDEV_XDP_ACT_XSK_ZEROCOPY;
/* MTU range: 68 - 65535 */
dev->min_mtu = MIN_MTU;
@@ -6420,10 +6725,19 @@ static int virtnet_probe(struct virtio_device *vdev)
virtio_cread16(vdev, offsetof(struct virtio_net_config,
rss_max_indirection_table_length));
}
+ err = rss_indirection_table_alloc(&vi->rss, vi->rss_indir_table_size);
+ if (err)
+ goto free;
if (vi->has_rss || vi->has_rss_hash_report) {
vi->rss_key_size =
virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
+ if (vi->rss_key_size > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
+ dev_err(&vdev->dev, "rss_max_key_size=%u exceeds the limit %u.\n",
+ vi->rss_key_size, VIRTIO_NET_RSS_MAX_KEY_SIZE);
+ err = -EINVAL;
+ goto free;
+ }
vi->rss_hash_types_supported =
virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
@@ -6551,6 +6865,15 @@ static int virtnet_probe(struct virtio_device *vdev)
virtio_device_ready(vdev);
+ if (vi->has_rss || vi->has_rss_hash_report) {
+ if (!virtnet_commit_rss_command(vi)) {
+ dev_warn(&vdev->dev, "RSS disabled because committing failed.\n");
+ dev->hw_features &= ~NETIF_F_RXHASH;
+ vi->has_rss_hash_report = false;
+ vi->has_rss = false;
+ }
+ }
+
virtnet_set_queues(vi, vi->curr_queue_pairs);
/* a random MAC address has been assigned, notify the device.
@@ -6674,6 +6997,8 @@ static void virtnet_remove(struct virtio_device *vdev)
remove_vq_common(vi);
+ rss_indirection_table_free(&vi->rss);
+
free_netdev(vi->dev);
}
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 4087f72f0d2b..67d25f4f94ef 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -521,7 +521,7 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
/* needed to match OIF rule */
fl4.flowi4_l3mdev = vrf_dev->ifindex;
fl4.flowi4_iif = LOOPBACK_IFINDEX;
- fl4.flowi4_tos = ip4h->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h));
fl4.flowi4_flags = FLOWI_FLAG_ANYSRC;
fl4.flowi4_proto = ip4h->protocol;
fl4.daddr = ip4h->daddr;
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 841b59d1c1c2..9ea63059d52d 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1232,10 +1232,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
*ifindex = 0;
}
- if (tb[NDA_NH_ID])
- *nhid = nla_get_u32(tb[NDA_NH_ID]);
- else
- *nhid = 0;
+ *nhid = nla_get_u32_default(tb[NDA_NH_ID], 0);
return 0;
}
@@ -1244,7 +1241,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid, u16 flags,
- struct netlink_ext_ack *extack)
+ bool *notified, struct netlink_ext_ack *extack)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
/* struct net *net = dev_net(vxlan->dev); */
@@ -1280,6 +1277,9 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
nhid, true, extack);
spin_unlock_bh(&vxlan->hash_lock[hash_index]);
+ if (!err)
+ *notified = true;
+
return err;
}
@@ -1319,7 +1319,7 @@ out:
/* Delete entry (via netlink) */
static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
- const unsigned char *addr, u16 vid,
+ const unsigned char *addr, u16 vid, bool *notified,
struct netlink_ext_ack *extack)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -1341,6 +1341,9 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
true);
spin_unlock_bh(&vxlan->hash_lock[hash_index]);
+ if (!err)
+ *notified = true;
+
return err;
}
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
index f0441b3d7dcb..db9f9ebcb62d 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -837,12 +837,12 @@ static void ath10k_ahb_remove(struct platform_device *pdev)
}
static struct platform_driver ath10k_ahb_driver = {
- .driver = {
- .name = "ath10k_ahb",
+ .driver = {
+ .name = "ath10k_ahb",
.of_match_table = ath10k_ahb_of_match,
},
- .probe = ath10k_ahb_probe,
- .remove_new = ath10k_ahb_remove,
+ .probe = ath10k_ahb_probe,
+ .remove = ath10k_ahb_remove,
};
int ath10k_ahb_init(void)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 646e1737d4c4..c61b95a928da 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6369,7 +6369,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
struct cfg80211_scan_request *req = &hw_req->req;
- struct wmi_start_scan_arg arg;
+ struct wmi_start_scan_arg *arg = NULL;
int ret = 0;
int i;
u32 scan_timeout;
@@ -6402,56 +6402,61 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
if (ret)
goto exit;
- memset(&arg, 0, sizeof(arg));
- ath10k_wmi_start_scan_init(ar, &arg);
- arg.vdev_id = arvif->vdev_id;
- arg.scan_id = ATH10K_SCAN_ID;
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ath10k_wmi_start_scan_init(ar, arg);
+ arg->vdev_id = arvif->vdev_id;
+ arg->scan_id = ATH10K_SCAN_ID;
if (req->ie_len) {
- arg.ie_len = req->ie_len;
- memcpy(arg.ie, req->ie, arg.ie_len);
+ arg->ie_len = req->ie_len;
+ memcpy(arg->ie, req->ie, arg->ie_len);
}
if (req->n_ssids) {
- arg.n_ssids = req->n_ssids;
- for (i = 0; i < arg.n_ssids; i++) {
- arg.ssids[i].len = req->ssids[i].ssid_len;
- arg.ssids[i].ssid = req->ssids[i].ssid;
+ arg->n_ssids = req->n_ssids;
+ for (i = 0; i < arg->n_ssids; i++) {
+ arg->ssids[i].len = req->ssids[i].ssid_len;
+ arg->ssids[i].ssid = req->ssids[i].ssid;
}
} else {
- arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
+ arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
}
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
- arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ;
- ether_addr_copy(arg.mac_addr.addr, req->mac_addr);
- ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask);
+ arg->scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ;
+ ether_addr_copy(arg->mac_addr.addr, req->mac_addr);
+ ether_addr_copy(arg->mac_mask.addr, req->mac_addr_mask);
}
if (req->n_channels) {
- arg.n_channels = req->n_channels;
- for (i = 0; i < arg.n_channels; i++)
- arg.channels[i] = req->channels[i]->center_freq;
+ arg->n_channels = req->n_channels;
+ for (i = 0; i < arg->n_channels; i++)
+ arg->channels[i] = req->channels[i]->center_freq;
}
/* if duration is set, default dwell times will be overwritten */
if (req->duration) {
- arg.dwell_time_active = req->duration;
- arg.dwell_time_passive = req->duration;
- arg.burst_duration_ms = req->duration;
+ arg->dwell_time_active = req->duration;
+ arg->dwell_time_passive = req->duration;
+ arg->burst_duration_ms = req->duration;
- scan_timeout = min_t(u32, arg.max_rest_time *
- (arg.n_channels - 1) + (req->duration +
+ scan_timeout = min_t(u32, arg->max_rest_time *
+ (arg->n_channels - 1) + (req->duration +
ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) *
- arg.n_channels, arg.max_scan_time);
+ arg->n_channels, arg->max_scan_time);
} else {
- scan_timeout = arg.max_scan_time;
+ scan_timeout = arg->max_scan_time;
}
/* Add a 200ms margin to account for event/command processing */
scan_timeout += 200;
- ret = ath10k_start_scan(ar, &arg);
+ ret = ath10k_start_scan(ar, arg);
if (ret) {
ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
@@ -6463,6 +6468,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
msecs_to_jiffies(scan_timeout));
exit:
+ kfree(arg);
+
mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -7899,7 +7906,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
- struct wmi_start_scan_arg arg;
+ struct wmi_start_scan_arg *arg = NULL;
int ret = 0;
u32 scan_time_msec;
@@ -7936,20 +7943,25 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
- memset(&arg, 0, sizeof(arg));
- ath10k_wmi_start_scan_init(ar, &arg);
- arg.vdev_id = arvif->vdev_id;
- arg.scan_id = ATH10K_SCAN_ID;
- arg.n_channels = 1;
- arg.channels[0] = chan->center_freq;
- arg.dwell_time_active = scan_time_msec;
- arg.dwell_time_passive = scan_time_msec;
- arg.max_scan_time = scan_time_msec;
- arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
- arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
- arg.burst_duration_ms = duration;
-
- ret = ath10k_start_scan(ar, &arg);
+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+ if (!arg) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ath10k_wmi_start_scan_init(ar, arg);
+ arg->vdev_id = arvif->vdev_id;
+ arg->scan_id = ATH10K_SCAN_ID;
+ arg->n_channels = 1;
+ arg->channels[0] = chan->center_freq;
+ arg->dwell_time_active = scan_time_msec;
+ arg->dwell_time_passive = scan_time_msec;
+ arg->max_scan_time = scan_time_msec;
+ arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE;
+ arg->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ;
+ arg->burst_duration_ms = duration;
+
+ ret = ath10k_start_scan(ar, arg);
if (ret) {
ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
spin_lock_bh(&ar->data_lock);
@@ -7975,6 +7987,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
ret = 0;
exit:
+ kfree(arg);
+
mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -8507,9 +8521,10 @@ exit:
static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
@@ -9121,7 +9136,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[
{6, {2633, 2925}, {1215, 1350}, {585, 650} },
{7, {2925, 3250}, {1350, 1500}, {650, 722} },
{8, {3510, 3900}, {1620, 1800}, {780, 867} },
- {9, {3900, 4333}, {1800, 2000}, {780, 867} }
+ {9, {3900, 4333}, {1800, 2000}, {865, 960} }
};
/*MCS parameters with Nss = 2 */
@@ -9136,7 +9151,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[
{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
- {9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
+ {9, {7800, 8667}, {3600, 4000}, {1730, 1920} }
};
static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs,
@@ -9450,7 +9465,7 @@ static const struct ieee80211_ops ath10k_ops = {
.reconfig_complete = ath10k_reconfig_complete,
.get_survey = ath10k_get_survey,
.set_bitrate_mask = ath10k_mac_op_set_bitrate_mask,
- .sta_rc_update = ath10k_sta_rc_update,
+ .link_sta_rc_update = ath10k_sta_rc_update,
.offset_tsf = ath10k_offset_tsf,
.ampdu_action = ath10k_ampdu_action,
.get_et_sset_count = ath10k_debug_get_et_sset_count,
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 08a6f36a6be9..6805357ee29e 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -3,7 +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.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -2648,9 +2648,9 @@ static void ath10k_sdio_remove(struct sdio_func *func)
netif_napi_del(&ar->napi);
- ath10k_core_destroy(ar);
-
destroy_workqueue(ar_sdio->workqueue);
+
+ ath10k_core_destroy(ar);
}
static const struct sdio_device_id ath10k_sdio_devices[] = {
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index 0fe47d51013c..d436a874cd5a 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -1885,11 +1885,11 @@ static void ath10k_snoc_shutdown(struct platform_device *pdev)
}
static struct platform_driver ath10k_snoc_driver = {
- .probe = ath10k_snoc_probe,
- .remove_new = ath10k_snoc_remove,
+ .probe = ath10k_snoc_probe,
+ .remove = ath10k_snoc_remove,
.shutdown = ath10k_snoc_shutdown,
.driver = {
- .name = "ath10k_snoc",
+ .name = "ath10k_snoc",
.of_match_table = ath10k_snoc_dt_match,
},
};
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index dbaf26d6a7a6..16d07d619b4d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3043,9 +3043,14 @@ ath10k_wmi_tlv_op_cleanup_mgmt_tx_send(struct ath10k *ar,
struct sk_buff *msdu)
{
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
+ struct ath10k_mgmt_tx_pkt_addr *pkt_addr;
struct ath10k_wmi *wmi = &ar->wmi;
- idr_remove(&wmi->mgmt_pending_tx, cb->msdu_id);
+ spin_lock_bh(&ar->data_lock);
+ pkt_addr = idr_remove(&wmi->mgmt_pending_tx, cb->msdu_id);
+ spin_unlock_bh(&ar->data_lock);
+
+ kfree(pkt_addr);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 4861179b2217..5e061f7525a6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2441,6 +2441,7 @@ wmi_process_mgmt_tx_comp(struct ath10k *ar, struct mgmt_tx_compl_params *param)
dma_unmap_single(ar->dev, pkt_addr->paddr,
msdu->len, DMA_TO_DEVICE);
info = IEEE80211_SKB_CB(msdu);
+ kfree(pkt_addr);
if (param->status) {
info->flags &= ~IEEE80211_TX_STAT_ACK;
@@ -9612,6 +9613,7 @@ static int ath10k_wmi_mgmt_tx_clean_up_pending(int msdu_id, void *ptr,
dma_unmap_single(ar->dev, pkt_addr->paddr,
msdu->len, DMA_TO_DEVICE);
ieee80211_free_txskb(ar->hw, msdu);
+ kfree(pkt_addr);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 97b12f51ef28..f2fc04596d48 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -1000,18 +1000,18 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
if (!ab->hw_params.fixed_fw_mem)
return 0;
- ret = ath11k_ahb_setup_msa_resources(ab);
- if (ret) {
- ath11k_err(ab, "failed to setup msa resources\n");
- return ret;
- }
-
node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
if (!node) {
ab_ahb->fw.use_tz = true;
return 0;
}
+ ret = ath11k_ahb_setup_msa_resources(ab);
+ if (ret) {
+ ath11k_err(ab, "failed to setup msa resources\n");
+ return ret;
+ }
+
info.fwnode = &node->fwnode;
info.parent = host_dev;
info.name = node->name;
@@ -1313,12 +1313,12 @@ free_resources:
}
static struct platform_driver ath11k_ahb_driver = {
- .driver = {
- .name = "ath11k",
+ .driver = {
+ .name = "ath11k",
.of_match_table = ath11k_ahb_of_match,
},
- .probe = ath11k_ahb_probe,
- .remove_new = ath11k_ahb_remove,
+ .probe = ath11k_ahb_probe,
+ .remove = ath11k_ahb_remove,
.shutdown = ath11k_ahb_shutdown,
};
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index ccf4ad35fdc3..be67382c00f6 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -616,7 +616,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_dynamic_smps_6ghz = false,
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
- .fw_wmi_diag_event = false,
+ .fw_wmi_diag_event = true,
.current_cc_support = true,
.dbr_debug_support = false,
.global_reset = false,
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index c087d8a0f5b2..40088e62572e 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -5291,8 +5291,11 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
hal_status == HAL_TLV_STATUS_PPDU_DONE) {
rx_mon_stats->status_ppdu_done++;
pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
- ath11k_dp_rx_mon_dest_process(ar, mac_id, budget, napi);
- pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+ if (!ab->hw_params.full_monitor_mode) {
+ ath11k_dp_rx_mon_dest_process(ar, mac_id,
+ budget, napi);
+ pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+ }
}
if (ppdu_info->peer_id == HAL_INVALID_PEERID ||
diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c
index f02599bd1c36..61f4b6dd5380 100644
--- a/drivers/net/wireless/ath/ath11k/hal.c
+++ b/drivers/net/wireless/ath/ath11k/hal.c
@@ -1351,6 +1351,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab)
ath11k_hal_free_cont_rdp(ab);
ath11k_hal_free_cont_wrp(ab);
kfree(hal->srng_config);
+ hal->srng_config = NULL;
}
EXPORT_SYMBOL(ath11k_hal_srng_deinit);
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index f8068d2e848c..e6acbff06749 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -5079,9 +5079,10 @@ static void ath11k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct ath11k *ar = hw->priv;
struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
@@ -9708,7 +9709,7 @@ static const struct ieee80211_ops ath11k_ops = {
.sta_state = ath11k_mac_op_sta_state,
.sta_set_4addr = ath11k_mac_op_sta_set_4addr,
.sta_set_txpwr = ath11k_mac_op_sta_set_txpwr,
- .sta_rc_update = ath11k_mac_op_sta_rc_update,
+ .link_sta_rc_update = ath11k_mac_op_sta_rc_update,
.conf_tx = ath11k_mac_op_conf_tx,
.set_antenna = ath11k_mac_op_set_antenna,
.get_antenna = ath11k_mac_op_get_antenna,
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index f477afd325de..7a22483b35cd 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2180,6 +2180,9 @@ static int ath11k_qmi_request_device_info(struct ath11k_base *ab)
ab->mem = bar_addr_va;
ab->mem_len = resp.bar_size;
+ if (!ab->hw_params.ce_remap)
+ ab->mem_ce = ab->mem;
+
return 0;
out:
return ret;
diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c
index 99d8ba45a75b..827085a926b2 100644
--- a/drivers/net/wireless/ath/ath11k/wow.c
+++ b/drivers/net/wireless/ath/ath11k/wow.c
@@ -1,7 +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.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/delay.h>
@@ -155,6 +155,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
u8 hdr_8023_bit_mask[ETH_HLEN] = {};
u8 hdr_80211_pattern[WOW_HDR_LEN] = {};
u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};
+ u8 bytemask[WOW_MAX_PATTERN_SIZE] = {};
int total_len = old->pkt_offset + old->pattern_len;
int hdr_80211_end_offset;
@@ -172,11 +173,17 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
struct rfc1042_hdr *new_rfc_mask =
(struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);
int rfc_len = sizeof(*new_rfc_pattern);
+ int i;
+
+ /* convert bitmask to bytemask */
+ for (i = 0; i < old->pattern_len; i++)
+ if (old->mask[i / 8] & BIT(i % 8))
+ bytemask[i] = 0xff;
memcpy(hdr_8023_pattern + old->pkt_offset,
old->pattern, ETH_HLEN - old->pkt_offset);
memcpy(hdr_8023_bit_mask + old->pkt_offset,
- old->mask, ETH_HLEN - old->pkt_offset);
+ bytemask, ETH_HLEN - old->pkt_offset);
/* Copy destination address */
memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);
@@ -232,7 +239,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
(void *)old->pattern + ETH_HLEN - old->pkt_offset,
total_len - ETH_HLEN);
memcpy((u8 *)new->mask + new->pattern_len,
- (void *)old->mask + ETH_HLEN - old->pkt_offset,
+ bytemask + ETH_HLEN - old->pkt_offset,
total_len - ETH_HLEN);
new->pattern_len += total_len - ETH_HLEN;
@@ -393,35 +400,31 @@ static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif,
}
for (i = 0; i < wowlan->n_patterns; i++) {
- u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};
u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};
struct cfg80211_pkt_pattern new_pattern = {};
- struct cfg80211_pkt_pattern old_pattern = patterns[i];
- int j;
new_pattern.pattern = ath_pattern;
new_pattern.mask = ath_bitmask;
if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
continue;
- /* convert bytemask to bitmask */
- for (j = 0; j < patterns[i].pattern_len; j++)
- if (patterns[i].mask[j / 8] & BIT(j % 8))
- bitmask[j] = 0xff;
- old_pattern.mask = bitmask;
if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode ==
ATH11K_HW_TXRX_NATIVE_WIFI) {
if (patterns[i].pkt_offset < ETH_HLEN) {
- u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {};
-
- memcpy(pattern_ext, old_pattern.pattern,
- old_pattern.pattern_len);
- old_pattern.pattern = pattern_ext;
ath11k_wow_convert_8023_to_80211(&new_pattern,
- &old_pattern);
+ &patterns[i]);
} else {
- new_pattern = old_pattern;
+ int j;
+
+ new_pattern = patterns[i];
+ new_pattern.mask = ath_bitmask;
+
+ /* convert bitmask to bytemask */
+ for (j = 0; j < patterns[i].pattern_len; j++)
+ if (patterns[i].mask[j / 8] & BIT(j % 8))
+ ath_bitmask[j] = 0xff;
+
new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
}
}
diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index f64e7c322216..52a1bb19e3da 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -42,3 +42,13 @@ config ATH12K_TRACING
If unsure, say Y to make it easier to debug problems. But if
you want optimal performance choose N.
+
+config ATH12K_COREDUMP
+ bool "ath12k coredump"
+ depends on ATH12K
+ select WANT_DEV_COREDUMP
+ help
+ Enable ath12k coredump collection
+
+ If unsure, say Y to make it easier to debug problems. But if
+ dump collection not required choose N.
diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index 5a1ed20d730e..b5bb3e2599cd 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -27,6 +27,7 @@ ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o
ath12k-$(CONFIG_ACPI) += acpi.o
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
ath12k-$(CONFIG_PM) += wow.o
+ath12k-$(CONFIG_ATH12K_COREDUMP) += coredump.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h
index 857bc5f9e946..1a14b9fb86b8 100644
--- a/drivers/net/wireless/ath/ath12k/ce.h
+++ b/drivers/net/wireless/ath/ath12k/ce.h
@@ -148,7 +148,7 @@ struct ath12k_ce_pipe {
void (*send_cb)(struct ath12k_ce_pipe *pipe);
void (*recv_cb)(struct ath12k_base *ab, struct sk_buff *skb);
- struct tasklet_struct intr_tq;
+ struct work_struct intr_wq;
struct ath12k_ce_ring *src_ring;
struct ath12k_ce_ring *dest_ring;
struct ath12k_ce_ring *status_ring;
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 51252e8bc1ae..c57322221e1d 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1004,7 +1004,7 @@ void ath12k_core_halt(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ar->num_created_vdevs = 0;
ar->allocated_vdev_map = 0;
@@ -1078,6 +1078,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
if (!ah || ah->state == ATH12K_HW_STATE_OFF)
continue;
+ wiphy_lock(ah->hw->wiphy);
mutex_lock(&ah->hw_mutex);
switch (ah->state) {
@@ -1086,10 +1087,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
for (j = 0; j < ah->num_radio; j++) {
ar = &ah->radio[j];
-
- mutex_lock(&ar->conf_mutex);
ath12k_core_halt(ar);
- mutex_unlock(&ar->conf_mutex);
}
break;
@@ -1110,6 +1108,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
}
mutex_unlock(&ah->hw_mutex);
+ wiphy_unlock(ah->hw->wiphy);
}
complete(&ab->driver_recovery);
@@ -1188,6 +1187,7 @@ static void ath12k_core_reset(struct work_struct *work)
ab->is_reset = true;
atomic_set(&ab->recovery_count, 0);
+ ath12k_coredump_collect(ab);
ath12k_core_pre_reconfigure_recovery(ab);
ath12k_core_post_reconfigure_recovery(ab);
@@ -1312,6 +1312,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
INIT_WORK(&ab->restart_work, ath12k_core_restart);
INIT_WORK(&ab->reset_work, ath12k_core_reset);
INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
+ INIT_WORK(&ab->dump_work, ath12k_coredump_upload);
timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
init_completion(&ab->htc_suspend);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 7f2e9a9b4097..3bf31ee5b9fa 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -30,6 +30,7 @@
#include "acpi.h"
#include "wow.h"
#include "debugfs_htt_stats.h"
+#include "coredump.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -94,6 +95,14 @@ static inline enum wme_ac ath12k_tid_to_ac(u32 tid)
WME_AC_VO);
}
+static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo)
+{
+ u64 hi64 = le32_to_cpu(hi);
+ u64 lo64 = le32_to_cpu(lo);
+
+ return (hi64 << 32) | lo64;
+}
+
enum ath12k_skb_flags {
ATH12K_SKB_HW_80211_ENCAP = BIT(0),
ATH12K_SKB_CIPHER_SET = BIT(1),
@@ -220,8 +229,9 @@ struct ath12k_tx_conf {
};
struct ath12k_key_conf {
- bool changed;
enum set_key_cmd cmd;
+ struct list_head list;
+ struct ieee80211_sta *sta;
struct ieee80211_key_conf *key;
};
@@ -238,10 +248,8 @@ struct ath12k_rekey_data {
bool enable_offload;
};
-struct ath12k_vif {
+struct ath12k_link_vif {
u32 vdev_id;
- enum wmi_vdev_type vdev_type;
- enum wmi_vdev_subtype vdev_subtype;
u32 beacon_interval;
u32 dtim_period;
u16 ast_hash;
@@ -251,13 +259,38 @@ struct ath12k_vif {
u8 search_type;
struct ath12k *ar;
- struct ieee80211_vif *vif;
int bank_id;
u8 vdev_id_check_en;
struct wmi_wmm_params_all_arg wmm_params;
struct list_head list;
+
+ bool is_created;
+ bool is_started;
+ bool is_up;
+ u8 bssid[ETH_ALEN];
+ struct cfg80211_bitrate_mask bitrate_mask;
+ struct delayed_work connection_loss_work;
+ int num_legacy_stations;
+ int rtscts_prot_mode;
+ int txpower;
+ bool rsnie_present;
+ bool wpaie_present;
+ struct ieee80211_chanctx_conf chanctx;
+ u8 vdev_stats_id;
+ u32 punct_bitmap;
+ u8 link_id;
+ struct ath12k_vif *ahvif;
+ struct ath12k_rekey_data rekey_data;
+};
+
+struct ath12k_vif {
+ enum wmi_vdev_type vdev_type;
+ enum wmi_vdev_subtype vdev_subtype;
+ struct ieee80211_vif *vif;
+ struct ath12k_hw *ah;
+
union {
struct {
u32 uapsd;
@@ -275,25 +308,16 @@ struct ath12k_vif {
} ap;
} u;
- bool is_created;
- bool is_started;
- bool is_up;
u32 aid;
- u8 bssid[ETH_ALEN];
- struct cfg80211_bitrate_mask bitrate_mask;
- struct delayed_work connection_loss_work;
- int num_legacy_stations;
- int rtscts_prot_mode;
- int txpower;
- bool rsnie_present;
- bool wpaie_present;
u32 key_cipher;
u8 tx_encap_type;
- u8 vdev_stats_id;
- u32 punct_bitmap;
bool ps;
- struct ath12k_vif_cache *cache;
- struct ath12k_rekey_data rekey_data;
+
+ struct ath12k_link_vif deflink;
+ struct ath12k_link_vif __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS];
+ /* indicates bitmap of link vif created in FW */
+ u16 links_map;
/* Must be last - ends in a flexible-array member.
*
@@ -306,7 +330,7 @@ struct ath12k_vif {
struct ath12k_vif_iter {
u32 vdev_id;
struct ath12k *ar;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
};
#define HAL_AST_IDX_INVALID 0xFFFF
@@ -441,27 +465,36 @@ struct ath12k_wbm_tx_stats {
u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX];
};
-struct ath12k_sta {
- struct ath12k_vif *arvif;
+struct ath12k_link_sta {
+ struct ath12k_link_vif *arvif;
+ struct ath12k_sta *ahsta;
/* the following are protected by ar->data_lock */
u32 changed; /* IEEE80211_RC_* */
u32 bw;
u32 nss;
u32 smps;
- enum hal_pn_type pn_type;
- struct work_struct update_wk;
+ struct wiphy_work update_wk;
struct rate_info txrate;
struct rate_info last_txrate;
u64 rx_duration;
u64 tx_duration;
u8 rssi_comb;
+ u8 link_id;
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_wbm_tx_stats *wbm_tx_stats;
u32 bw_prev;
};
+struct ath12k_sta {
+ enum hal_pn_type pn_type;
+ struct ath12k_link_sta deflink;
+ struct ath12k_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
+ /* indicates bitmap of link sta created in FW */
+ u16 links_map;
+};
+
#define ATH12K_MIN_5G_FREQ 4150
#define ATH12K_MIN_6G_FREQ 5925
#define ATH12K_MAX_6G_FREQ 7115
@@ -561,13 +594,9 @@ struct ath12k {
u32 chan_tx_pwr;
u32 num_stations;
u32 max_num_stations;
- bool monitor_present;
- /* To synchronize concurrent synchronous mac80211 callback operations,
- * concurrent debugfs configuration and concurrent FW statistics events.
- */
- struct mutex conf_mutex;
+
/* protects the radio specific data like debug stats, ppdu_stats_info stats,
- * vdev_stop_status info, scan data, ath12k_sta info, ath12k_vif info,
+ * vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info,
* channel context data, survey info, test mode data.
*/
spinlock_t data_lock;
@@ -666,6 +695,7 @@ struct ath12k_hw {
enum ath12k_hw_state state;
bool regd_updated;
bool use_6ghz_regd;
+
u8 num_radio;
/* Keep last */
@@ -782,6 +812,10 @@ struct ath12k_base {
/* HW channel counters frequency value in hertz common to all MACs */
u32 cc_freq_hz;
+ struct ath12k_dump_file_data *dump_data;
+ size_t ath12k_coredump_len;
+ struct work_struct dump_work;
+
struct ath12k_htc htc;
struct ath12k_dp dp;
@@ -1024,16 +1058,26 @@ static inline struct ath12k_skb_rxcb *ATH12K_SKB_RXCB(struct sk_buff *skb)
return (struct ath12k_skb_rxcb *)skb->cb;
}
-static inline struct ath12k_vif *ath12k_vif_to_arvif(struct ieee80211_vif *vif)
+static inline struct ath12k_vif *ath12k_vif_to_ahvif(struct ieee80211_vif *vif)
{
return (struct ath12k_vif *)vif->drv_priv;
}
-static inline struct ath12k_sta *ath12k_sta_to_arsta(struct ieee80211_sta *sta)
+static inline struct ath12k_sta *ath12k_sta_to_ahsta(struct ieee80211_sta *sta)
{
return (struct ath12k_sta *)sta->drv_priv;
}
+static inline struct ieee80211_sta *ath12k_ahsta_to_sta(struct ath12k_sta *ahsta)
+{
+ return container_of((void *)ahsta, struct ieee80211_sta, drv_priv);
+}
+
+static inline struct ieee80211_vif *ath12k_ahvif_to_vif(struct ath12k_vif *ahvif)
+{
+ return container_of((void *)ahvif, struct ieee80211_vif, drv_priv);
+}
+
static inline struct ath12k *ath12k_ab_to_ar(struct ath12k_base *ab,
int mac_id)
{
diff --git a/drivers/net/wireless/ath/ath12k/coredump.c b/drivers/net/wireless/ath/ath12k/coredump.c
new file mode 100644
index 000000000000..72d675d15e64
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/coredump.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/devcoredump.h>
+#include "hif.h"
+#include "coredump.h"
+#include "debug.h"
+
+enum
+ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type(enum ath12k_qmi_target_mem type)
+{
+ enum ath12k_fw_crash_dump_type dump_type;
+
+ switch (type) {
+ case HOST_DDR_REGION_TYPE:
+ dump_type = FW_CRASH_DUMP_REMOTE_MEM_DATA;
+ break;
+ case M3_DUMP_REGION_TYPE:
+ dump_type = FW_CRASH_DUMP_M3_DUMP;
+ break;
+ case PAGEABLE_MEM_REGION_TYPE:
+ dump_type = FW_CRASH_DUMP_PAGEABLE_DATA;
+ break;
+ case BDF_MEM_REGION_TYPE:
+ case CALDB_MEM_REGION_TYPE:
+ dump_type = FW_CRASH_DUMP_NONE;
+ break;
+ default:
+ dump_type = FW_CRASH_DUMP_TYPE_MAX;
+ break;
+ }
+
+ return dump_type;
+}
+
+void ath12k_coredump_upload(struct work_struct *work)
+{
+ struct ath12k_base *ab = container_of(work, struct ath12k_base, dump_work);
+
+ ath12k_info(ab, "Uploading coredump\n");
+ /* dev_coredumpv() takes ownership of the buffer */
+ dev_coredumpv(ab->dev, ab->dump_data, ab->ath12k_coredump_len, GFP_KERNEL);
+ ab->dump_data = NULL;
+}
+
+void ath12k_coredump_collect(struct ath12k_base *ab)
+{
+ ath12k_hif_coredump_download(ab);
+}
diff --git a/drivers/net/wireless/ath/ath12k/coredump.h b/drivers/net/wireless/ath/ath12k/coredump.h
new file mode 100644
index 000000000000..5d6003b1c12d
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/coredump.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#ifndef _ATH12K_COREDUMP_H_
+#define _ATH12K_COREDUMP_H_
+
+#define ATH12K_FW_CRASH_DUMP_V2 2
+
+enum ath12k_fw_crash_dump_type {
+ FW_CRASH_DUMP_PAGING_DATA,
+ FW_CRASH_DUMP_RDDM_DATA,
+ FW_CRASH_DUMP_REMOTE_MEM_DATA,
+ FW_CRASH_DUMP_PAGEABLE_DATA,
+ FW_CRASH_DUMP_M3_DUMP,
+ FW_CRASH_DUMP_NONE,
+
+ /* keep last */
+ FW_CRASH_DUMP_TYPE_MAX,
+};
+
+#define COREDUMP_TLV_HDR_SIZE 8
+
+struct ath12k_tlv_dump_data {
+ /* see ath11k_fw_crash_dump_type above */
+ __le32 type;
+
+ /* in bytes */
+ __le32 tlv_len;
+
+ /* pad to 32-bit boundaries as needed */
+ u8 tlv_data[];
+} __packed;
+
+struct ath12k_dump_file_data {
+ /* "ATH12K-FW-DUMP" */
+ char df_magic[16];
+ /* total dump len in bytes */
+ __le32 len;
+ /* file dump version */
+ __le32 version;
+ /* pci device id */
+ __le32 chip_id;
+ /* qrtr instance id */
+ __le32 qrtr_id;
+ /* pci domain id */
+ __le32 bus_id;
+ guid_t guid;
+ /* time-of-day stamp */
+ __le64 tv_sec;
+ /* time-of-day stamp, nano-seconds */
+ __le64 tv_nsec;
+ /* room for growth w/out changing binary format */
+ u8 unused[128];
+ u8 data[];
+} __packed;
+
+#ifdef CONFIG_ATH12K_COREDUMP
+enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type
+ (enum ath12k_qmi_target_mem type);
+void ath12k_coredump_upload(struct work_struct *work);
+void ath12k_coredump_collect(struct ath12k_base *ab);
+#else
+static inline enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type
+ (enum ath12k_qmi_target_mem type)
+{
+ return FW_CRASH_DUMP_TYPE_MAX;
+}
+
+static inline void ath12k_coredump_upload(struct work_struct *work)
+{
+}
+
+static inline void ath12k_coredump_collect(struct ath12k_base *ab)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index 2a977c36af00..d4b32d1a431c 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -15,14 +15,14 @@ static ssize_t ath12k_write_simulate_radar(struct file *file,
struct ath12k *ar = file->private_data;
int ret;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
ret = ath12k_wmi_simulate_radar(ar);
if (ret)
goto exit;
ret = count;
exit:
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index f1b7e74aefe4..c9980c0193d1 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -12,8 +12,8 @@
#include "dp_rx.h"
static u32
-print_array_to_buf(u8 *buf, u32 offset, const char *header,
- const __le32 *array, u32 array_len, const char *footer)
+print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_index,
+ const __le32 *array, u32 array_len, const char *footer)
{
int index = 0;
u8 i;
@@ -26,7 +26,7 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header,
for (i = 0; i < array_len; i++) {
index += scnprintf(buf + offset + index,
(ATH12K_HTT_STATS_BUF_SIZE - offset) - index,
- " %u:%u,", i, le32_to_cpu(array[i]));
+ " %u:%u,", stats_index++, le32_to_cpu(array[i]));
}
/* To overwrite the last trailing comma */
index--;
@@ -40,6 +40,54 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header,
return index;
}
+static u32
+print_array_to_buf(u8 *buf, u32 offset, const char *header,
+ const __le32 *array, u32 array_len, const char *footer)
+{
+ return print_array_to_buf_index(buf, offset, header, 0, array, array_len,
+ footer);
+}
+
+static const char *ath12k_htt_be_tx_rx_ru_size_to_str(u8 ru_size)
+{
+ switch (ru_size) {
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26:
+ return "26";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52:
+ return "52";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26:
+ return "52+26";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106:
+ return "106";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26:
+ return "106+26";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242:
+ return "242";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484:
+ return "484";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242:
+ return "484+242";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996:
+ return "996";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484:
+ return "996+484";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242:
+ return "996+484+242";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2:
+ return "996x2";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484:
+ return "996x2+484";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3:
+ return "996x3";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484:
+ return "996x3+484";
+ case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4:
+ return "996x4";
+ default:
+ return "unknown";
+ }
+}
+
static void
htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf, u16 tag_len,
struct debug_htt_stats_req *stats_req)
@@ -1447,6 +1495,1207 @@ ath12k_htt_print_tx_de_compl_stats_tlv(const void *tag_buf, u16 tag_len,
stats_req->buf_len = len;
}
+static void
+ath12k_htt_print_tx_selfgen_cmn_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_cmn_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word);
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID));
+ len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n",
+ le32_to_cpu(htt_stats_buf->su_bar));
+ len += scnprintf(buf + len, buf_len - len, "rts = %u\n",
+ le32_to_cpu(htt_stats_buf->rts));
+ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n",
+ le32_to_cpu(htt_stats_buf->cts2self));
+ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n",
+ le32_to_cpu(htt_stats_buf->qos_null));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_1 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_1));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_2 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_2));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_3 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_3));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_4 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_4));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_5 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_5));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_6 = %u\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_6));
+ len += scnprintf(buf + len, buf_len - len, "delayed_bar_7 = %u\n\n",
+ le32_to_cpu(htt_stats_buf->delayed_bar_7));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ac_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_ac_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_su_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_su_ndp));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp));
+ len += print_array_to_buf_index(buf, len, "ac_mu_mimo_brpollX_tried = ", 1,
+ htt_stats_buf->ac_mu_mimo_brpoll,
+ ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS, "\n\n");
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ax_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_ax_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_su_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_su_ndp));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp));
+ len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpollX_tried = ", 1,
+ htt_stats_buf->ax_mu_mimo_brpoll,
+ ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n");
+ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_basic_trigger));
+ len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger));
+ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_bsr_trigger));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_be_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_be_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_queued = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndpa_queued));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndp_queued = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndp_queued));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndp));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_queued = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_queued));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_queued = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_queued));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp));
+ len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_queued = ", 1,
+ htt_stats_buf->be_mu_mimo_brpoll_queued,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1,
+ "\n");
+ len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_tried = ", 1,
+ htt_stats_buf->be_mu_mimo_brpoll,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1,
+ "\n");
+ len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger = ",
+ htt_stats_buf->be_ul_mumimo_trigger,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n");
+ len += scnprintf(buf + len, buf_len - len, "be_basic_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->be_basic_trigger));
+ len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger));
+ len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->be_bsr_trigger));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_bar_trigger));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger = %u\n\n",
+ le32_to_cpu(htt_stats_buf->be_mu_rts_trigger));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_ac_err_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_su_ndp_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_su_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp1_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp2_err));
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n\n",
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp3_err));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_ax_err_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_su_ndp_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_su_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp_err));
+ len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpX_err", 1,
+ htt_stats_buf->ax_mu_mimo_brp_err,
+ ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1,
+ "\n");
+ len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_basic_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_bsr_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n\n",
+ le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger_err));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_be_err_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_selfgen_be_err_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_ERR_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndp_err));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndp_flushed = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndp_flushed));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_flushed = %u\n",
+ le32_to_cpu(htt_stats_buf->be_su_ndpa_flushed));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_err));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_flushed = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_flushed));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_err));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_flushed = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_flushed));
+ len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpX_err", 1,
+ htt_stats_buf->be_mu_mimo_brp_err,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1,
+ "\n");
+ len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_flushed", 1,
+ htt_stats_buf->be_mu_mimo_brpoll_flushed,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1,
+ "\n");
+ len += print_array_to_buf(buf, len, "be_mu_mimo_num_cbf_rcvd_on_brp_err",
+ htt_stats_buf->be_mu_mimo_brp_err_num_cbf_rxd,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger_err",
+ htt_stats_buf->be_ul_mumimo_trigger_err,
+ ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n");
+ len += scnprintf(buf + len, buf_len - len, "be_basic_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_basic_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trig_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_bsr_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger_err = %u\n",
+ le32_to_cpu(htt_stats_buf->be_mu_bar_trigger_err));
+ len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger_err = %u\n\n",
+ le32_to_cpu(htt_stats_buf->be_mu_rts_trigger_err));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats)
+{
+ const struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv *htt_stats_buf =
+ tag_buf;
+ u8 *buf = stats->buf;
+ u32 len = stats->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_SELFGEN_AC_SCHED_STATUS_STATS_TLV:\n");
+ len += print_array_to_buf(buf, len, "ac_su_ndpa_sch_status",
+ htt_stats_buf->ac_su_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ac_su_ndp_sch_status",
+ htt_stats_buf->ac_su_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ac_mu_mimo_ndpa_sch_status",
+ htt_stats_buf->ac_mu_mimo_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_status",
+ htt_stats_buf->ac_mu_mimo_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_status",
+ htt_stats_buf->ac_mu_mimo_brp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ac_su_ndp_sch_flag_err",
+ htt_stats_buf->ac_su_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_flag_err",
+ htt_stats_buf->ac_mu_mimo_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_flag_err",
+ htt_stats_buf->ac_mu_mimo_brp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n");
+
+ stats->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats)
+{
+ const struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv *htt_stats_buf =
+ tag_buf;
+ u8 *buf = stats->buf;
+ u32 len = stats->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_SELFGEN_AX_SCHED_STATUS_STATS_TLV:\n");
+ len += print_array_to_buf(buf, len, "ax_su_ndpa_sch_status",
+ htt_stats_buf->ax_su_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_su_ndp_sch_status",
+ htt_stats_buf->ax_su_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_mimo_ndpa_sch_status",
+ htt_stats_buf->ax_mu_mimo_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_status",
+ htt_stats_buf->ax_mu_mimo_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_brp_sch_status",
+ htt_stats_buf->ax_mu_brp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_bar_sch_status",
+ htt_stats_buf->ax_mu_bar_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_basic_trig_sch_status",
+ htt_stats_buf->ax_basic_trig_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_su_ndp_sch_flag_err",
+ htt_stats_buf->ax_su_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_flag_err",
+ htt_stats_buf->ax_mu_mimo_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_brp_sch_flag_err",
+ htt_stats_buf->ax_mu_brp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ax_mu_bar_sch_flag_err",
+ htt_stats_buf->ax_mu_bar_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ax_basic_trig_sch_flag_err",
+ htt_stats_buf->ax_basic_trig_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_status",
+ htt_stats_buf->ax_ulmumimo_trig_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_flag_err",
+ htt_stats_buf->ax_ulmumimo_trig_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n");
+
+ stats->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats)
+{
+ const struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv *htt_stats_buf =
+ tag_buf;
+ u8 *buf = stats->buf;
+ u32 len = stats->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_SELFGEN_BE_SCHED_STATUS_STATS_TLV:\n");
+ len += print_array_to_buf(buf, len, "be_su_ndpa_sch_status",
+ htt_stats_buf->be_su_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_su_ndp_sch_status",
+ htt_stats_buf->be_su_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_mimo_ndpa_sch_status",
+ htt_stats_buf->be_mu_mimo_ndpa_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_status",
+ htt_stats_buf->be_mu_mimo_ndp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_brp_sch_status",
+ htt_stats_buf->be_mu_brp_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_bar_sch_status",
+ htt_stats_buf->be_mu_bar_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_basic_trig_sch_status",
+ htt_stats_buf->be_basic_trig_sch_status,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_su_ndp_sch_flag_err",
+ htt_stats_buf->be_su_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_flag_err",
+ htt_stats_buf->be_mu_mimo_ndp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_brp_sch_flag_err",
+ htt_stats_buf->be_mu_brp_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_mu_bar_sch_flag_err",
+ htt_stats_buf->be_mu_bar_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err",
+ htt_stats_buf->be_basic_trig_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n");
+ len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err",
+ htt_stats_buf->be_basic_trig_sch_flag_err,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n");
+ len += print_array_to_buf(buf, len, "be_ulmumimo_trig_sch_flag_err",
+ htt_stats_buf->be_ulmumimo_trig_sch_flag_err,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n");
+
+ stats->buf_len = len;
+}
+
+static void
+ath12k_htt_print_stats_string_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_stats_string_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u8 i;
+ u16 index = 0;
+ u32 datum;
+ char data[ATH12K_HTT_MAX_STRING_LEN] = {0};
+
+ tag_len = tag_len >> 2;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n");
+ for (i = 0; i < tag_len; i++) {
+ datum = __le32_to_cpu(htt_stats_buf->data[i]);
+ index += scnprintf(&data[index], ATH12K_HTT_MAX_STRING_LEN - index,
+ "%.*s", 4, (char *)&datum);
+ if (index >= ATH12K_HTT_MAX_STRING_LEN)
+ break;
+ }
+ len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data);
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_sring_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_sring_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word;
+ u32 avail_words;
+ u32 head_tail_ptr;
+ u32 sring_stat;
+ u32 tail_ptr;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__ring_id__arena__ep);
+ avail_words = __le32_to_cpu(htt_stats_buf->num_avail_words__num_valid_words);
+ head_tail_ptr = __le32_to_cpu(htt_stats_buf->head_ptr__tail_ptr);
+ sring_stat = __le32_to_cpu(htt_stats_buf->consumer_empty__producer_full);
+ tail_ptr = __le32_to_cpu(htt_stats_buf->prefetch_count__internal_tail_ptr);
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_MAC_ID));
+ len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_RING_ID));
+ len += scnprintf(buf + len, buf_len - len, "arena = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_ARENA));
+ len += scnprintf(buf + len, buf_len - len, "ep = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_EP));
+ len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n",
+ le32_to_cpu(htt_stats_buf->base_addr_lsb));
+ len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n",
+ le32_to_cpu(htt_stats_buf->base_addr_msb));
+ len += scnprintf(buf + len, buf_len - len, "ring_size = %u\n",
+ le32_to_cpu(htt_stats_buf->ring_size));
+ len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n",
+ le32_to_cpu(htt_stats_buf->elem_size));
+ len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n",
+ u32_get_bits(avail_words,
+ ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS));
+ len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n",
+ u32_get_bits(avail_words,
+ ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS));
+ len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n",
+ u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_HEAD_PTR));
+ len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n",
+ u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_TAIL_PTR));
+ len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n",
+ u32_get_bits(sring_stat,
+ ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY));
+ len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n",
+ u32_get_bits(head_tail_ptr,
+ ATH12K_HTT_SRING_STATS_PRODUCER_FULL));
+ len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n",
+ u32_get_bits(tail_ptr, ATH12K_HTT_SRING_STATS_PREFETCH_COUNT));
+ len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n",
+ u32_get_bits(tail_ptr,
+ ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_sfm_cmn_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_sfm_cmn_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word);
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID));
+ len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_total));
+ len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n",
+ le32_to_cpu(htt_stats_buf->mem_empty));
+ len += scnprintf(buf + len, buf_len - len, "deallocate_bufs = %u\n",
+ le32_to_cpu(htt_stats_buf->deallocate_bufs));
+ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n",
+ le32_to_cpu(htt_stats_buf->num_records));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_sfm_client_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_sfm_client_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "client_id = %u\n",
+ le32_to_cpu(htt_stats_buf->client_id));
+ len += scnprintf(buf + len, buf_len - len, "buf_min = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_min));
+ len += scnprintf(buf + len, buf_len - len, "buf_max = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_max));
+ len += scnprintf(buf + len, buf_len - len, "buf_busy = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_busy));
+ len += scnprintf(buf + len, buf_len - len, "buf_alloc = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_alloc));
+ len += scnprintf(buf + len, buf_len - len, "buf_avail = %u\n",
+ le32_to_cpu(htt_stats_buf->buf_avail));
+ len += scnprintf(buf + len, buf_len - len, "num_users = %u\n\n",
+ le32_to_cpu(htt_stats_buf->num_users));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_sfm_client_user_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_sfm_client_user_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u16 num_elems = tag_len >> 2;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV:\n");
+ len += print_array_to_buf(buf, len, "dwords_used_by_user_n",
+ htt_stats_buf->dwords_used_by_user_n,
+ num_elems, "\n\n");
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u8 i;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_mimo_sch_posted));
+ len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_mimo_sch_failed));
+ len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n",
+ le32_to_cpu(htt_stats_buf->mu_mimo_ppdu_posted));
+ len += scnprintf(buf + len, buf_len - len,
+ "\nac_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0,
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[0]));
+ for (i = 1; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_sch_posted_per_group_index %u ", i);
+ len += scnprintf(buf + len, buf_len - len,
+ "(TOTAL STREAMS = %u) = %u\n", i + 1,
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[i]));
+ }
+
+ for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_sch_posted_per_group_index %u ",
+ i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS);
+ len += scnprintf(buf + len, buf_len - len,
+ "(TOTAL STREAMS = %u) = %u\n",
+ i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS + 1,
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_grp_sz_ext[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len,
+ "\nax_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0,
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[0]));
+ for (i = 1; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_sch_posted_per_group_index %u ", i);
+ len += scnprintf(buf + len, buf_len - len,
+ "(TOTAL STREAMS = %u) = %u\n", i + 1,
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len,
+ "\nbe_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0,
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[0]));
+ for (i = 1; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "be_mu_mimo_sch_posted_per_group_index %u ", i);
+ len += scnprintf(buf + len, buf_len - len,
+ "(TOTAL STREAMS = %u) = %u\n", i + 1,
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n11ac MU_MIMO SCH STATS:\n");
+ for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_sch_nusers_");
+ len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ac_mu_mimo_sch_nusers[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:\n");
+ for (i = 0; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_sch_nusers_");
+ len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_mu_mimo_sch_nusers[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n11be MU_MIMO SCH STATS:\n");
+ for (i = 0; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_sch_nusers_");
+ len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->be_mu_mimo_sch_nusers[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:\n");
+ for (i = 0; i < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ofdma_sch_nusers_%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ofdma_sch_nusers[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_ofdma_basic_sch_nusers_%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_ofdma_nusers[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_ofdma_bsr_sch_nusers_%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bsr_nusers[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_ofdma_bar_sch_nusers_%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bar_nusers[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_ofdma_brp_sch_nusers_%u = %u\n\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_ofdma_brp_nusers[i]));
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "11ax UL MUMIMO SCH STATS:\n");
+ for (i = 0; i < ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_mumimo_basic_sch_nusers_%u = %u\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_mumimo_nusers[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_ul_mumimo_brp_sch_nusers_%u = %u\n\n", i,
+ le32_to_cpu(htt_stats_buf->ax_ul_mumimo_brp_nusers[i]));
+ }
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ int j;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_MUMIMO_GRP_STATS:\n");
+ len += print_array_to_buf(buf, len,
+ "dl_mumimo_grp_tputs_observed (per bin = 300 mbps)",
+ htt_stats_buf->dl_mumimo_grp_tputs,
+ ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n");
+ len += print_array_to_buf(buf, len, "dl_mumimo_grp eligible",
+ htt_stats_buf->dl_mumimo_grp_eligible,
+ ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n");
+ len += print_array_to_buf(buf, len, "dl_mumimo_grp_ineligible",
+ htt_stats_buf->dl_mumimo_grp_ineligible,
+ ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n");
+ len += scnprintf(buf + len, buf_len - len, "dl_mumimo_grp_invalid:\n");
+ for (j = 0; j < ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ; j++) {
+ len += scnprintf(buf + len, buf_len - len, "grp_id = %u", j);
+ len += print_array_to_buf(buf, len, "",
+ htt_stats_buf->dl_mumimo_grp_invalid,
+ ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE,
+ "\n");
+ }
+
+ len += print_array_to_buf(buf, len, "ul_mumimo_grp_best_grp_size",
+ htt_stats_buf->ul_mumimo_grp_best_grp_size,
+ ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n");
+ len += print_array_to_buf_index(buf, len, "ul_mumimo_grp_best_num_usrs = ", 1,
+ htt_stats_buf->ul_mumimo_grp_best_usrs,
+ ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n");
+ len += print_array_to_buf(buf, len,
+ "ul_mumimo_grp_tputs_observed (per bin = 300 mbps)",
+ htt_stats_buf->ul_mumimo_grp_tputs,
+ ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n\n");
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_mpdu_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 user_index;
+ u32 tx_sched_mode;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ user_index = __le32_to_cpu(htt_stats_buf->user_index);
+ tx_sched_mode = __le32_to_cpu(htt_stats_buf->tx_sched_mode);
+
+ if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) {
+ if (!user_index)
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n");
+
+ if (user_index < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_mpdus_queued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_queued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_mpdus_tried_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_tried_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_mpdus_failed_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_failed_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_mpdus_requeued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_requeued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_err_no_ba_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->err_no_ba_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_mpdu_underrun_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdu_underrun_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->ampdu_underrun_usr));
+ }
+ }
+
+ if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) {
+ if (!user_index)
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n");
+
+ if (user_index < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_mpdus_queued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_queued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_mpdus_tried_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_tried_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_mpdus_failed_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_failed_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_mpdus_requeued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_requeued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_err_no_ba_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->err_no_ba_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_mpdu_underrun_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdu_underrun_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->ampdu_underrun_usr));
+ }
+ }
+
+ if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) {
+ if (!user_index)
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n");
+
+ if (user_index < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS) {
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_mpdus_queued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_queued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_mpdus_tried_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_tried_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_mpdus_failed_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_failed_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_mpdus_requeued_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdus_requeued_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_err_no_ba_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->err_no_ba_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_mpdu_underrun_usr_%u = %u\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->mpdu_underrun_usr));
+ len += scnprintf(buf + len, buf_len - len,
+ "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n\n",
+ user_index,
+ le32_to_cpu(htt_stats_buf->ampdu_underrun_usr));
+ }
+ }
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_pdev_cca_stats_hist_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_pdev_cca_stats_hist_v1_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_CCA_STATS_HIST_TLV :\n");
+ len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n",
+ le32_to_cpu(htt_stats_buf->chan_num));
+ len += scnprintf(buf + len, buf_len - len, "num_records = %u\n",
+ le32_to_cpu(htt_stats_buf->num_records));
+ len += scnprintf(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x\n",
+ le32_to_cpu(htt_stats_buf->valid_cca_counters_bitmap));
+ len += scnprintf(buf + len, buf_len - len, "collection_interval = %u\n\n",
+ le32_to_cpu(htt_stats_buf->collection_interval));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_pdev_stats_cca_counters_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_pdev_stats_cca_counters_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)\n");
+ len += scnprintf(buf + len, buf_len - len, "tx_frame_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->tx_frame_usec));
+ len += scnprintf(buf + len, buf_len - len, "rx_frame_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_frame_usec));
+ len += scnprintf(buf + len, buf_len - len, "rx_clear_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_clear_usec));
+ len += scnprintf(buf + len, buf_len - len, "my_rx_frame_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->my_rx_frame_usec));
+ len += scnprintf(buf + len, buf_len - len, "usec_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->usec_cnt));
+ len += scnprintf(buf + len, buf_len - len, "med_rx_idle_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->med_rx_idle_usec));
+ len += scnprintf(buf + len, buf_len - len, "med_tx_idle_global_usec = %u\n",
+ le32_to_cpu(htt_stats_buf->med_tx_idle_global_usec));
+ len += scnprintf(buf + len, buf_len - len, "cca_obss_usec = %u\n\n",
+ le32_to_cpu(htt_stats_buf->cca_obss_usec));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_pdev_obss_pd_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_pdev_obss_pd_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u8 i;
+ static const char *access_cat_names[ATH12K_HTT_NUM_AC_WMM] = {"best effort",
+ "background",
+ "video", "voice"};
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "num_spatial_reuse_tx = %u\n",
+ le32_to_cpu(htt_stats_buf->num_sr_tx_transmissions));
+ len += scnprintf(buf + len, buf_len - len,
+ "num_spatial_reuse_opportunities = %u\n",
+ le32_to_cpu(htt_stats_buf->num_spatial_reuse_opportunities));
+ len += scnprintf(buf + len, buf_len - len, "num_non_srg_opportunities = %u\n",
+ le32_to_cpu(htt_stats_buf->num_non_srg_opportunities));
+ len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_tried));
+ len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_success = %u\n",
+ le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_success));
+ len += scnprintf(buf + len, buf_len - len, "num_srg_opportunities = %u\n",
+ le32_to_cpu(htt_stats_buf->num_srg_opportunities));
+ len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->num_srg_ppdu_tried));
+ len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_success = %u\n",
+ le32_to_cpu(htt_stats_buf->num_srg_ppdu_success));
+ len += scnprintf(buf + len, buf_len - len, "num_psr_opportunities = %u\n",
+ le32_to_cpu(htt_stats_buf->num_psr_opportunities));
+ len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->num_psr_ppdu_tried));
+ len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_success = %u\n",
+ le32_to_cpu(htt_stats_buf->num_psr_ppdu_success));
+ len += scnprintf(buf + len, buf_len - len, "min_duration_check_flush_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->num_obss_min_dur_check_flush_cnt));
+ len += scnprintf(buf + len, buf_len - len, "sr_ppdu_abort_flush_cnt = %u\n\n",
+ le32_to_cpu(htt_stats_buf->num_sr_ppdu_abort_flush_cnt));
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_PER_AC_STATS:\n");
+ for (i = 0; i < ATH12K_HTT_NUM_AC_WMM; i++) {
+ len += scnprintf(buf + len, buf_len - len, "Access Category %u (%s)\n",
+ i, access_cat_names[i]);
+ len += scnprintf(buf + len, buf_len - len,
+ "num_non_srg_ppdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->num_non_srg_tried_per_ac[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "num_non_srg_ppdu_success = %u\n",
+ le32_to_cpu(htt_stats_buf->num_non_srg_success_ac[i]));
+ len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n",
+ le32_to_cpu(htt_stats_buf->num_srg_tried_per_ac[i]));
+ len += scnprintf(buf + len, buf_len - len,
+ "num_srg_ppdu_success = %u\n\n",
+ le32_to_cpu(htt_stats_buf->num_srg_success_per_ac[i]));
+ }
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_dmac_reset_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_dmac_reset_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u64 time;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_DMAC_RESET_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "reset_count = %u\n",
+ le32_to_cpu(htt_stats_buf->reset_count));
+ time = ath12k_le32hilo_to_u64(htt_stats_buf->reset_time_hi_ms,
+ htt_stats_buf->reset_time_lo_ms);
+ len += scnprintf(buf + len, buf_len - len, "reset_time_ms = %llu\n", time);
+
+ time = ath12k_le32hilo_to_u64(htt_stats_buf->disengage_time_hi_ms,
+ htt_stats_buf->disengage_time_lo_ms);
+ len += scnprintf(buf + len, buf_len - len, "disengage_time_ms = %llu\n", time);
+
+ time = ath12k_le32hilo_to_u64(htt_stats_buf->engage_time_hi_ms,
+ htt_stats_buf->engage_time_lo_ms);
+ len += scnprintf(buf + len, buf_len - len, "engage_time_ms = %llu\n", time);
+
+ len += scnprintf(buf + len, buf_len - len, "disengage_count = %u\n",
+ le32_to_cpu(htt_stats_buf->disengage_count));
+ len += scnprintf(buf + len, buf_len - len, "engage_count = %u\n",
+ le32_to_cpu(htt_stats_buf->engage_count));
+ len += scnprintf(buf + len, buf_len - len, "drain_dest_ring_mask = 0x%x\n\n",
+ le32_to_cpu(htt_stats_buf->drain_dest_ring_mask));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word);
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_SCHED_ALGO_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID));
+ len += print_array_to_buf(buf, len, "rate_based_dlofdma_enabled_count",
+ htt_stats_buf->rate_based_dlofdma_enabled_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "rate_based_dlofdma_disabled_count",
+ htt_stats_buf->rate_based_dlofdma_disabled_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "rate_based_dlofdma_probing_count",
+ htt_stats_buf->rate_based_dlofdma_disabled_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "rate_based_dlofdma_monitoring_count",
+ htt_stats_buf->rate_based_dlofdma_monitor_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_enabled_count",
+ htt_stats_buf->chan_acc_lat_based_dlofdma_enabled_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_disabled_count",
+ htt_stats_buf->chan_acc_lat_based_dlofdma_disabled_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_monitoring_count",
+ htt_stats_buf->chan_acc_lat_based_dlofdma_monitor_cnt,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "downgrade_to_dl_su_ru_alloc_fail",
+ htt_stats_buf->downgrade_to_dl_su_ru_alloc_fail,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "candidate_list_single_user_disable_ofdma",
+ htt_stats_buf->candidate_list_single_user_disable_ofdma,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "dl_cand_list_dropped_high_ul_qos_weight",
+ htt_stats_buf->dl_cand_list_dropped_high_ul_qos_weight,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "ax_dlofdma_disabled_due_to_pipelining",
+ htt_stats_buf->ax_dlofdma_disabled_due_to_pipelining,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "dlofdma_disabled_su_only_eligible",
+ htt_stats_buf->dlofdma_disabled_su_only_eligible,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_tried",
+ htt_stats_buf->dlofdma_disabled_consec_no_mpdus_tried,
+ ATH12K_HTT_NUM_AC_WMM, "\n");
+ len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_success",
+ htt_stats_buf->dlofdma_disabled_consec_no_mpdus_success,
+ ATH12K_HTT_NUM_AC_WMM, "\n\n");
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv *htt_stats_buf = tag_buf;
+ u8 *buf = stats_req->buf;
+ u32 len = stats_req->buf_len;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 mac_id_word;
+ u8 i;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "HTT_TX_PDEV_RATE_STATS_BE_OFDMA_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID));
+ len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ldpc = %u\n",
+ le32_to_cpu(htt_stats_buf->be_ofdma_tx_ldpc));
+ len += print_array_to_buf(buf, len, "be_ofdma_tx_mcs",
+ htt_stats_buf->be_ofdma_tx_mcs,
+ ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n");
+ len += print_array_to_buf(buf, len, "be_ofdma_eht_sig_mcs",
+ htt_stats_buf->be_ofdma_eht_sig_mcs,
+ ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS, "\n");
+ len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ru_size = ");
+ for (i = 0; i < ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS; i++)
+ len += scnprintf(buf + len, buf_len - len, " %s:%u ",
+ ath12k_htt_be_tx_rx_ru_size_to_str(i),
+ le32_to_cpu(htt_stats_buf->be_ofdma_tx_ru_size[i]));
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ len += print_array_to_buf_index(buf, len, "be_ofdma_tx_nss = ", 1,
+ htt_stats_buf->be_ofdma_tx_nss,
+ ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS,
+ "\n");
+ len += print_array_to_buf(buf, len, "be_ofdma_tx_bw",
+ htt_stats_buf->be_ofdma_tx_bw,
+ ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS, "\n");
+ for (i = 0; i < ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS; i++) {
+ len += scnprintf(buf + len, buf_len - len,
+ "be_ofdma_tx_gi[%u]", i);
+ len += print_array_to_buf(buf, len, "", htt_stats_buf->gi[i],
+ ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n");
+ }
+ len += scnprintf(buf + len, buf_len - len, "\n");
+
+ stats_req->buf_len = len;
+}
+
static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
u16 tag, u16 len, const void *tag_buf,
void *user_data)
@@ -1552,6 +2801,83 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_TX_DE_COMPL_STATS_TAG:
ath12k_htt_print_tx_de_compl_stats_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_TX_SELFGEN_CMN_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_cmn_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AC_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ac_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AX_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ax_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_BE_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_be_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_be_err_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(tag_buf, len,
+ stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(tag_buf, len,
+ stats_req);
+ break;
+ case HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG:
+ ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(tag_buf, len,
+ stats_req);
+ break;
+ case HTT_STATS_STRING_TAG:
+ ath12k_htt_print_stats_string_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_SRING_STATS_TAG:
+ ath12k_htt_print_sring_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_SFM_CMN_TAG:
+ ath12k_htt_print_sfm_cmn_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_SFM_CLIENT_TAG:
+ ath12k_htt_print_sfm_client_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_SFM_CLIENT_USER_TAG:
+ ath12k_htt_print_sfm_client_user_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG:
+ ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG:
+ ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_MPDU_STATS_TAG:
+ ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_PDEV_CCA_1SEC_HIST_TAG:
+ case HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG:
+ case HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG:
+ ath12k_htt_print_pdev_cca_stats_hist_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_PDEV_CCA_COUNTERS_TAG:
+ ath12k_htt_print_pdev_stats_cca_counters_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_PDEV_OBSS_PD_TAG:
+ ath12k_htt_print_pdev_obss_pd_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_DMAC_RESET_STATS_TAG:
+ ath12k_htt_print_dmac_reset_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG:
+ ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(tag_buf, len, stats_req);
+ break;
+ case HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG:
+ ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(tag_buf, len, stats_req);
+ break;
default:
break;
}
@@ -1627,9 +2953,9 @@ static ssize_t ath12k_read_htt_stats_type(struct file *file,
char buf[32];
size_t len;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
type = ar->debug.htt_stats.type;
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
len = scnprintf(buf, sizeof(buf), "%u\n", type);
@@ -1662,7 +2988,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file,
type >= ATH12K_DBG_HTT_NUM_EXT_STATS)
return -EINVAL;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
ar->debug.htt_stats.type = type;
ar->debug.htt_stats.cfg_param[0] = cfg_param[0];
@@ -1670,7 +2996,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file,
ar->debug.htt_stats.cfg_param[2] = cfg_param[2];
ar->debug.htt_stats.cfg_param[3] = cfg_param[3];
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return count;
}
@@ -1691,7 +3017,7 @@ static int ath12k_debugfs_htt_stats_req(struct ath12k *ar)
int ret, pdev_id;
struct htt_ext_stats_cfg_params cfg_params = { 0 };
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
init_completion(&stats_req->htt_stats_rcvd);
@@ -1741,7 +3067,7 @@ static int ath12k_open_htt_stats(struct inode *inode,
if (type == ATH12K_DBG_HTT_EXT_STATS_RESET)
return -EPERM;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
if (ah->state != ATH12K_HW_STATE_ON) {
ret = -ENETDOWN;
@@ -1776,14 +3102,14 @@ static int ath12k_open_htt_stats(struct inode *inode,
file->private_data = stats_req;
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return 0;
out:
kfree(stats_req);
ar->debug.htt_stats.stats_req = NULL;
err_unlock:
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return ret;
}
@@ -1793,10 +3119,10 @@ static int ath12k_release_htt_stats(struct inode *inode,
{
struct ath12k *ar = inode->i_private;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
kfree(file->private_data);
ar->debug.htt_stats.stats_req = NULL;
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return 0;
}
@@ -1840,7 +3166,7 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file,
type == ATH12K_DBG_HTT_EXT_STATS_RESET)
return -E2BIG;
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET;
param_pos = (type >> 5) + 1;
@@ -1866,12 +3192,12 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file,
0ULL);
if (ret) {
ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret);
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return ret;
}
ar->debug.htt_stats.reset = type;
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
return count;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index d52b26b23e65..ac86cab234ec 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -123,12 +123,21 @@ struct ath12k_htt_extd_stats_msg {
/* htt_dbg_ext_stats_type */
enum ath12k_dbg_htt_ext_stats_type {
- ATH12K_DBG_HTT_EXT_STATS_RESET = 0,
- ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
- ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
- ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
- ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
- ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
+ ATH12K_DBG_HTT_EXT_STATS_RESET = 0,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
+ ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
+ ATH12K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12,
+ ATH12K_DBG_HTT_EXT_STATS_SRNG_INFO = 15,
+ ATH12K_DBG_HTT_EXT_STATS_SFM_INFO = 16,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23,
+ ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49,
+ ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51,
/* keep this last */
ATH12K_DBG_HTT_NUM_EXT_STATS,
@@ -139,6 +148,7 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1,
HTT_STATS_TX_PDEV_SIFS_TAG = 2,
HTT_STATS_TX_PDEV_FLUSH_TAG = 3,
+ HTT_STATS_STRING_TAG = 5,
HTT_STATS_TX_TQM_GEN_MPDU_TAG = 11,
HTT_STATS_TX_TQM_LIST_MPDU_TAG = 12,
HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG = 13,
@@ -151,22 +161,47 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_TX_DE_ENQUEUE_PACKETS_TAG = 21,
HTT_STATS_TX_DE_ENQUEUE_DISCARD_TAG = 22,
HTT_STATS_TX_DE_CMN_TAG = 23,
+ HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG = 25,
+ HTT_STATS_SFM_CMN_TAG = 26,
+ HTT_STATS_SRING_STATS_TAG = 27,
HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36,
HTT_STATS_TX_SCHED_CMN_TAG = 37,
HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39,
+ HTT_STATS_SFM_CLIENT_USER_TAG = 41,
+ HTT_STATS_SFM_CLIENT_TAG = 42,
HTT_STATS_TX_TQM_ERROR_STATS_TAG = 43,
HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44,
+ HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG = 46,
+ HTT_STATS_TX_SELFGEN_CMN_STATS_TAG = 47,
+ HTT_STATS_TX_SELFGEN_AC_STATS_TAG = 48,
+ HTT_STATS_TX_SELFGEN_AX_STATS_TAG = 49,
+ HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG = 50,
HTT_STATS_HW_INTR_MISC_TAG = 54,
HTT_STATS_HW_PDEV_ERRS_TAG = 56,
HTT_STATS_TX_DE_COMPL_STATS_TAG = 65,
HTT_STATS_WHAL_TX_TAG = 66,
HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67,
+ HTT_STATS_PDEV_CCA_1SEC_HIST_TAG = 70,
+ HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG = 71,
+ HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG = 72,
+ HTT_STATS_PDEV_CCA_COUNTERS_TAG = 73,
+ HTT_STATS_TX_PDEV_MPDU_STATS_TAG = 74,
HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86,
HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87,
+ HTT_STATS_PDEV_OBSS_PD_TAG = 88,
HTT_STATS_HW_WAR_TAG = 89,
HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100,
HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102,
+ HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG = 111,
+ HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG = 112,
HTT_STATS_MU_PPDU_DIST_TAG = 129,
+ HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG = 130,
+ HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = 135,
+ HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137,
+ HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138,
+ HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139,
+ HTT_STATS_DMAC_RESET_STATS_TAG = 155,
+ HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165,
HTT_STATS_MAX_TAG,
};
@@ -690,4 +725,401 @@ struct ath12k_htt_tx_de_compl_stats_tlv {
__le32 tqm_bypass_frame;
} __packed;
+enum ath12k_htt_tx_mumimo_grp_invalid_reason_code_stats {
+ ATH12K_HTT_TX_MUMIMO_GRP_VALID,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NUM_MU_USERS_EXCEEDED_MU_MAX_USERS,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_SCHED_ALGO_NOT_MU_COMPATIBLE_GID,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NON_PRIMARY_GRP,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_ZERO_CANDIDATES,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MORE_CANDIDATES,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_SIZE_EXCEED_NSS,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_INELIGIBLE,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_EFF_MU_TPUT_OMBPS,
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE,
+};
+
+#define ATH12K_HTT_NUM_AC_WMM 0x4
+#define ATH12K_HTT_MAX_NUM_SBT_INTR 4
+#define ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS 4
+#define ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS 8
+#define ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS 8
+#define ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS 7
+#define ATH12K_HTT_TX_NUM_OFDMA_USER_STATS 74
+#define ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS 8
+#define ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ 8
+#define ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS 10
+
+#define ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE \
+ ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE
+#define ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS \
+ (ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ * ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE)
+
+struct ath12k_htt_tx_selfgen_cmn_stats_tlv {
+ __le32 mac_id__word;
+ __le32 su_bar;
+ __le32 rts;
+ __le32 cts2self;
+ __le32 qos_null;
+ __le32 delayed_bar_1;
+ __le32 delayed_bar_2;
+ __le32 delayed_bar_3;
+ __le32 delayed_bar_4;
+ __le32 delayed_bar_5;
+ __le32 delayed_bar_6;
+ __le32 delayed_bar_7;
+} __packed;
+
+struct ath12k_htt_tx_selfgen_ac_stats_tlv {
+ __le32 ac_su_ndpa;
+ __le32 ac_su_ndp;
+ __le32 ac_mu_mimo_ndpa;
+ __le32 ac_mu_mimo_ndp;
+ __le32 ac_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS - 1];
+} __packed;
+
+struct ath12k_htt_tx_selfgen_ax_stats_tlv {
+ __le32 ax_su_ndpa;
+ __le32 ax_su_ndp;
+ __le32 ax_mu_mimo_ndpa;
+ __le32 ax_mu_mimo_ndp;
+ __le32 ax_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1];
+ __le32 ax_basic_trigger;
+ __le32 ax_bsr_trigger;
+ __le32 ax_mu_bar_trigger;
+ __le32 ax_mu_rts_trigger;
+ __le32 ax_ulmumimo_trigger;
+} __packed;
+
+struct ath12k_htt_tx_selfgen_be_stats_tlv {
+ __le32 be_su_ndpa;
+ __le32 be_su_ndp;
+ __le32 be_mu_mimo_ndpa;
+ __le32 be_mu_mimo_ndp;
+ __le32 be_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1];
+ __le32 be_basic_trigger;
+ __le32 be_bsr_trigger;
+ __le32 be_mu_bar_trigger;
+ __le32 be_mu_rts_trigger;
+ __le32 be_ulmumimo_trigger;
+ __le32 be_su_ndpa_queued;
+ __le32 be_su_ndp_queued;
+ __le32 be_mu_mimo_ndpa_queued;
+ __le32 be_mu_mimo_ndp_queued;
+ __le32 be_mu_mimo_brpoll_queued[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1];
+ __le32 be_ul_mumimo_trigger[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
+} __packed;
+
+struct ath12k_htt_tx_selfgen_ac_err_stats_tlv {
+ __le32 ac_su_ndp_err;
+ __le32 ac_su_ndpa_err;
+ __le32 ac_mu_mimo_ndpa_err;
+ __le32 ac_mu_mimo_ndp_err;
+ __le32 ac_mu_mimo_brp1_err;
+ __le32 ac_mu_mimo_brp2_err;
+ __le32 ac_mu_mimo_brp3_err;
+} __packed;
+
+struct ath12k_htt_tx_selfgen_ax_err_stats_tlv {
+ __le32 ax_su_ndp_err;
+ __le32 ax_su_ndpa_err;
+ __le32 ax_mu_mimo_ndpa_err;
+ __le32 ax_mu_mimo_ndp_err;
+ __le32 ax_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1];
+ __le32 ax_basic_trigger_err;
+ __le32 ax_bsr_trigger_err;
+ __le32 ax_mu_bar_trigger_err;
+ __le32 ax_mu_rts_trigger_err;
+ __le32 ax_ulmumimo_trigger_err;
+} __packed;
+
+struct ath12k_htt_tx_selfgen_be_err_stats_tlv {
+ __le32 be_su_ndp_err;
+ __le32 be_su_ndpa_err;
+ __le32 be_mu_mimo_ndpa_err;
+ __le32 be_mu_mimo_ndp_err;
+ __le32 be_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1];
+ __le32 be_basic_trigger_err;
+ __le32 be_bsr_trigger_err;
+ __le32 be_mu_bar_trigger_err;
+ __le32 be_mu_rts_trigger_err;
+ __le32 be_ulmumimo_trigger_err;
+ __le32 be_mu_mimo_brp_err_num_cbf_rxd[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
+ __le32 be_su_ndpa_flushed;
+ __le32 be_su_ndp_flushed;
+ __le32 be_mu_mimo_ndpa_flushed;
+ __le32 be_mu_mimo_ndp_flushed;
+ __le32 be_mu_mimo_brpoll_flushed[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1];
+ __le32 be_ul_mumimo_trigger_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
+} __packed;
+
+enum ath12k_htt_tx_selfgen_sch_tsflag_error_stats {
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FLUSH_RCVD_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FILT_SCHED_CMD_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_MISMATCH_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_MIMO_CTRL_MISMATCH_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_BW_MISMATCH_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RETRY_COUNT_FAIL_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_TOO_LATE_RECEIVED_ERR,
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_SIFS_STALL_NO_NEXT_CMD_ERR,
+
+ ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS
+};
+
+struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv {
+ __le32 ac_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ac_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ac_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ac_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ac_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ac_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ac_mu_mimo_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ac_mu_mimo_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+} __packed;
+
+struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv {
+ __le32 ax_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ax_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ax_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ax_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ax_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 ax_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 ax_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+} __packed;
+
+struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv {
+ __le32 be_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 be_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 be_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 be_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 be_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+ __le32 be_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS];
+ __le32 be_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS];
+} __packed;
+
+struct ath12k_htt_stats_string_tlv {
+ DECLARE_FLEX_ARRAY(__le32, data);
+} __packed;
+
+#define ATH12K_HTT_SRING_STATS_MAC_ID GENMASK(7, 0)
+#define ATH12K_HTT_SRING_STATS_RING_ID GENMASK(15, 8)
+#define ATH12K_HTT_SRING_STATS_ARENA GENMASK(23, 16)
+#define ATH12K_HTT_SRING_STATS_EP BIT(24)
+#define ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS GENMASK(15, 0)
+#define ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS GENMASK(31, 16)
+#define ATH12K_HTT_SRING_STATS_HEAD_PTR GENMASK(15, 0)
+#define ATH12K_HTT_SRING_STATS_TAIL_PTR GENMASK(31, 16)
+#define ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY GENMASK(15, 0)
+#define ATH12K_HTT_SRING_STATS_PRODUCER_FULL GENMASK(31, 16)
+#define ATH12K_HTT_SRING_STATS_PREFETCH_COUNT GENMASK(15, 0)
+#define ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR GENMASK(31, 16)
+
+struct ath12k_htt_sring_stats_tlv {
+ __le32 mac_id__ring_id__arena__ep;
+ __le32 base_addr_lsb;
+ __le32 base_addr_msb;
+ __le32 ring_size;
+ __le32 elem_size;
+ __le32 num_avail_words__num_valid_words;
+ __le32 head_ptr__tail_ptr;
+ __le32 consumer_empty__producer_full;
+ __le32 prefetch_count__internal_tail_ptr;
+} __packed;
+
+struct ath12k_htt_sfm_cmn_tlv {
+ __le32 mac_id__word;
+ __le32 buf_total;
+ __le32 mem_empty;
+ __le32 deallocate_bufs;
+ __le32 num_records;
+} __packed;
+
+struct ath12k_htt_sfm_client_tlv {
+ __le32 client_id;
+ __le32 buf_min;
+ __le32 buf_max;
+ __le32 buf_busy;
+ __le32 buf_alloc;
+ __le32 buf_avail;
+ __le32 num_users;
+} __packed;
+
+struct ath12k_htt_sfm_client_user_tlv {
+ DECLARE_FLEX_ARRAY(__le32, dwords_used_by_user_n);
+} __packed;
+
+struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv {
+ __le32 mu_mimo_sch_posted;
+ __le32 mu_mimo_sch_failed;
+ __le32 mu_mimo_ppdu_posted;
+ __le32 ac_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS];
+ __le32 ax_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS];
+ __le32 ax_ofdma_sch_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS];
+ __le32 ax_ul_ofdma_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS];
+ __le32 ax_ul_ofdma_bsr_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS];
+ __le32 ax_ul_ofdma_bar_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS];
+ __le32 ax_ul_ofdma_brp_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS];
+ __le32 ax_ul_mumimo_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS];
+ __le32 ax_ul_mumimo_brp_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS];
+ __le32 ac_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS];
+ __le32 ax_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS];
+ __le32 be_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
+ __le32 be_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS];
+ __le32 ac_mu_mimo_grp_sz_ext[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS];
+} __packed;
+
+struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv {
+ __le32 dl_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ];
+ __le32 dl_mumimo_grp_best_num_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS];
+ __le32 dl_mumimo_grp_eligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ];
+ __le32 dl_mumimo_grp_ineligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ];
+ __le32 dl_mumimo_grp_invalid[ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS];
+ __le32 dl_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS];
+ __le32 ul_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ];
+ __le32 ul_mumimo_grp_best_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS];
+ __le32 ul_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS];
+} __packed;
+
+enum ath12k_htt_stats_tx_sched_modes {
+ ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC = 0,
+ ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX,
+ ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX,
+ ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_BE,
+ ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_BE
+};
+
+struct ath12k_htt_tx_pdev_mpdu_stats_tlv {
+ __le32 mpdus_queued_usr;
+ __le32 mpdus_tried_usr;
+ __le32 mpdus_failed_usr;
+ __le32 mpdus_requeued_usr;
+ __le32 err_no_ba_usr;
+ __le32 mpdu_underrun_usr;
+ __le32 ampdu_underrun_usr;
+ __le32 user_index;
+ __le32 tx_sched_mode;
+} __packed;
+
+struct ath12k_htt_pdev_stats_cca_counters_tlv {
+ __le32 tx_frame_usec;
+ __le32 rx_frame_usec;
+ __le32 rx_clear_usec;
+ __le32 my_rx_frame_usec;
+ __le32 usec_cnt;
+ __le32 med_rx_idle_usec;
+ __le32 med_tx_idle_global_usec;
+ __le32 cca_obss_usec;
+} __packed;
+
+struct ath12k_htt_pdev_cca_stats_hist_v1_tlv {
+ __le32 chan_num;
+ __le32 num_records;
+ __le32 valid_cca_counters_bitmap;
+ __le32 collection_interval;
+} __packed;
+
+struct ath12k_htt_pdev_obss_pd_stats_tlv {
+ __le32 num_obss_tx_ppdu_success;
+ __le32 num_obss_tx_ppdu_failure;
+ __le32 num_sr_tx_transmissions;
+ __le32 num_spatial_reuse_opportunities;
+ __le32 num_non_srg_opportunities;
+ __le32 num_non_srg_ppdu_tried;
+ __le32 num_non_srg_ppdu_success;
+ __le32 num_srg_opportunities;
+ __le32 num_srg_ppdu_tried;
+ __le32 num_srg_ppdu_success;
+ __le32 num_psr_opportunities;
+ __le32 num_psr_ppdu_tried;
+ __le32 num_psr_ppdu_success;
+ __le32 num_non_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM];
+ __le32 num_non_srg_success_ac[ATH12K_HTT_NUM_AC_WMM];
+ __le32 num_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM];
+ __le32 num_srg_success_per_ac[ATH12K_HTT_NUM_AC_WMM];
+ __le32 num_obss_min_dur_check_flush_cnt;
+ __le32 num_sr_ppdu_abort_flush_cnt;
+} __packed;
+
+struct ath12k_htt_dmac_reset_stats_tlv {
+ __le32 reset_count;
+ __le32 reset_time_lo_ms;
+ __le32 reset_time_hi_ms;
+ __le32 disengage_time_lo_ms;
+ __le32 disengage_time_hi_ms;
+ __le32 engage_time_lo_ms;
+ __le32 engage_time_hi_ms;
+ __le32 disengage_count;
+ __le32 engage_count;
+ __le32 drain_dest_ring_mask;
+} __packed;
+
+struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv {
+ __le32 mac_id__word;
+ __le32 rate_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 rate_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 rate_based_dlofdma_probing_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 rate_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 chan_acc_lat_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 chan_acc_lat_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 chan_acc_lat_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM];
+ __le32 downgrade_to_dl_su_ru_alloc_fail[ATH12K_HTT_NUM_AC_WMM];
+ __le32 candidate_list_single_user_disable_ofdma[ATH12K_HTT_NUM_AC_WMM];
+ __le32 dl_cand_list_dropped_high_ul_qos_weight[ATH12K_HTT_NUM_AC_WMM];
+ __le32 ax_dlofdma_disabled_due_to_pipelining[ATH12K_HTT_NUM_AC_WMM];
+ __le32 dlofdma_disabled_su_only_eligible[ATH12K_HTT_NUM_AC_WMM];
+ __le32 dlofdma_disabled_consec_no_mpdus_tried[ATH12K_HTT_NUM_AC_WMM];
+ __le32 dlofdma_disabled_consec_no_mpdus_success[ATH12K_HTT_NUM_AC_WMM];
+} __packed;
+
+enum ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE {
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484,
+ ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4,
+ ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS,
+};
+
+#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8
+#define ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS 16
+#define ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS 5
+#define ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS 4
+#define ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS 4
+
+struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv {
+ __le32 mac_id__word;
+ __le32 be_ofdma_tx_ldpc;
+ __le32 be_ofdma_tx_mcs[ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS];
+ __le32 be_ofdma_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+ __le32 be_ofdma_tx_bw[ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS];
+ __le32 gi[ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS][ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS];
+ __le32 be_ofdma_tx_ru_size[ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS];
+ __le32 be_ofdma_eht_sig_mcs[ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS];
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index 61aa78d8bd8c..c99e9ceb1a6e 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -327,20 +327,22 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring,
}
static
-u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif *arvif)
+u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
+ struct ath12k_link_vif *arvif)
{
u32 bank_config = 0;
+ struct ath12k_vif *ahvif = arvif->ahvif;
/* Only valid for raw frames with HW crypto enabled.
* With SW crypto, mac80211 sets key per packet
*/
- if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
+ if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
bank_config |=
- u32_encode_bits(ath12k_dp_tx_get_encrypt_type(arvif->key_cipher),
+ u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher),
HAL_TX_BANK_CONFIG_ENCRYPT_TYPE);
- bank_config |= u32_encode_bits(arvif->tx_encap_type,
+ bank_config |= u32_encode_bits(ahvif->tx_encap_type,
HAL_TX_BANK_CONFIG_ENCAP_TYPE);
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) |
u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) |
@@ -355,7 +357,7 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif
HAL_TX_ADDRY_EN),
HAL_TX_BANK_CONFIG_ADDRY_EN);
- bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(arvif->vif) ? 3 : 0,
+ bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0,
HAL_TX_BANK_CONFIG_MESH_EN) |
u32_encode_bits(arvif->vdev_id_check_en,
HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN);
@@ -365,7 +367,8 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif
return bank_config;
}
-static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, struct ath12k_vif *arvif,
+static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab,
+ struct ath12k_link_vif *arvif,
struct ath12k_dp *dp)
{
int bank_id = DP_INVALID_BANK_ID;
@@ -1099,9 +1102,9 @@ int ath12k_dp_htt_connect(struct ath12k_dp *dp)
return 0;
}
-static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif)
+static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif)
{
- switch (arvif->vdev_type) {
+ switch (arvif->ahvif->vdev_type) {
case WMI_VDEV_TYPE_STA:
/* TODO: Verify the search type and flags since ast hash
* is not part of peer mapv3
@@ -1120,7 +1123,7 @@ static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif)
}
}
-void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif)
+void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif)
{
struct ath12k_base *ab = ar->ab;
@@ -1162,7 +1165,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
spin_lock_bh(&dp->rx_desc_lock);
for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
- desc_info = dp->spt_info->rxbaddr[i];
+ desc_info = dp->rxbaddr[i];
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
if (!desc_info[j].in_use) {
@@ -1181,11 +1184,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
}
for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
- if (!dp->spt_info->rxbaddr[i])
+ if (!dp->rxbaddr[i])
continue;
- kfree(dp->spt_info->rxbaddr[i]);
- dp->spt_info->rxbaddr[i] = NULL;
+ kfree(dp->rxbaddr[i]);
+ dp->rxbaddr[i] = NULL;
}
spin_unlock_bh(&dp->rx_desc_lock);
@@ -1202,10 +1205,16 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
if (!skb)
continue;
- skb_cb = ATH12K_SKB_CB(skb);
- ar = skb_cb->ar;
- if (atomic_dec_and_test(&ar->dp.num_tx_pending))
- wake_up(&ar->dp.tx_empty_waitq);
+ /* if we are unregistering, hw would've been destroyed and
+ * ar is no longer valid.
+ */
+ if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) {
+ skb_cb = ATH12K_SKB_CB(skb);
+ ar = skb_cb->ar;
+
+ if (atomic_dec_and_test(&ar->dp.num_tx_pending))
+ wake_up(&ar->dp.tx_empty_waitq);
+ }
dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr,
skb->len, DMA_TO_DEVICE);
@@ -1220,11 +1229,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) {
tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
- if (!dp->spt_info->txbaddr[tx_spt_page])
+ if (!dp->txbaddr[tx_spt_page])
continue;
- kfree(dp->spt_info->txbaddr[tx_spt_page]);
- dp->spt_info->txbaddr[tx_spt_page] = NULL;
+ kfree(dp->txbaddr[tx_spt_page]);
+ dp->txbaddr[tx_spt_page] = NULL;
}
spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
@@ -1241,6 +1250,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
}
kfree(dp->spt_info);
+ dp->spt_info = NULL;
}
static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
@@ -1276,8 +1286,10 @@ void ath12k_dp_free(struct ath12k_base *ab)
ath12k_dp_rx_reo_cmd_list_cleanup(ab);
- for (i = 0; i < ab->hw_params->max_tx_ring; i++)
+ for (i = 0; i < ab->hw_params->max_tx_ring; i++) {
kfree(dp->tx_ring[i].tx_status);
+ dp->tx_ring[i].tx_status = NULL;
+ }
ath12k_dp_rx_free(ab);
/* Deinit any SOC level resource */
@@ -1415,7 +1427,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i;
cookie_ppt_idx = dp->rx_ppt_base + ppt_idx;
- dp->spt_info->rxbaddr[i] = &rx_descs[0];
+ dp->rxbaddr[i] = &rx_descs[0];
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j);
@@ -1445,7 +1457,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page;
- dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0];
+ dp->txbaddr[tx_spt_page] = &tx_descs[0];
for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j);
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 2fb18b83b3ee..2e05fc19410e 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -16,6 +16,7 @@ struct ath12k_base;
struct ath12k_peer;
struct ath12k_dp;
struct ath12k_vif;
+struct ath12k_link_vif;
struct hal_tcl_status_ring;
struct ath12k_ext_irq_grp;
@@ -300,8 +301,6 @@ struct ath12k_tx_desc_info {
struct ath12k_spt_info {
dma_addr_t paddr;
u64 *vaddr;
- struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES];
- struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES];
};
struct ath12k_reo_queue_ref {
@@ -352,6 +351,8 @@ struct ath12k_dp {
struct ath12k_spt_info *spt_info;
u32 num_spt_pages;
u32 rx_ppt_base;
+ struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES];
+ struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES];
struct list_head rx_desc_free_list;
/* protects the free desc list */
spinlock_t rx_desc_lock;
@@ -1799,7 +1800,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab,
struct ath12k_ext_irq_grp *irq_grp,
int budget);
int ath12k_dp_htt_connect(struct ath12k_dp *dp);
-void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif);
+void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif);
void ath12k_dp_free(struct ath12k_base *ab);
int ath12k_dp_alloc(struct ath12k_base *ab);
void ath12k_dp_cc_config(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index 5c6749bc4039..494984133a91 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -26,15 +26,12 @@ ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *st
void *ppduinfo,
struct hal_rx_user_status *rx_user_status)
{
- u32 mpdu_ok_byte_count = __le32_to_cpu(stats->mpdu_ok_cnt);
- u32 mpdu_err_byte_count = __le32_to_cpu(stats->mpdu_err_cnt);
-
rx_user_status->mpdu_ok_byte_count =
- u32_get_bits(mpdu_ok_byte_count,
- HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT);
+ le32_get_bits(stats->info7,
+ HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT);
rx_user_status->mpdu_err_byte_count =
- u32_get_bits(mpdu_err_byte_count,
- HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT);
+ le32_get_bits(stats->info8,
+ HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT);
}
static void
@@ -593,12 +590,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
struct hal_rx_ppdu_start *ppdu_start =
(struct hal_rx_ppdu_start *)tlv_data;
+ u64 ppdu_ts = ath12k_le32hilo_to_u64(ppdu_start->ppdu_start_ts_63_32,
+ ppdu_start->ppdu_start_ts_31_0);
+
info[0] = __le32_to_cpu(ppdu_start->info0);
- ppdu_info->ppdu_id =
- u32_get_bits(info[0], HAL_RX_PPDU_START_INFO0_PPDU_ID);
- ppdu_info->chan_num = __le32_to_cpu(ppdu_start->chan_num);
- ppdu_info->ppdu_ts = __le32_to_cpu(ppdu_start->ppdu_start_ts);
+ ppdu_info->ppdu_id = u32_get_bits(info[0],
+ HAL_RX_PPDU_START_INFO0_PPDU_ID);
+
+ info[1] = __le32_to_cpu(ppdu_start->info1);
+ ppdu_info->chan_num = u32_get_bits(info[1],
+ HAL_RX_PPDU_START_INFO1_CHAN_NUM);
+ ppdu_info->freq = u32_get_bits(info[1],
+ HAL_RX_PPDU_START_INFO1_CHAN_FREQ);
+ ppdu_info->ppdu_ts = ppdu_ts;
if (ppdu_info->ppdu_id != ppdu_info->last_ppdu_id) {
ppdu_info->last_ppdu_id = ppdu_info->ppdu_id;
@@ -726,33 +731,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
case HAL_PHYRX_RSSI_LEGACY: {
struct hal_rx_phyrx_rssi_legacy_info *rssi =
(struct hal_rx_phyrx_rssi_legacy_info *)tlv_data;
- u32 reception_type = 0;
- u32 rssi_legacy_info = __le32_to_cpu(rssi->rsvd[0]);
info[0] = __le32_to_cpu(rssi->info0);
+ info[1] = __le32_to_cpu(rssi->info1);
/* TODO: Please note that the combined rssi will not be accurate
* in MU case. Rssi in MU needs to be retrieved from
* PHYRX_OTHER_RECEIVE_INFO TLV.
*/
ppdu_info->rssi_comb =
- u32_get_bits(info[0],
- HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB);
- reception_type =
- u32_get_bits(rssi_legacy_info,
- HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION);
-
- switch (reception_type) {
- case HAL_RECEPTION_TYPE_ULOFMDA:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA;
- break;
- case HAL_RECEPTION_TYPE_ULMIMO:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
- break;
- default:
- ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
- break;
- }
+ u32_get_bits(info[1],
+ HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB);
+
+ ppdu_info->bw = u32_get_bits(info[0],
+ HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW);
break;
}
case HAL_RXPCU_PPDU_END_INFO: {
@@ -860,27 +852,29 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
}
-static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff *msdu)
+static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar,
+ struct sk_buff *head_msdu,
+ struct sk_buff *tail_msdu)
{
u32 rx_pkt_offset, l2_hdr_offset;
rx_pkt_offset = ar->ab->hal.hal_desc_sz;
- l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab,
- (struct hal_rx_desc *)msdu->data);
- skb_pull(msdu, rx_pkt_offset + l2_hdr_offset);
+ l2_hdr_offset =
+ ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)tail_msdu->data);
+ skb_pull(head_msdu, rx_pkt_offset + l2_hdr_offset);
}
static struct sk_buff *
-ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
- u32 mac_id, struct sk_buff *head_msdu,
+ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u32 mac_id,
+ struct sk_buff *head_msdu, struct sk_buff *tail_msdu,
struct ieee80211_rx_status *rxs, bool *fcs_err)
{
struct ath12k_base *ab = ar->ab;
- struct sk_buff *msdu, *mpdu_buf, *prev_buf;
- struct hal_rx_desc *rx_desc;
+ struct sk_buff *msdu, *mpdu_buf, *prev_buf, *head_frag_list;
+ struct hal_rx_desc *rx_desc, *tail_rx_desc;
u8 *hdr_desc, *dest, decap_format;
struct ieee80211_hdr_3addr *wh;
- u32 err_bitmap;
+ u32 err_bitmap, frag_list_sum_len = 0;
mpdu_buf = NULL;
@@ -888,24 +882,30 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
goto err_merge_fail;
rx_desc = (struct hal_rx_desc *)head_msdu->data;
- err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc);
+ tail_rx_desc = (struct hal_rx_desc *)tail_msdu->data;
+ err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, tail_rx_desc);
if (err_bitmap & HAL_RX_MPDU_ERR_FCS)
*fcs_err = true;
- decap_format = ath12k_dp_rx_h_decap_type(ab, rx_desc);
+ decap_format = ath12k_dp_rx_h_decap_type(ab, tail_rx_desc);
- ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
+ ath12k_dp_rx_h_ppdu(ar, tail_rx_desc, rxs);
if (decap_format == DP_RX_DECAP_TYPE_RAW) {
- ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu);
+ ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu);
prev_buf = head_msdu;
msdu = head_msdu->next;
+ head_frag_list = NULL;
while (msdu) {
- ath12k_dp_mon_rx_msdus_set_payload(ar, msdu);
+ ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu);
+
+ if (!head_frag_list)
+ head_frag_list = msdu;
+ frag_list_sum_len += msdu->len;
prev_buf = msdu;
msdu = msdu->next;
}
@@ -913,6 +913,12 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
prev_buf->next = NULL;
skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN);
+ if (head_frag_list) {
+ skb_shinfo(head_msdu)->frag_list = head_frag_list;
+ head_msdu->data_len = frag_list_sum_len;
+ head_msdu->len += head_msdu->data_len;
+ head_msdu->next = NULL;
+ }
} else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
u8 qos_pkt = 0;
@@ -929,7 +935,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar,
msdu = head_msdu;
while (msdu) {
- ath12k_dp_mon_rx_msdus_set_payload(ar, msdu);
+ ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu);
if (qos_pkt) {
dest = skb_push(msdu, sizeof(__le16));
if (!dest)
@@ -1135,7 +1141,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
}
static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id,
- struct sk_buff *head_msdu,
+ struct sk_buff *head_msdu, struct sk_buff *tail_msdu,
struct hal_rx_mon_ppdu_info *ppduinfo,
struct napi_struct *napi)
{
@@ -1144,7 +1150,8 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id,
struct ieee80211_rx_status *rxs = &dp->rx_status;
bool fcs_err = false;
- mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id, head_msdu,
+ mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id,
+ head_msdu, tail_msdu,
rxs, &fcs_err);
if (!mon_skb)
goto mon_deliver_fail;
@@ -1252,7 +1259,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
if (head_msdu && tail_msdu) {
ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu,
- ppdu_info, napi);
+ tail_msdu, ppdu_info, napi);
}
kfree(mon_mpdu);
@@ -1948,15 +1955,16 @@ ath12k_dp_mon_tx_process_ppdu_info(struct ath12k *ar, int mac_id,
struct dp_mon_tx_ppdu_info *tx_ppdu_info)
{
struct dp_mon_mpdu *tmp, *mon_mpdu;
- struct sk_buff *head_msdu;
+ struct sk_buff *head_msdu, *tail_msdu;
list_for_each_entry_safe(mon_mpdu, tmp,
&tx_ppdu_info->dp_tx_mon_mpdu_list, list) {
list_del(&mon_mpdu->list);
head_msdu = mon_mpdu->head;
+ tail_msdu = mon_mpdu->tail;
if (head_msdu)
- ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu,
+ ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, tail_msdu,
&tx_ppdu_info->rx_status, napi);
kfree(mon_mpdu);
@@ -2165,7 +2173,7 @@ ath12k_dp_mon_rx_update_peer_rate_table_stats(struct ath12k_rx_peer_stats *rx_st
}
static void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k *ar,
- struct ath12k_sta *arsta,
+ struct ath12k_link_sta *arsta,
struct hal_rx_mon_ppdu_info *ppdu_info)
{
struct ath12k_rx_peer_stats *rx_stats = arsta->rx_stats;
@@ -2321,7 +2329,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar,
struct hal_rx_mon_ppdu_info *ppdu_info,
u32 uid)
{
- struct ath12k_sta *arsta = NULL;
+ struct ath12k_sta *ahsta;
+ struct ath12k_link_sta *arsta;
struct ath12k_rx_peer_stats *rx_stats = NULL;
struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid];
struct ath12k_peer *peer;
@@ -2338,7 +2347,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar,
return;
}
- arsta = ath12k_sta_to_arsta(peer->sta);
+ ahsta = ath12k_sta_to_ahsta(peer->sta);
+ arsta = &ahsta->deflink;
rx_stats = arsta->rx_stats;
if (!rx_stats)
@@ -2445,7 +2455,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id,
struct dp_srng *mon_dst_ring;
struct hal_srng *srng;
struct dp_rxdma_mon_ring *buf_ring;
- struct ath12k_sta *arsta = NULL;
+ struct ath12k_sta *ahsta = NULL;
+ struct ath12k_link_sta *arsta;
struct ath12k_peer *peer;
u64 cookie;
int num_buffs_reaped = 0, srng_id, buf_id;
@@ -2514,7 +2525,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id,
}
if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) {
- arsta = ath12k_sta_to_arsta(peer->sta);
+ ahsta = ath12k_sta_to_ahsta(peer->sta);
+ arsta = &ahsta->deflink;
ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta,
ppdu_info);
} else if ((ppdu_info->fc_valid) &&
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 91e3393f7b5f..9ae579e50557 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1041,13 +1041,14 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params)
{
struct ath12k_base *ab = ar->ab;
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta);
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta);
+ struct ath12k_link_sta *arsta = &ahsta->deflink;
int vdev_id = arsta->arvif->vdev_id;
int ret;
ret = ath12k_dp_rx_peer_tid_setup(ar, params->sta->addr, vdev_id,
params->tid, params->buf_size,
- params->ssn, arsta->pn_type);
+ params->ssn, arsta->ahsta->pn_type);
if (ret)
ath12k_warn(ab, "failed to setup rx tid %d\n", ret);
@@ -1059,7 +1060,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
{
struct ath12k_base *ab = ar->ab;
struct ath12k_peer *peer;
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta);
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta);
+ struct ath12k_link_sta *arsta = &ahsta->deflink;
int vdev_id = arsta->arvif->vdev_id;
bool active;
int ret;
@@ -1091,7 +1093,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
return ret;
}
-int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif,
+int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
const u8 *peer_addr,
enum set_key_cmd key_cmd,
struct ieee80211_key_conf *key)
@@ -1313,7 +1315,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar,
struct ath12k_base *ab = ar->ab;
struct ath12k_peer *peer;
struct ieee80211_sta *sta;
- struct ath12k_sta *arsta;
+ struct ath12k_sta *ahsta;
+ struct ath12k_link_sta *arsta;
struct htt_ppdu_stats_user_rate *user_rate;
struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats;
struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user];
@@ -1394,7 +1397,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar,
}
sta = peer->sta;
- arsta = ath12k_sta_to_arsta(sta);
+ ahsta = ath12k_sta_to_ahsta(sta);
+ arsta = &ahsta->deflink;
memset(&arsta->txrate, 0, sizeof(arsta->txrate));
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index eb1f92559179..bfd4f814553e 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -88,7 +88,7 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params);
int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
struct ieee80211_ampdu_params *params);
-int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif,
+int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
const u8 *peer_addr,
enum set_key_cmd key_cmd,
struct ieee80211_key_conf *key);
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index 44406e0b4a34..a8d341a6df01 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -10,7 +10,7 @@
#include "hw.h"
static enum hal_tcl_encap_type
-ath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb)
+ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath12k_base *ab = arvif->ar->ab;
@@ -216,7 +216,7 @@ out:
return ret;
}
-int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
+int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct sk_buff *skb)
{
struct ath12k_base *ab = ar->ab;
@@ -230,6 +230,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
struct sk_buff *skb_ext_desc;
struct hal_srng *tcl_ring;
struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ath12k_vif *ahvif = arvif->ahvif;
struct dp_tx_ring *tx_ring;
u8 pool_id;
u8 hal_ring_id;
@@ -274,7 +275,7 @@ tcl_ring_sel:
ti.bank_id = arvif->bank_id;
ti.meta_data_flags = arvif->tcl_metadata;
- if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
+ if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) {
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
ti.encrypt_type =
@@ -376,7 +377,7 @@ map:
ti.desc_id = tx_desc->desc_id;
ti.data_len = skb->len;
skb_cb->paddr = ti.paddr;
- skb_cb->vif = arvif->vif;
+ skb_cb->vif = ahvif->vif;
skb_cb->ar = ar;
if (msdu_ext_desc) {
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h
index 55ff8cc721e3..46dce23501f3 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.h
@@ -16,7 +16,7 @@ struct ath12k_dp_htt_wbm_tx_status {
};
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
-int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
+int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct sk_buff *skb);
void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id);
diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index ca04bfae8bdc..fd98fac16dd5 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -385,13 +385,13 @@ static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.qcn9274.msdu_end.info12,
- RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP);
+ RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
}
static u8 ath12k_hw_qcn9274_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcn9274.msdu_end.info5,
- RX_MSDU_END_QCN9274_INFO5_TID);
+ RX_MSDU_END_INFO5_TID);
}
static u16 ath12k_hw_qcn9274_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
@@ -846,13 +846,13 @@ static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc
static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12,
- RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP);
+ RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
}
static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5,
- RX_MSDU_END_QCN9274_INFO5_TID);
+ RX_MSDU_END_INFO5_TID);
}
static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
@@ -1198,7 +1198,7 @@ static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
- RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP);
+ RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
}
static u8 ath12k_hw_wcn7850_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
@@ -1216,7 +1216,7 @@ static void ath12k_hw_wcn7850_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc,
struct hal_rx_desc *ldesc)
{
memcpy(&fdesc->u.wcn7850.msdu_end, &ldesc->u.wcn7850.msdu_end,
- sizeof(struct rx_msdu_end_wcn7850));
+ sizeof(struct rx_msdu_end_qcn9274));
}
static u32 ath12k_hw_wcn7850_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc)
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
index 095216eabc01..2de7b0eba9f2 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-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HAL_RX_H
@@ -156,6 +156,7 @@ struct hal_rx_mon_ppdu_info {
u32 preamble_type;
u32 mpdu_len;
u16 chan_num;
+ u16 freq;
u16 tcp_msdu_count;
u16 tcp_ack_msdu_count;
u16 udp_msdu_count;
@@ -232,21 +233,25 @@ struct hal_rx_mon_ppdu_info {
u8 medium_prot_type;
};
-#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0)
+#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0)
+#define HAL_RX_PPDU_START_INFO1_CHAN_NUM GENMASK(15, 0)
+#define HAL_RX_PPDU_START_INFO1_CHAN_FREQ GENMASK(31, 16)
struct hal_rx_ppdu_start {
__le32 info0;
- __le32 chan_num;
- __le32 ppdu_start_ts;
+ __le32 info1;
+ __le32 ppdu_start_ts_31_0;
+ __le32 ppdu_start_ts_63_32;
+ __le32 rsvd[2];
} __packed;
-#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(25, 16)
+#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(26, 16)
-#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(8, 0)
-#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(9)
-#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(10)
-#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(11)
-#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(23, 20)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(10, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(11)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(12)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(13)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(24, 21)
#define HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX GENMASK(15, 0)
#define HAL_RX_PPDU_END_USER_STATS_INFO2_FRAME_CTRL GENMASK(31, 16)
@@ -262,8 +267,8 @@ struct hal_rx_ppdu_start {
#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0)
#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16)
-#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT GENMASK(24, 0)
-#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT GENMASK(24, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT GENMASK(24, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0)
struct hal_rx_ppdu_end_user_stats {
__le32 rsvd0[2];
@@ -278,9 +283,9 @@ struct hal_rx_ppdu_end_user_stats {
__le32 usr_resp_ref;
__le32 info6;
__le32 rsvd3[4];
- __le32 mpdu_ok_cnt;
+ __le32 info7;
__le32 rsvd4;
- __le32 mpdu_err_cnt;
+ __le32 info8;
__le32 rsvd5[2];
__le32 usr_resp_ref_ext;
__le32 rsvd6;
@@ -436,23 +441,27 @@ enum hal_rx_ul_reception_type {
HAL_RECEPTION_TYPE_FRAMELESS
};
-#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB GENMASK(15, 8)
-#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION GENMASK(3, 0)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5)
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8)
struct hal_rx_phyrx_rssi_legacy_info {
- __le32 rsvd[35];
__le32 info0;
+ __le32 rsvd0[39];
+ __le32 info1;
+ __le32 rsvd1;
} __packed;
-#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16)
-#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16)
-#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0)
+#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16)
+#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16)
+#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0)
struct hal_rx_mpdu_start {
+ __le32 rsvd0[9];
__le32 info0;
__le32 info1;
- __le32 rsvd1[11];
+ __le32 rsvd1[2];
__le32 info2;
- __le32 rsvd2[9];
+ __le32 rsvd2[16];
} __packed;
#define HAL_RX_PPDU_END_DURATION GENMASK(23, 0)
diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h
index 0e53ec269fa4..e8840fab6061 100644
--- a/drivers/net/wireless/ath/ath12k/hif.h
+++ b/drivers/net/wireless/ath/ath12k/hif.h
@@ -31,6 +31,7 @@ struct ath12k_hif_ops {
void (*ce_irq_disable)(struct ath12k_base *ab);
void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx);
int (*panic_handler)(struct ath12k_base *ab);
+ void (*coredump_download)(struct ath12k_base *ab);
};
static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,
@@ -156,4 +157,9 @@ static inline int ath12k_hif_panic_handler(struct ath12k_base *ab)
return ab->hif.ops->panic_handler(ab);
}
+static inline void ath12k_hif_coredump_download(struct ath12k_base *ab)
+{
+ if (ab->hif.ops->coredump_download)
+ ab->hif.ops->coredump_download(ab);
+}
#endif /* ATH12K_HIF_H */
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index ec1bda95e555..b7b583fadb5a 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -913,7 +913,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.rfkill_cfg = 0,
.rfkill_on_level = 0,
- .rddm_size = 0,
+ .rddm_size = 0x600000,
.def_num_link = 0,
.max_mlo_peer = 256,
@@ -1069,7 +1069,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.rfkill_cfg = 0,
.rfkill_on_level = 0,
- .rddm_size = 0,
+ .rddm_size = 0x600000,
.def_num_link = 0,
.max_mlo_peer = 256,
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 137394c36460..d493ec812055 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -250,10 +250,10 @@ static const u32 ath12k_smps_map[] = {
};
static int ath12k_start_vdev_delay(struct ath12k *ar,
- struct ath12k_vif *arvif);
+ struct ath12k_link_vif *arvif);
static void ath12k_mac_stop(struct ath12k *ar);
-static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif);
-static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif);
+static int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif);
+static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif);
static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode)
{
@@ -476,18 +476,25 @@ static u8 ath12k_parse_mpdudensity(u8 mpdudensity)
}
}
-static int ath12k_mac_vif_chan(struct ieee80211_vif *vif,
- struct cfg80211_chan_def *def)
+static int ath12k_mac_vif_link_chan(struct ieee80211_vif *vif, u8 link_id,
+ struct cfg80211_chan_def *def)
{
+ struct ieee80211_bss_conf *link_conf;
struct ieee80211_chanctx_conf *conf;
rcu_read_lock();
- conf = rcu_dereference(vif->bss_conf.chanctx_conf);
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+
+ if (!link_conf) {
+ rcu_read_unlock();
+ return -ENOLINK;
+ }
+
+ conf = rcu_dereference(link_conf->chanctx_conf);
if (!conf) {
rcu_read_unlock();
return -ENOENT;
}
-
*def = conf->def;
rcu_read_unlock();
@@ -539,18 +546,33 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct ath12k_vif_iter *arvif_iter = data;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ unsigned long links_map = ahvif->links_map;
+ struct ath12k_link_vif *arvif;
+ u8 link_id;
+
+ for_each_set_bit(link_id, &links_map, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = rcu_dereference(ahvif->link[link_id]);
+
+ if (WARN_ON(!arvif))
+ continue;
- if (arvif->vdev_id == arvif_iter->vdev_id &&
- arvif->ar == arvif_iter->ar)
- arvif_iter->arvif = arvif;
+ if (arvif->vdev_id == arvif_iter->vdev_id &&
+ arvif->ar == arvif_iter->ar) {
+ arvif_iter->arvif = arvif;
+ break;
+ }
+ }
}
-struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
+struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
{
struct ath12k_vif_iter arvif_iter = {};
u32 flags;
+ /* To use the arvif returned, caller must have held rcu read lock.
+ */
+ WARN_ON(!rcu_read_lock_any_held());
arvif_iter.vdev_id = vdev_id;
arvif_iter.ar = ar;
@@ -567,12 +589,12 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
return arvif_iter.arvif;
}
-struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
- u32 vdev_id)
+struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
+ u32 vdev_id)
{
int i;
struct ath12k_pdev *pdev;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
for (i = 0; i < ab->num_radios; i++) {
pdev = rcu_dereference(ab->pdevs_active[i]);
@@ -658,7 +680,8 @@ static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw,
static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif = &ahvif->deflink;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
/* If there is one pdev within ah, then we return
@@ -673,11 +696,12 @@ static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw,
return NULL;
}
-static struct ath12k_vif *ath12k_mac_get_vif_up(struct ath12k *ar)
+static struct ath12k_link_vif *ath12k_mac_get_vif_up(struct ath12k *ar)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
+
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (arvif->is_up)
return arvif;
@@ -705,17 +729,17 @@ static bool ath12k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BA
return false;
}
-static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif)
+static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
struct ath12k_base *ab = ar->ab;
- struct ieee80211_vif *vif = arvif->vif;
+ struct ieee80211_vif *vif = arvif->ahvif->vif;
struct cfg80211_chan_def def;
enum nl80211_band band;
u8 pdev_id = ab->fw_pdev[0].pdev_id;
int i;
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return pdev_id;
band = def.chan->band;
@@ -730,7 +754,7 @@ static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif)
u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
struct ath12k_base *ab = ar->ab;
if (!ab->hw_params->single_pdev_only)
@@ -770,11 +794,11 @@ static void ath12k_pdev_caps_update(struct ath12k *ar)
static int ath12k_mac_txpower_recalc(struct ath12k *ar)
{
struct ath12k_pdev *pdev = ar->pdev;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret, txpower = -1;
u32 param;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (arvif->txpower <= 0)
@@ -824,13 +848,13 @@ fail:
return ret;
}
-static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif)
+static int ath12k_recalc_rtscts_prot(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
u32 vdev_param, rts_cts;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS;
@@ -863,7 +887,7 @@ static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif)
return ret;
}
-static int ath12k_mac_set_kickout(struct ath12k_vif *arvif)
+static int ath12k_mac_set_kickout(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
u32 param;
@@ -913,11 +937,14 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
struct ath12k_peer *peer, *tmp;
struct ath12k_base *ab = ar->ab;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
spin_lock_bh(&ab->base_lock);
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
- ath12k_dp_rx_peer_tid_cleanup(ar, peer);
+ /* Skip Rx TID cleanup for self peer */
+ if (peer->sta)
+ ath12k_dp_rx_peer_tid_cleanup(ar, peer);
+
list_del(&peer->list);
kfree(peer);
}
@@ -929,7 +956,7 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar)
static int ath12k_mac_vdev_setup_sync(struct ath12k *ar)
{
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN;
@@ -971,7 +998,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id,
struct ath12k_wmi_vdev_up_params params = {};
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
channel = chandef->chan;
arg.vdev_id = vdev_id;
@@ -1034,7 +1061,7 @@ static int ath12k_mac_monitor_vdev_stop(struct ath12k *ar)
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->vdev_setup_done);
@@ -1064,9 +1091,8 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar)
struct ath12k_wmi_vdev_create_arg arg = {};
int bit, ret;
u8 tmp_addr[6];
- u16 nss;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (ar->monitor_vdev_created)
return 0;
@@ -1104,19 +1130,6 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar)
return ret;
}
- nss = hweight32(ar->cfg_tx_chainmask) ? : 1;
- ret = ath12k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id,
- WMI_VDEV_PARAM_NSS, nss);
- if (ret) {
- ath12k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n",
- ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret);
- return ret;
- }
-
- ret = ath12k_mac_txpower_recalc(ar);
- if (ret)
- return ret;
-
ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id;
ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
ar->num_created_vdevs++;
@@ -1132,7 +1145,7 @@ static int ath12k_mac_monitor_vdev_delete(struct ath12k *ar)
int ret;
unsigned long time_left;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (!ar->monitor_vdev_created)
return 0;
@@ -1178,7 +1191,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar)
struct cfg80211_chan_def *chandef = NULL;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (ar->monitor_started)
return 0;
@@ -1208,7 +1221,7 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar)
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (!ar->monitor_started)
return 0;
@@ -1226,12 +1239,13 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar)
return ret;
}
-static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif)
+static int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif)
{
+ struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k *ar = arvif->ar;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->vdev_setup_done);
@@ -1253,7 +1267,7 @@ static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif)
ar->num_started_vdevs--;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n",
- arvif->vif->addr, arvif->vdev_id);
+ ahvif->vif->addr, arvif->vdev_id);
if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) {
clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
@@ -1272,36 +1286,33 @@ static int ath12k_mac_config(struct ath12k *ar, u32 changed)
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
ar->monitor_conf_enabled = conf->flags & IEEE80211_CONF_MONITOR;
if (ar->monitor_conf_enabled) {
if (ar->monitor_vdev_created)
- goto exit;
+ return ret;
ret = ath12k_mac_monitor_vdev_create(ar);
if (ret)
- goto exit;
+ return ret;
ret = ath12k_mac_monitor_start(ar);
if (ret)
goto err_mon_del;
} else {
if (!ar->monitor_vdev_created)
- goto exit;
+ return ret;
ret = ath12k_mac_monitor_stop(ar);
if (ret)
- goto exit;
+ return ret;
ath12k_mac_monitor_vdev_delete(ar);
}
}
-exit:
- mutex_unlock(&ar->conf_mutex);
return ret;
err_mon_del:
ath12k_mac_monitor_vdev_delete(ar);
- mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -1311,6 +1322,8 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
struct ath12k *ar;
int ret;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_ah_to_ar(ah, 0);
ret = ath12k_mac_config(ar, changed);
@@ -1321,7 +1334,7 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
return ret;
}
-static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif,
+static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_link_vif *arvif,
struct sk_buff *bcn)
{
struct ath12k *ar = arvif->ar;
@@ -1378,7 +1391,7 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
return 0;
}
-static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn,
+static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn,
u8 bssid_index, bool *nontx_profile_found)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data;
@@ -1470,19 +1483,22 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b
}
}
-static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif)
+static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif)
{
- struct ieee80211_bss_conf *bss_conf = &arvif->vif->bss_conf;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_bss_conf *bss_conf = &ahvif->vif->bss_conf;
struct ath12k_wmi_bcn_tmpl_ema_arg ema_args;
struct ieee80211_ema_beacons *beacons;
- struct ath12k_vif *tx_arvif;
+ struct ath12k_link_vif *tx_arvif;
bool nontx_profile_found = false;
+ struct ath12k_vif *tx_ahvif;
int ret = 0;
u8 i;
- tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
+ tx_ahvif = ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif);
+ tx_arvif = &tx_ahvif->deflink;
beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar),
- tx_arvif->vif, 0);
+ tx_ahvif->vif, 0);
if (!beacons || !beacons->cnt) {
ath12k_warn(arvif->ar->ab,
"failed to get ema beacon templates from mac80211\n");
@@ -1520,22 +1536,25 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif)
return ret;
}
-static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
+static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif)
{
- struct ath12k_vif *tx_arvif = arvif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+ struct ath12k_link_vif *tx_arvif = arvif;
struct ath12k *ar = arvif->ar;
struct ath12k_base *ab = ar->ab;
- struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_mutable_offsets offs = {};
+ struct ath12k_vif *tx_ahvif = ahvif;
bool nontx_profile_found = false;
struct sk_buff *bcn;
int ret;
- if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_AP)
return 0;
if (vif->mbssid_tx_vif) {
- tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif);
+ tx_ahvif = ath12k_vif_to_ahvif(vif->mbssid_tx_vif);
+ tx_arvif = &tx_ahvif->deflink;
if (tx_arvif != arvif && arvif->is_up)
return 0;
@@ -1543,7 +1562,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
return ath12k_mac_setup_bcn_tmpl_ema(arvif);
}
- bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif,
+ bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_ahvif->vif,
&offs, 0);
if (!bcn) {
ath12k_warn(ab, "failed to get beacon template from mac80211\n");
@@ -1554,14 +1573,14 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL);
} else {
ath12k_mac_set_arvif_ies(arvif, bcn,
- arvif->vif->bss_conf.bssid_index,
+ ahvif->vif->bss_conf.bssid_index,
&nontx_profile_found);
if (!nontx_profile_found)
ath12k_warn(ab,
"nontransmitted profile not found in beacon template\n");
}
- if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) {
+ if (ahvif->vif->type == NL80211_IFTYPE_AP && ahvif->vif->p2p) {
ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn);
if (ret) {
ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n",
@@ -1595,14 +1614,15 @@ free_bcn_skb:
return ret;
}
-static void ath12k_control_beaconing(struct ath12k_vif *arvif,
+static void ath12k_control_beaconing(struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *info)
{
struct ath12k_wmi_vdev_up_params params = {};
+ struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k *ar = arvif->ar;
int ret;
- lockdep_assert_held(&arvif->ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(arvif->ar)->wiphy);
if (!info->enable_beacon) {
ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id);
@@ -1622,15 +1642,19 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif,
return;
}
- arvif->aid = 0;
+ ahvif->aid = 0;
ether_addr_copy(arvif->bssid, info->bssid);
params.vdev_id = arvif->vdev_id;
- params.aid = arvif->aid;
+ params.aid = ahvif->aid;
params.bssid = arvif->bssid;
- if (arvif->vif->mbssid_tx_vif) {
- params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid;
+ if (ahvif->vif->mbssid_tx_vif) {
+ struct ath12k_vif *tx_ahvif =
+ ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif);
+ struct ath12k_link_vif *tx_arvif = &tx_ahvif->deflink;
+
+ params.tx_bssid = tx_arvif->bssid;
params.nontx_profile_idx = info->bssid_index;
params.nontx_profile_cnt = 1 << info->bssid_indicator;
}
@@ -1651,7 +1675,8 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac,
{
struct sk_buff *skb = data;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif = &ahvif->deflink;
if (vif->type != NL80211_IFTYPE_STATION)
return;
@@ -1674,7 +1699,8 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
u32 *vdev_id = data;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif = &ahvif->deflink;
struct ath12k *ar = arvif->ar;
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
@@ -1705,9 +1731,9 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id)
static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
{
- struct ath12k_vif *arvif = container_of(work, struct ath12k_vif,
- connection_loss_work.work);
- struct ieee80211_vif *vif = arvif->vif;
+ struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif,
+ connection_loss_work.work);
+ struct ieee80211_vif *vif = arvif->ahvif->vif;
if (!arvif->is_up)
return;
@@ -1716,15 +1742,16 @@ static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
}
static void ath12k_peer_assoc_h_basic(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
u32 aid;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
if (vif->type == NL80211_IFTYPE_STATION)
aid = vif->cfg.aid;
@@ -1742,21 +1769,22 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar,
}
static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_chan_def def;
struct cfg80211_bss *bss;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
const u8 *rsnie = NULL;
const u8 *wpaie = NULL;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0,
@@ -1804,11 +1832,12 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
}
static void ath12k_peer_assoc_h_rates(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
struct cfg80211_chan_def def;
const struct ieee80211_supported_band *sband;
@@ -1819,9 +1848,9 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar,
u8 rate;
int i;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
band = def.chan->band;
@@ -1867,12 +1896,13 @@ ath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask)
}
static void ath12k_peer_assoc_h_ht(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
const u8 *ht_mcs_mask;
@@ -1880,9 +1910,9 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar,
u8 max_nss;
u32 stbc;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
if (!ht_cap->ht_supported)
@@ -2028,12 +2058,13 @@ ath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
}
static void ath12k_peer_assoc_h_vht(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
const u16 *vht_mcs_mask;
@@ -2042,7 +2073,9 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar,
u8 max_nss, vht_mcs;
int i;
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
if (!vht_cap->vht_supported)
@@ -2123,10 +2156,12 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar,
}
static void ath12k_peer_assoc_h_he(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
int i;
u8 ampdu_factor, max_nss;
@@ -2278,16 +2313,18 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar,
}
static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
struct cfg80211_chan_def def;
enum nl80211_band band;
u8 ampdu_factor, mpdu_density;
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
band = def.chan->band;
@@ -2347,9 +2384,10 @@ static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap,
return 0;
}
-static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta,
+static void ath12k_peer_assoc_h_smps(struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_he_6ghz_capa *he_6ghz_capa = &sta->deflink.he_6ghz_capa;
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
int smps;
@@ -2376,13 +2414,13 @@ static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta,
}
static void ath12k_peer_assoc_h_qos(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
- switch (arvif->vdev_type) {
+ switch (arvif->ahvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
if (sta->wme) {
/* TODO: Check WME vs QoS */
@@ -2412,15 +2450,16 @@ static void ath12k_peer_assoc_h_qos(struct ath12k *ar,
}
static int ath12k_peer_assoc_qos_ap(struct ath12k *ar,
- struct ath12k_vif *arvif,
- struct ieee80211_sta *sta)
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k_wmi_ap_ps_arg arg;
u32 max_sp;
u32 uapsd;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
arg.vdev_id = arvif->vdev_id;
@@ -2574,18 +2613,22 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar,
}
static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct cfg80211_chan_def def;
enum nl80211_band band;
const u8 *ht_mcs_mask;
const u16 *vht_mcs_mask;
enum wmi_phy_mode phymode = MODE_UNKNOWN;
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
+
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
band = def.chan->band;
@@ -2719,17 +2762,19 @@ static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres,
}
static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap;
const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20;
const struct ieee80211_eht_mcs_nss_supp_bw *bw;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
u32 *rx_mcs, *tx_mcs;
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht)
return;
@@ -2802,34 +2847,34 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
}
static void ath12k_peer_assoc_prepare(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ath12k_wmi_peer_assoc_arg *arg,
bool reassoc)
{
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
memset(arg, 0, sizeof(*arg));
reinit_completion(&ar->peer_assoc_done);
arg->peer_new_assoc = !reassoc;
- ath12k_peer_assoc_h_basic(ar, vif, sta, arg);
- ath12k_peer_assoc_h_crypto(ar, vif, sta, arg);
- ath12k_peer_assoc_h_rates(ar, vif, sta, arg);
- ath12k_peer_assoc_h_ht(ar, vif, sta, arg);
- ath12k_peer_assoc_h_vht(ar, vif, sta, arg);
- ath12k_peer_assoc_h_he(ar, vif, sta, arg);
- ath12k_peer_assoc_h_he_6ghz(ar, vif, sta, arg);
- ath12k_peer_assoc_h_eht(ar, vif, sta, arg);
- ath12k_peer_assoc_h_qos(ar, vif, sta, arg);
- ath12k_peer_assoc_h_phymode(ar, vif, sta, arg);
- ath12k_peer_assoc_h_smps(sta, arg);
+ ath12k_peer_assoc_h_basic(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_crypto(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_rates(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_ht(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_vht(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_he(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_he_6ghz(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_eht(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_qos(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_phymode(ar, arvif, arsta, arg);
+ ath12k_peer_assoc_h_smps(arsta, arg);
/* TODO: amsdu_disable req? */
}
-static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif,
+static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arvif,
const u8 *addr,
const struct ieee80211_sta_ht_cap *ht_cap,
const struct ieee80211_he_6ghz_capa *he_6ghz_capa)
@@ -2849,21 +2894,24 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif,
}
static void ath12k_bss_assoc(struct ath12k *ar,
- struct ath12k_vif *arvif,
+ struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ieee80211_vif *vif = arvif->vif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct ath12k_wmi_vdev_up_params params = {};
struct ath12k_wmi_peer_assoc_arg peer_arg;
+ struct ath12k_link_sta *arsta;
struct ieee80211_sta *ap_sta;
+ struct ath12k_sta *ahsta;
struct ath12k_peer *peer;
bool is_auth = false;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
- arvif->vdev_id, arvif->bssid, arvif->aid);
+ arvif->vdev_id, arvif->bssid, ahvif->aid);
rcu_read_lock();
@@ -2875,7 +2923,15 @@ static void ath12k_bss_assoc(struct ath12k *ar,
return;
}
- ath12k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false);
+ ahsta = ath12k_sta_to_ahsta(ap_sta);
+ arsta = &ahsta->deflink;
+
+ if (WARN_ON(!arsta)) {
+ rcu_read_unlock();
+ return;
+ }
+
+ ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, false);
rcu_read_unlock();
@@ -2903,11 +2959,11 @@ static void ath12k_bss_assoc(struct ath12k *ar,
WARN_ON(arvif->is_up);
- arvif->aid = vif->cfg.aid;
+ ahvif->aid = vif->cfg.aid;
ether_addr_copy(arvif->bssid, bss_conf->bssid);
params.vdev_id = arvif->vdev_id;
- params.aid = arvif->aid;
+ params.aid = ahvif->aid;
params.bssid = arvif->bssid;
ret = ath12k_wmi_vdev_up(ar, &params);
if (ret) {
@@ -2949,11 +3005,11 @@ static void ath12k_bss_assoc(struct ath12k *ar,
}
static void ath12k_bss_disassoc(struct ath12k *ar,
- struct ath12k_vif *arvif)
+ struct ath12k_link_vif *arvif)
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
arvif->vdev_id, arvif->bssid);
@@ -2996,10 +3052,10 @@ static u32 ath12k_mac_get_rate_hw_value(int bitrate)
}
static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
- struct ieee80211_vif *vif,
+ struct ath12k_link_vif *arvif,
struct cfg80211_chan_def *def)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
const struct ieee80211_supported_band *sband;
u8 basic_rate_idx;
@@ -3008,7 +3064,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
u16 bitrate;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
sband = hw->wiphy->bands[def->chan->band];
basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
@@ -3033,9 +3089,19 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
ath12k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret);
}
-static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
+static int
+ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u16 old_links, u16 new_links,
+ struct ieee80211_bss_conf *ol[IEEE80211_MLD_MAX_NUM_LINKS])
+{
+ return 0;
+}
+
+static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *info)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ath12k *ar = arvif->ar;
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
struct sk_buff *tmpl;
@@ -3046,7 +3112,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
if (info->fils_discovery.max_interval) {
interval = info->fils_discovery.max_interval;
- tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif);
+ tmpl = ieee80211_get_fils_discovery_tmpl(hw, vif);
if (tmpl)
ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id,
tmpl);
@@ -3054,8 +3120,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
unsol_bcast_probe_resp_enabled = 1;
interval = info->unsol_bcast_probe_resp_interval;
- tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw,
- arvif->vif);
+ tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
if (tmpl)
ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id,
tmpl);
@@ -3080,10 +3145,44 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
return ret;
}
-static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
+static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u64 changed)
+{
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ unsigned long links = ahvif->links_map;
+ struct ath12k_link_vif *arvif;
+ struct ath12k *ar;
+ u8 link_id;
+
+ lockdep_assert_wiphy(hw->wiphy);
+
+ if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) {
+ ahvif->u.ap.ssid_len = vif->cfg.ssid_len;
+ if (vif->cfg.ssid_len)
+ memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len);
+ }
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ if (!arvif || !arvif->ar)
+ continue;
+
+ ar = arvif->ar;
+
+ if (vif->cfg.assoc)
+ ath12k_bss_assoc(ar, arvif, &vif->bss_conf);
+ else
+ ath12k_bss_disassoc(ar, arvif);
+ }
+ }
+}
+
+static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
- struct ieee80211_vif *vif = arvif->vif;
+ struct ieee80211_vif *vif = arvif->ahvif->vif;
struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf;
enum wmi_sta_powersave_param param;
enum wmi_sta_ps_mode psmode;
@@ -3091,12 +3190,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
int timeout;
bool enable_ps;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (vif->type != NL80211_IFTYPE_STATION)
return;
- enable_ps = arvif->ps;
+ enable_ps = arvif->ahvif->ps;
if (enable_ps) {
psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
@@ -3128,11 +3227,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
}
static void ath12k_mac_bss_info_changed(struct ath12k *ar,
- struct ath12k_vif *arvif,
+ struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *info,
u64 changed)
{
- struct ieee80211_vif *vif = arvif->vif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct ieee80211_vif_cfg *vif_cfg = &vif->cfg;
struct cfg80211_chan_def def;
u32 param_id, param_value;
@@ -3146,7 +3246,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
u8 rateidx;
u32 rate;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (changed & BSS_CHANGED_BEACON_INT) {
arvif->beacon_interval = info->beacon_int;
@@ -3202,10 +3302,10 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
if (changed & BSS_CHANGED_SSID &&
vif->type == NL80211_IFTYPE_AP) {
- arvif->u.ap.ssid_len = vif->cfg.ssid_len;
+ ahvif->u.ap.ssid_len = vif->cfg.ssid_len;
if (vif->cfg.ssid_len)
- memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len);
- arvif->u.ap.hidden_ssid = info->hidden_ssid;
+ memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len);
+ ahvif->u.ap.hidden_ssid = info->hidden_ssid;
}
if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
@@ -3316,7 +3416,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
}
if (changed & BSS_CHANGED_MCAST_RATE &&
- !ath12k_mac_vif_chan(arvif->vif, &def)) {
+ !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) {
band = def.chan->band;
mcast_rate = vif->bss_conf.mcast_rate[band];
@@ -3360,8 +3460,8 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
}
if (changed & BSS_CHANGED_BASIC_RATES &&
- !ath12k_mac_vif_chan(arvif->vif, &def))
- ath12k_recalculate_mgmt_rate(ar, vif, &def);
+ !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))
+ ath12k_recalculate_mgmt_rate(ar, arvif, &def);
if (changed & BSS_CHANGED_TWT) {
if (info->twt_requester || info->twt_responder)
@@ -3406,53 +3506,177 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
if (changed & BSS_CHANGED_PS &&
ar->ab->hw_params->supports_sta_ps) {
- arvif->ps = vif_cfg->ps;
+ ahvif->ps = vif_cfg->ps;
ath12k_mac_vif_setup_ps(arvif);
}
}
-static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif)
+static struct ath12k_vif_cache *ath12k_ahvif_get_link_cache(struct ath12k_vif *ahvif,
+ u8 link_id)
+{
+ if (!ahvif->cache[link_id]) {
+ ahvif->cache[link_id] = kzalloc(sizeof(*ahvif->cache[0]), GFP_KERNEL);
+ if (ahvif->cache[link_id])
+ INIT_LIST_HEAD(&ahvif->cache[link_id]->key_conf.list);
+ }
+
+ return ahvif->cache[link_id];
+}
+
+static void ath12k_ahvif_put_link_key_cache(struct ath12k_vif_cache *cache)
{
- if (!arvif->cache)
- arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL);
+ struct ath12k_key_conf *key_conf, *tmp;
- return arvif->cache;
+ if (!cache || list_empty(&cache->key_conf.list))
+ return;
+ list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) {
+ list_del(&key_conf->list);
+ kfree(key_conf);
+ }
}
-static void ath12k_arvif_put_cache(struct ath12k_vif *arvif)
+static void ath12k_ahvif_put_link_cache(struct ath12k_vif *ahvif, u8 link_id)
{
- kfree(arvif->cache);
- arvif->cache = NULL;
+ ath12k_ahvif_put_link_key_cache(ahvif->cache[link_id]);
+ kfree(ahvif->cache[link_id]);
+ ahvif->cache[link_id] = NULL;
}
-static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u64 changed)
+static void ath12k_mac_op_link_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u64 changed)
{
struct ath12k *ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_vif_cache *cache;
+ struct ath12k_link_vif *arvif;
+ u8 link_id = info->link_id;
- ar = ath12k_get_ar_by_vif(hw, vif);
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
/* if the vdev is not created on a certain radio,
* cache the info to be updated later on vdev creation
*/
- if (!ar) {
- cache = ath12k_arvif_get_cache(arvif);
+ if (!arvif || !arvif->is_created) {
+ cache = ath12k_ahvif_get_link_cache(ahvif, link_id);
if (!cache)
return;
- arvif->cache->bss_conf_changed |= changed;
+
+ cache->bss_conf_changed |= changed;
+
return;
}
- mutex_lock(&ar->conf_mutex);
+ ar = arvif->ar;
ath12k_mac_bss_info_changed(ar, arvif, info, changed);
+}
+
+static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah,
+ struct ieee80211_vif *vif,
+ u8 link_id)
+{
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ int i;
+
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]);
+ if (arvif)
+ return arvif;
+
+ if (!vif->valid_links) {
+ /* Use deflink for Non-ML VIFs and mark the link id as 0
+ */
+ link_id = 0;
+ arvif = &ahvif->deflink;
+ } else {
+ /* If this is the first link arvif being created for an ML VIF
+ * use the preallocated deflink memory
+ */
+ if (!ahvif->links_map) {
+ arvif = &ahvif->deflink;
+ } else {
+ arvif = (struct ath12k_link_vif *)
+ kzalloc(sizeof(struct ath12k_link_vif), GFP_KERNEL);
+ if (!arvif)
+ return NULL;
+ }
+ }
+
+ arvif->ahvif = ahvif;
+ arvif->link_id = link_id;
+ ahvif->links_map |= BIT(link_id);
+
+ INIT_LIST_HEAD(&arvif->list);
+ INIT_DELAYED_WORK(&arvif->connection_loss_work,
+ ath12k_mac_vif_sta_connection_loss_work);
+
+ for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
+ arvif->bitrate_mask.control[i].legacy = 0xffffffff;
+ memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].ht_mcs));
+ memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
+ sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+ }
+
+ /* Allocate Default Queue now and reassign during actual vdev create */
+ vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE;
+ for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
+ vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE;
- mutex_unlock(&ar->conf_mutex);
+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
+ rcu_assign_pointer(ahvif->link[arvif->link_id], arvif);
+ ahvif->links_map |= BIT(link_id);
+ synchronize_rcu();
+ return arvif;
+}
+
+static void ath12k_mac_unassign_link_vif(struct ath12k_link_vif *arvif)
+{
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ath12k_hw *ah = ahvif->ah;
+
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ rcu_assign_pointer(ahvif->link[arvif->link_id], NULL);
+ synchronize_rcu();
+ ahvif->links_map &= ~BIT(arvif->link_id);
+
+ if (arvif != &ahvif->deflink)
+ kfree(arvif);
+ else
+ memset(arvif, 0, sizeof(*arvif));
+}
+
+static void ath12k_mac_remove_link_interface(struct ieee80211_hw *hw,
+ struct ath12k_link_vif *arvif)
+{
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ath12k_hw *ah = hw->priv;
+ struct ath12k *ar = arvif->ar;
+ int ret;
+
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ cancel_delayed_work_sync(&arvif->connection_loss_work);
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac remove link interface (vdev %d link id %d)",
+ arvif->vdev_id, arvif->link_id);
+
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ ret = ath12k_peer_delete(ar, arvif->vdev_id, arvif->bssid);
+ if (ret)
+ ath12k_warn(ar->ab, "failed to submit AP self-peer removal on vdev %d link id %d: %d",
+ arvif->vdev_id, arvif->link_id, ret);
+ }
+ ath12k_mac_vdev_delete(ar, arvif);
}
static struct ath12k*
@@ -3541,7 +3765,7 @@ static int ath12k_scan_stop(struct ath12k *ar)
};
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
/* TODO: Fill other STOP Params */
arg.pdev_id = ar->pdev->pdev_id;
@@ -3581,7 +3805,7 @@ static void ath12k_scan_abort(struct ath12k *ar)
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
spin_lock_bh(&ar->data_lock);
@@ -3616,9 +3840,9 @@ static void ath12k_scan_timeout_work(struct work_struct *work)
struct ath12k *ar = container_of(work, struct ath12k,
scan.timeout.work);
- mutex_lock(&ar->conf_mutex);
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
ath12k_scan_abort(ar);
- mutex_unlock(&ar->conf_mutex);
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
}
static int ath12k_start_scan(struct ath12k *ar,
@@ -3626,7 +3850,7 @@ static int ath12k_start_scan(struct ath12k *ar,
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ret = ath12k_wmi_send_scan_start_cmd(ar, arg);
if (ret)
@@ -3655,24 +3879,50 @@ static int ath12k_start_scan(struct ath12k *ar,
return 0;
}
+static u8
+ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
+{
+ struct ath12k_link_vif *arvif;
+ struct ath12k_hw *ah = ahvif->ah;
+ unsigned long links = ahvif->links_map;
+ u8 link_id;
+
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]);
+
+ if (!arvif || !arvif->is_created)
+ continue;
+
+ if (ar == arvif->ar)
+ return link_id;
+ }
+
+ /* input ar is not assigned to any of the links, use link id
+ * 0 for scan vdev creation.
+ */
+ return 0;
+}
+
static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req)
{
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
- struct ath12k *ar, *prev_ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k *ar;
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
struct cfg80211_scan_request *req = &hw_req->req;
struct ath12k_wmi_scan_req_arg *arg = NULL;
+ u8 link_id;
int ret;
int i;
bool create = true;
- if (ah->num_radio == 1) {
- WARN_ON(!arvif->is_created);
- ar = ath12k_ah_to_ar(ah, 0);
- goto scan;
- }
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
/* Since the targeted scan device could depend on the frequency
* requested in the hw_req, select the corresponding radio
@@ -3681,6 +3931,13 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
if (!ar)
return -EINVAL;
+ /* check if any of the links of ML VIF is already started on
+ * radio(ar) correpsondig to given scan frequency and use it,
+ * if not use deflink(link 0) for scan purpose.
+ */
+ link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar);
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
+
/* If the vif is already assigned to a specific vdev of an ar,
* check whether its already started, vdev which is started
* are not allowed to switch to a new radio.
@@ -3698,31 +3955,24 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
return -EINVAL;
if (ar != arvif->ar) {
- /* backup the previously used ar ptr, since the vdev delete
- * would assign the arvif->ar to NULL after the call
- */
- prev_ar = arvif->ar;
- mutex_lock(&prev_ar->conf_mutex);
- ret = ath12k_mac_vdev_delete(prev_ar, vif);
- mutex_unlock(&prev_ar->conf_mutex);
- if (ret)
- ath12k_warn(prev_ar->ab,
- "unable to delete scan vdev %d\n", ret);
+ ath12k_mac_remove_link_interface(hw, arvif);
+ ath12k_mac_unassign_link_vif(arvif);
} else {
create = false;
}
}
if (create) {
- mutex_lock(&ar->conf_mutex);
- ret = ath12k_mac_vdev_create(ar, vif);
- mutex_unlock(&ar->conf_mutex);
+ /* Previous arvif would've been cleared in radio switch block
+ * above, assign arvif again for create.
+ */
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
+
+ ret = ath12k_mac_vdev_create(ar, arvif);
if (ret) {
ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret);
return -EINVAL;
}
}
-scan:
- mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
switch (ar->scan.state) {
@@ -3805,30 +4055,31 @@ exit:
kfree(arg);
}
- mutex_unlock(&ar->conf_mutex);
-
return ret;
}
static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
struct ath12k *ar;
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
+
if (!arvif->is_created)
return;
ar = arvif->ar;
- mutex_lock(&ar->conf_mutex);
ath12k_scan_abort(ar);
- mutex_unlock(&ar->conf_mutex);
cancel_delayed_work_sync(&ar->scan.timeout);
}
-static int ath12k_install_key(struct ath12k_vif *arvif,
+static int ath12k_install_key(struct ath12k_link_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
const u8 *macaddr, u32 flags)
@@ -3843,8 +4094,10 @@ static int ath12k_install_key(struct ath12k_vif *arvif,
.key_flags = flags,
.macaddr = macaddr,
};
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
- lockdep_assert_held(&arvif->ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->install_key_done);
@@ -3895,13 +4148,13 @@ install:
if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
return -ETIMEDOUT;
- if (ether_addr_equal(macaddr, arvif->vif->addr))
- arvif->key_cipher = key->cipher;
+ if (ether_addr_equal(macaddr, vif->addr))
+ ahvif->key_cipher = key->cipher;
return ar->install_key_status ? -EINVAL : 0;
}
-static int ath12k_clear_peer_keys(struct ath12k_vif *arvif,
+static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif,
const u8 *addr)
{
struct ath12k *ar = arvif->ar;
@@ -3912,7 +4165,7 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif,
int i;
u32 flags = 0;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find(ab, arvif->vdev_id, addr);
@@ -3944,25 +4197,31 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif,
}
static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
struct ieee80211_key_conf *key)
{
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+ struct ieee80211_sta *sta = NULL;
struct ath12k_base *ab = ar->ab;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
struct ath12k_peer *peer;
- struct ath12k_sta *arsta;
+ struct ath12k_sta *ahsta;
const u8 *peer_addr;
- int ret = 0;
+ int ret;
u32 flags = 0;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
+ if (arsta)
+ sta = ath12k_ahsta_to_sta(arsta->ahsta);
if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
return 1;
if (sta)
peer_addr = sta->addr;
- else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+ else if (ahvif->vdev_type == WMI_VDEV_TYPE_STA)
peer_addr = vif->bss_conf.bssid;
else
peer_addr = vif->addr;
@@ -3970,7 +4229,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
key->hw_key_idx = key->keyidx;
/* the peer should not disappear in mid-way (unless FW goes awry) since
- * we already hold conf_mutex. we just make sure its there now.
+ * we already hold wiphy lock. we just make sure its there now.
*/
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr);
@@ -3980,14 +4239,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
if (cmd == SET_KEY) {
ath12k_warn(ab, "cannot install key for non-existent peer %pM\n",
peer_addr);
- ret = -EOPNOTSUPP;
- goto exit;
- } else {
- /* if the peer doesn't exist there is no key to disable
- * anymore
- */
- goto exit;
+ return -EOPNOTSUPP;
}
+
+ /* if the peer doesn't exist there is no key to disable
+ * anymore
+ */
+ return 0;
}
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
@@ -3998,13 +4256,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags);
if (ret) {
ath12k_warn(ab, "ath12k_install_key failed (%d)\n", ret);
- goto exit;
+ return ret;
}
ret = ath12k_dp_rx_peer_pn_replay_config(arvif, peer_addr, cmd, key);
if (ret) {
ath12k_warn(ab, "failed to offload PN replay detection %d\n", ret);
- goto exit;
+ return ret;
}
spin_lock_bh(&ab->base_lock);
@@ -4029,7 +4287,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
ath12k_warn(ab, "peer %pM disappeared!\n", peer_addr);
if (sta) {
- arsta = ath12k_sta_to_arsta(sta);
+ ahsta = ath12k_sta_to_ahsta(sta);
switch (key->cipher) {
case WLAN_CIPHER_SUITE_TKIP:
@@ -4038,61 +4296,138 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
if (cmd == SET_KEY)
- arsta->pn_type = HAL_PN_TYPE_WPA;
+ ahsta->pn_type = HAL_PN_TYPE_WPA;
else
- arsta->pn_type = HAL_PN_TYPE_NONE;
+ ahsta->pn_type = HAL_PN_TYPE_NONE;
break;
default:
- arsta->pn_type = HAL_PN_TYPE_NONE;
+ ahsta->pn_type = HAL_PN_TYPE_NONE;
break;
}
}
spin_unlock_bh(&ab->base_lock);
-exit:
- return ret;
+ return 0;
+}
+
+static int ath12k_mac_update_key_cache(struct ath12k_vif_cache *cache,
+ enum set_key_cmd cmd,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct ath12k_key_conf *key_conf = NULL, *tmp;
+
+ if (cmd == SET_KEY) {
+ key_conf = kzalloc(sizeof(*key_conf), GFP_KERNEL);
+
+ if (!key_conf)
+ return -ENOMEM;
+
+ key_conf->cmd = cmd;
+ key_conf->sta = sta;
+ key_conf->key = key;
+ list_add_tail(&key_conf->list,
+ &cache->key_conf.list);
+ }
+ if (list_empty(&cache->key_conf.list))
+ return 0;
+ list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) {
+ if (key_conf->key == key) {
+ /* DEL key for an old SET key which driver hasn't flushed yet.
+ */
+ list_del(&key_conf->list);
+ kfree(key_conf);
+ break;
+ }
+ }
+ return 0;
}
static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ struct ath12k_link_sta *arsta = NULL;
struct ath12k_vif_cache *cache;
- struct ath12k *ar;
+ struct ath12k_sta *ahsta;
+ unsigned long links;
+ u8 link_id;
int ret;
+ lockdep_assert_wiphy(hw->wiphy);
+
/* BIP needs to be done in software */
if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
- key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) {
return 1;
+ }
if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC;
- ar = ath12k_get_ar_by_vif(hw, vif);
- if (!ar) {
- /* ar is expected to be valid when sta ptr is available */
- if (sta) {
- WARN_ON_ONCE(1);
- return -EINVAL;
+ if (sta) {
+ ahsta = ath12k_sta_to_ahsta(sta);
+ /* For an ML STA Pairwise key is same for all associated link Stations,
+ * hence do set key for all link STAs which are active.
+ */
+ if (sta->mlo) {
+ links = ahsta->links_map;
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = wiphy_dereference(hw->wiphy,
+ ahvif->link[link_id]);
+ arsta = wiphy_dereference(hw->wiphy,
+ ahsta->link[link_id]);
+
+ if (WARN_ON(!arvif || !arsta))
+ /* arvif and arsta are expected to be valid when
+ * STA is present.
+ */
+ continue;
+
+ ret = ath12k_mac_set_key(arvif->ar, cmd, arvif,
+ arsta, key);
+ if (ret)
+ break;
+ }
+ } else {
+ arsta = &ahsta->deflink;
+ arvif = arsta->arvif;
+ if (WARN_ON(!arvif)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, arsta, key);
+ }
+ } else {
+ if (key->link_id >= 0 && key->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
+ link_id = key->link_id;
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ } else {
+ link_id = 0;
+ arvif = &ahvif->deflink;
}
- cache = ath12k_arvif_get_cache(arvif);
- if (!cache)
- return -ENOSPC;
- cache->key_conf.cmd = cmd;
- cache->key_conf.key = key;
- cache->key_conf.changed = true;
- return 0;
+ if (!arvif || !arvif->is_created) {
+ cache = ath12k_ahvif_get_link_cache(ahvif, link_id);
+ if (!cache)
+ return -ENOSPC;
+
+ ret = ath12k_mac_update_key_cache(cache, cmd, sta, key);
+
+ return ret;
+ }
+
+ ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, NULL, key);
}
- mutex_lock(&ar->conf_mutex);
- ret = ath12k_mac_set_key(ar, cmd, vif, sta, key);
- mutex_unlock(&ar->conf_mutex);
+out:
+
return ret;
}
@@ -4111,17 +4446,18 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar,
}
static int
-ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif,
- struct ieee80211_sta *sta,
+ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
const struct cfg80211_bitrate_mask *mask,
enum nl80211_band band)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k *ar = arvif->ar;
u8 vht_rate, nss;
u32 rate_code;
int ret, i;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
nss = 0;
@@ -4157,11 +4493,12 @@ ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif,
}
static int ath12k_station_assoc(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta,
bool reassoc)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k_wmi_peer_assoc_arg peer_arg;
int ret;
struct cfg80211_chan_def def;
@@ -4169,15 +4506,15 @@ static int ath12k_station_assoc(struct ath12k *ar,
struct cfg80211_bitrate_mask *mask;
u8 num_vht_rates;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return -EPERM;
band = def.chan->band;
mask = &arvif->bitrate_mask;
- ath12k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc);
+ ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, reassoc);
if (peer_arg.peer_nss < 1) {
ath12k_warn(ar->ab,
@@ -4205,7 +4542,7 @@ static int ath12k_station_assoc(struct ath12k *ar,
* Note that all other rates and NSS will be disabled for this peer.
*/
if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) {
- ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
+ ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask,
band);
if (ret)
return ret;
@@ -4234,7 +4571,7 @@ static int ath12k_station_assoc(struct ath12k *ar,
}
if (sta->wme && sta->uapsd_queues) {
- ret = ath12k_peer_assoc_qos_ap(ar, arvif, sta);
+ ret = ath12k_peer_assoc_qos_ap(ar, arvif, arsta);
if (ret) {
ath12k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n",
sta->addr, arvif->vdev_id, ret);
@@ -4246,13 +4583,13 @@ static int ath12k_station_assoc(struct ath12k *ar,
}
static int ath12k_station_disassoc(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (!sta->wme) {
arvif->num_legacy_stations--;
@@ -4270,11 +4607,10 @@ static int ath12k_station_disassoc(struct ath12k *ar,
return 0;
}
-static void ath12k_sta_rc_update_wk(struct work_struct *wk)
+static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
{
struct ath12k *ar;
- struct ath12k_vif *arvif;
- struct ath12k_sta *arsta;
+ struct ath12k_link_vif *arvif;
struct ieee80211_sta *sta;
struct cfg80211_chan_def def;
enum nl80211_band band;
@@ -4285,13 +4621,18 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
const struct cfg80211_bitrate_mask *mask;
struct ath12k_wmi_peer_assoc_arg peer_arg;
enum wmi_phy_mode peer_phymode;
+ struct ath12k_link_sta *arsta;
+ struct ieee80211_vif *vif;
- arsta = container_of(wk, struct ath12k_sta, update_wk);
- sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+ lockdep_assert_wiphy(wiphy);
+
+ arsta = container_of(wk, struct ath12k_link_sta, update_wk);
+ sta = ath12k_ahsta_to_sta(arsta->ahsta);
arvif = arsta->arvif;
+ vif = ath12k_ahvif_to_vif(arvif->ahvif);
ar = arvif->ar;
- if (WARN_ON(ath12k_mac_vif_chan(arvif->vif, &def)))
+ if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return;
band = def.chan->band;
@@ -4310,14 +4651,12 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
spin_unlock_bh(&ar->data_lock);
- mutex_lock(&ar->conf_mutex);
-
nss = max_t(u32, 1, nss);
nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask),
ath12k_mac_max_vht_nss(vht_mcs_mask)));
if (changed & IEEE80211_RC_BW_CHANGED) {
- ath12k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg);
+ ath12k_peer_assoc_h_phymode(ar, arvif, arsta, &peer_arg);
peer_phymode = peer_arg.peer_phymode;
if (bw > bw_prev) {
@@ -4334,7 +4673,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
if (err) {
ath12k_warn(ar->ab, "failed to update STA %pM to peer phymode %d: %d\n",
sta->addr, peer_phymode, err);
- goto err_rc_bw_changed;
+ return;
}
err = ath12k_wmi_set_peer_param(ar, sta->addr,
arvif->vdev_id, WMI_PEER_CHWIDTH,
@@ -4355,7 +4694,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
if (err) {
ath12k_warn(ar->ab, "failed to update STA %pM peer to bandwidth %d: %d\n",
sta->addr, bw, err);
- goto err_rc_bw_changed;
+ return;
}
err = ath12k_wmi_set_peer_param(ar, sta->addr,
arvif->vdev_id, WMI_PEER_PHYMODE,
@@ -4405,14 +4744,14 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
* across HT/VHT and for multiple VHT MCS support.
*/
if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) {
- ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
+ ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask,
band);
} else {
/* If the peer is non-VHT or no fixed VHT rate
* is provided in the new bitrate mask we set the
* other rates using peer_assoc command.
*/
- ath12k_peer_assoc_prepare(ar, arvif->vif, sta,
+ ath12k_peer_assoc_prepare(ar, arvif, arsta,
&peer_arg, true);
err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
@@ -4425,18 +4764,17 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
sta->addr, arvif->vdev_id);
}
}
-err_rc_bw_changed:
- mutex_unlock(&ar->conf_mutex);
}
-static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif,
- struct ieee80211_sta *sta)
+static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k *ar = arvif->ar;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
+ if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return 0;
if (ar->num_stations >= ar->max_num_stations)
@@ -4447,38 +4785,38 @@ static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif,
return 0;
}
-static void ath12k_mac_dec_num_stations(struct ath12k_vif *arvif,
- struct ieee80211_sta *sta)
+static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta)
{
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k *ar = arvif->ar;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
+ if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
return;
ar->num_stations--;
}
static int ath12k_mac_station_add(struct ath12k *ar,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct ath12k_link_vif *arvif,
+ struct ath12k_link_sta *arsta)
{
struct ath12k_base *ab = ar->ab;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
+ struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta);
struct ath12k_wmi_peer_create_arg peer_param;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- ret = ath12k_mac_inc_num_stations(arvif, sta);
+ ret = ath12k_mac_inc_num_stations(arvif, arsta);
if (ret) {
ath12k_warn(ab, "refusing to associate station: too many connected already (%d)\n",
ar->max_num_stations);
goto exit;
}
-
arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
if (!arsta->rx_stats) {
ret = -ENOMEM;
@@ -4519,7 +4857,7 @@ static int ath12k_mac_station_add(struct ath12k *ar,
if (ab->hw_params->vdev_start_delay &&
!arvif->is_started &&
- arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+ arvif->ahvif->vdev_type != WMI_VDEV_TYPE_AP) {
ret = ath12k_start_vdev_delay(ar, arvif);
if (ret) {
ath12k_warn(ab, "failed to delay vdev start: %d\n", ret);
@@ -4532,7 +4870,7 @@ static int ath12k_mac_station_add(struct ath12k *ar,
free_peer:
ath12k_peer_delete(ar, arvif->vdev_id, sta->addr);
dec_num_station:
- ath12k_mac_dec_num_stations(arvif, sta);
+ ath12k_mac_dec_num_stations(arvif, arsta);
exit:
return ret;
}
@@ -4574,16 +4912,18 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
struct ath12k *ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
+ struct ath12k_link_vif *arvif;
+ struct ath12k_link_sta *arsta;
struct ath12k_peer *peer;
int ret = 0;
- /* cancel must be done outside the mutex to avoid deadlock */
- if ((old_state == IEEE80211_STA_NONE &&
- new_state == IEEE80211_STA_NOTEXIST))
- cancel_work_sync(&arsta->update_wk);
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
+ arsta = &ahsta->deflink;
ar = ath12k_get_ar_by_vif(hw, vif);
if (!ar) {
@@ -4591,21 +4931,28 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
return -EINVAL;
}
- mutex_lock(&ar->conf_mutex);
-
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE) {
memset(arsta, 0, sizeof(*arsta));
+ rcu_assign_pointer(ahsta->link[0], arsta);
+ /* TODO use appropriate link id once MLO support is added */
+ arsta->link_id = ATH12K_DEFAULT_LINK_ID;
+ ahsta->links_map = BIT(arsta->link_id);
+ arsta->ahsta = ahsta;
arsta->arvif = arvif;
- INIT_WORK(&arsta->update_wk, ath12k_sta_rc_update_wk);
+ wiphy_work_init(&arsta->update_wk, ath12k_sta_rc_update_wk);
+
+ synchronize_rcu();
- ret = ath12k_mac_station_add(ar, vif, sta);
+ ret = ath12k_mac_station_add(ar, arvif, arsta);
if (ret)
ath12k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
} else if ((old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)) {
- if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
+ wiphy_work_cancel(hw->wiphy, &arsta->update_wk);
+
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) {
ath12k_bss_disassoc(ar, arvif);
ret = ath12k_mac_vdev_stop(arvif);
if (ret)
@@ -4622,7 +4969,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
- ath12k_mac_dec_num_stations(arvif, sta);
+ ath12k_mac_dec_num_stations(arvif, arsta);
spin_lock_bh(&ar->ab->base_lock);
peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
if (peer && peer->sta == sta) {
@@ -4637,12 +4984,20 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
+
+ if (arsta->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
+ rcu_assign_pointer(ahsta->link[arsta->link_id], NULL);
+ synchronize_rcu();
+ ahsta->links_map &= ~(BIT(arsta->link_id));
+ arsta->link_id = ATH12K_INVALID_LINK_ID;
+ arsta->ahsta = NULL;
+ }
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC &&
(vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_ADHOC)) {
- ret = ath12k_station_assoc(ar, vif, sta, false);
+ ret = ath12k_station_assoc(ar, arvif, arsta, false);
if (ret)
ath12k_warn(ar->ab, "Failed to associate station: %pM\n",
sta->addr);
@@ -4686,14 +5041,12 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
(vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_ADHOC)) {
- ret = ath12k_station_disassoc(ar, vif, sta);
+ ret = ath12k_station_disassoc(ar, arvif, arsta);
if (ret)
ath12k_warn(ar->ab, "Failed to disassociate station: %pM\n",
sta->addr);
}
- mutex_unlock(&ar->conf_mutex);
-
return ret;
}
@@ -4703,25 +5056,32 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
{
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
int ret;
s16 txpwr;
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
+
if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) {
txpwr = 0;
} else {
txpwr = sta->deflink.txpwr.power;
- if (!txpwr)
- return -EINVAL;
+ if (!txpwr) {
+ ret = -EINVAL;
+ goto out;
+ }
}
- if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL)
- return -EINVAL;
+ if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) {
+ ret = -EINVAL;
+ goto out;
+ }
ar = ath12k_ah_to_ar(ah, 0);
- mutex_lock(&ar->conf_mutex);
-
ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
WMI_PEER_USE_FIXED_PWR, txpwr);
if (ret) {
@@ -4731,20 +5091,26 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
}
out:
- mutex_unlock(&ar->conf_mutex);
return ret;
}
static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct ath12k *ar;
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_sta *arsta;
+ struct ath12k_link_vif *arvif;
struct ath12k_peer *peer;
u32 bw, smps;
+ /* TODO: use proper link id once link sta specific rc update support is
+ * available in mac80211.
+ */
+ u8 link_id = ATH12K_DEFAULT_LINK_ID;
ar = ath12k_get_ar_by_vif(hw, vif);
if (!ar) {
@@ -4752,11 +5118,27 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
return;
}
+ rcu_read_lock();
+ arvif = rcu_dereference(ahvif->link[link_id]);
+ if (!arvif) {
+ ath12k_warn(ar->ab, "mac sta rc update failed to fetch link vif on link id %u for peer %pM\n",
+ link_id, sta->addr);
+ rcu_read_unlock();
+ return;
+ }
+ arsta = rcu_dereference(ahsta->link[link_id]);
+ if (!arsta) {
+ rcu_read_unlock();
+ ath12k_warn(ar->ab, "mac sta rc update failed to fetch link sta on link id %u for peer %pM\n",
+ link_id, sta->addr);
+ return;
+ }
spin_lock_bh(&ar->ab->base_lock);
peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
if (!peer) {
spin_unlock_bh(&ar->ab->base_lock);
+ rcu_read_unlock();
ath12k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n",
sta->addr, arvif->vdev_id);
return;
@@ -4808,17 +5190,20 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->data_lock);
- ieee80211_queue_work(hw, &arsta->update_wk);
+ wiphy_work_queue(hw->wiphy, &arsta->update_wk);
+
+ rcu_read_unlock();
}
-static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
+static int ath12k_conf_tx_uapsd(struct ath12k_link_vif *arvif,
u16 ac, bool enable)
{
struct ath12k *ar = arvif->ar;
+ struct ath12k_vif *ahvif = arvif->ahvif;
u32 value;
int ret;
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_STA)
return 0;
switch (ac) {
@@ -4841,19 +5226,19 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
}
if (enable)
- arvif->u.sta.uapsd |= value;
+ ahvif->u.sta.uapsd |= value;
else
- arvif->u.sta.uapsd &= ~value;
+ ahvif->u.sta.uapsd &= ~value;
ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
WMI_STA_PS_PARAM_UAPSD,
- arvif->u.sta.uapsd);
+ ahvif->u.sta.uapsd);
if (ret) {
ath12k_warn(ar->ab, "could not set uapsd params %d\n", ret);
goto exit;
}
- if (arvif->u.sta.uapsd)
+ if (ahvif->u.sta.uapsd)
value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
else
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
@@ -4868,8 +5253,7 @@ exit:
return ret;
}
-static int ath12k_mac_conf_tx(struct ath12k_vif *arvif,
- unsigned int link_id, u16 ac,
+static int ath12k_mac_conf_tx(struct ath12k_link_vif *arvif, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
struct wmi_wmm_params_arg *p = NULL;
@@ -4877,7 +5261,7 @@ static int ath12k_mac_conf_tx(struct ath12k_vif *arvif,
struct ath12k_base *ab = ar->ab;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
switch (ac) {
case IEEE80211_AC_VO:
@@ -4926,26 +5310,30 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params)
{
- struct ath12k *ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_vif_cache *cache = arvif->cache;
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ struct ath12k_vif_cache *cache;
int ret;
- ar = ath12k_get_ar_by_vif(hw, vif);
- if (!ar) {
- /* cache the info and apply after vdev is created */
- cache = ath12k_arvif_get_cache(arvif);
+ lockdep_assert_wiphy(hw->wiphy);
+
+ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
+ return -EINVAL;
+
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ if (!arvif || !arvif->is_created) {
+ cache = ath12k_ahvif_get_link_cache(ahvif, link_id);
if (!cache)
return -ENOSPC;
+
cache->tx_conf.changed = true;
cache->tx_conf.ac = ac;
cache->tx_conf.tx_queue_params = *params;
+
return 0;
}
- mutex_lock(&ar->conf_mutex);
- ret = ath12k_mac_conf_tx(arvif, link_id, ac, params);
- mutex_unlock(&ar->conf_mutex);
+ ret = ath12k_mac_conf_tx(arvif, ac, params);
return ret;
}
@@ -5016,10 +5404,11 @@ ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask
return ht_cap;
}
-static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
+static int ath12k_mac_set_txbf_conf(struct ath12k_link_vif *arvif)
{
u32 value = 0;
struct ath12k *ar = arvif->ar;
+ struct ath12k_vif *ahvif = arvif->ahvif;
int nsts;
int sound_dim;
u32 vht_cap = ar->pdev->cap.vht_cap;
@@ -5047,7 +5436,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
- arvif->vdev_type == WMI_VDEV_TYPE_AP)
+ ahvif->vdev_type == WMI_VDEV_TYPE_AP)
value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
}
@@ -5055,7 +5444,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
- arvif->vdev_type == WMI_VDEV_TYPE_STA)
+ ahvif->vdev_type == WMI_VDEV_TYPE_STA)
value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
}
@@ -5612,7 +6001,7 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant)
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (ath12k_check_chain_mask(ar, tx_ant, true))
return -EINVAL;
@@ -5716,7 +6105,7 @@ static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
return 0;
}
-static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif,
+static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct sk_buff *skb)
{
struct ath12k_base *ab = ar->ab;
@@ -5784,7 +6173,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work)
{
struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work);
struct ath12k_skb_cb *skb_cb;
- struct ath12k_vif *arvif;
+ struct ath12k_vif *ahvif;
+ struct ath12k_link_vif *arvif;
struct sk_buff *skb;
int ret;
@@ -5796,8 +6186,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work)
continue;
}
- arvif = ath12k_vif_to_arvif(skb_cb->vif);
-
+ ahvif = ath12k_vif_to_ahvif(skb_cb->vif);
+ arvif = &ahvif->deflink;
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) {
ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb);
if (ret) {
@@ -5852,18 +6242,18 @@ static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar,
struct sk_buff *skb,
bool is_prb_rsp)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
if (likely(!is_prb_rsp))
return;
spin_lock_bh(&ar->data_lock);
- if (arvif->u.ap.noa_data &&
- !pskb_expand_head(skb, 0, arvif->u.ap.noa_len,
+ if (ahvif->u.ap.noa_data &&
+ !pskb_expand_head(skb, 0, ahvif->u.ap.noa_len,
GFP_ATOMIC))
- skb_put_data(skb, arvif->u.ap.noa_data,
- arvif->u.ap.noa_len);
+ skb_put_data(skb, ahvif->u.ap.noa_data,
+ ahvif->u.ap.noa_len);
spin_unlock_bh(&ar->data_lock);
}
@@ -5875,7 +6265,8 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif = &ahvif->deflink;
struct ath12k *ar = arvif->ar;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
@@ -5939,8 +6330,7 @@ static int ath12k_mac_start(struct ath12k *ar)
int ret;
lockdep_assert_held(&ah->hw_mutex);
-
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS,
1, pdev->pdev_id);
@@ -6025,14 +6415,11 @@ static int ath12k_mac_start(struct ath12k *ar)
}
}
- mutex_unlock(&ar->conf_mutex);
-
rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx],
&ab->pdevs[ar->pdev_idx]);
return 0;
err:
- mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -6052,6 +6439,8 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
struct ath12k *ar;
int ret, i;
+ lockdep_assert_wiphy(hw->wiphy);
+
ath12k_drain_tx(ah);
guard(mutex)(&ah->hw_mutex);
@@ -6158,15 +6547,14 @@ static void ath12k_mac_stop(struct ath12k *ar)
int ret;
lockdep_assert_held(&ah->hw_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- mutex_lock(&ar->conf_mutex);
ret = ath12k_mac_config_mon_status_default(ar, false);
if (ret && (ret != -EOPNOTSUPP))
ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n",
ret);
clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
- mutex_unlock(&ar->conf_mutex);
cancel_delayed_work_sync(&ar->scan.timeout);
cancel_work_sync(&ar->regd_update_work);
@@ -6192,6 +6580,8 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
struct ath12k *ar;
int i;
+ lockdep_assert_wiphy(hw->wiphy);
+
ath12k_drain_tx(ah);
mutex_lock(&ah->hw_mutex);
@@ -6205,7 +6595,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
}
static u8
-ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
+ath12k_mac_get_vdev_stats_id(struct ath12k_link_vif *arvif)
{
struct ath12k_base *ab = arvif->ar->ab;
u8 vdev_stats_id = 0;
@@ -6227,19 +6617,22 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
return vdev_stats_id;
}
-static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif,
+static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_link_vif *arvif,
u32 *flags, u32 *tx_vdev_id)
{
- struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *tx_vif = ahvif->vif->mbssid_tx_vif;
struct ath12k *ar = arvif->ar;
- struct ath12k_vif *tx_arvif;
+ struct ath12k_link_vif *tx_arvif;
+ struct ath12k_vif *tx_ahvif;
if (!tx_vif)
return 0;
- tx_arvif = ath12k_vif_to_arvif(tx_vif);
+ tx_ahvif = ath12k_vif_to_ahvif(tx_vif);
+ tx_arvif = &tx_ahvif->deflink;
- if (arvif->vif->bss_conf.nontransmitted) {
+ if (ahvif->vif->bss_conf.nontransmitted) {
if (ar->ah->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy)
return -EINVAL;
@@ -6251,22 +6644,23 @@ static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif,
return -EINVAL;
}
- if (arvif->vif->bss_conf.ema_ap)
+ if (ahvif->vif->bss_conf.ema_ap)
*flags |= WMI_VDEV_MBSSID_FLAGS_EMA_MODE;
return 0;
}
-static int ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif,
+static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif,
struct ath12k_wmi_vdev_create_arg *arg)
{
struct ath12k *ar = arvif->ar;
struct ath12k_pdev *pdev = ar->pdev;
+ struct ath12k_vif *ahvif = arvif->ahvif;
int ret;
arg->if_id = arvif->vdev_id;
- arg->type = arvif->vdev_type;
- arg->subtype = arvif->vdev_subtype;
+ arg->type = ahvif->vdev_type;
+ arg->subtype = ahvif->vdev_subtype;
arg->pdev_id = pdev->pdev_id;
arg->mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP;
@@ -6333,14 +6727,15 @@ ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype)
}
static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar,
- struct ath12k_vif *arvif)
+ struct ath12k_link_vif *arvif)
{
u32 param_id, param_value;
struct ath12k_base *ab = ar->ab;
+ struct ath12k_vif *ahvif = arvif->ahvif;
int ret;
param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
- param_value = ath12k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
+ param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type);
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
@@ -6363,9 +6758,10 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar,
return ret;
}
-static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
+static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
{
- struct ieee80211_vif *vif = arvif->vif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct ath12k *ar = arvif->ar;
struct ath12k_base *ab = ar->ab;
u32 param_id, param_value;
@@ -6378,14 +6774,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
IEEE80211_OFFLOAD_DECAP_ENABLED);
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
- arvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
+ ahvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
- arvif->tx_encap_type = ATH12K_HW_TXRX_RAW;
+ ahvif->tx_encap_type = ATH12K_HW_TXRX_RAW;
else
- arvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
+ ahvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
- param_id, arvif->tx_encap_type);
+ param_id, ahvif->tx_encap_type);
if (ret) {
ath12k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
arvif->vdev_id, ret);
@@ -6412,57 +6808,86 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ unsigned long links;
+ int link_id;
- ath12k_mac_update_vif_offload(arvif);
+ lockdep_assert_wiphy(hw->wiphy);
+
+ if (vif->valid_links) {
+ links = vif->valid_links;
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ if (!(arvif && arvif->ar))
+ continue;
+
+ ath12k_mac_update_vif_offload(arvif);
+ }
+
+ return;
+ }
+
+ ath12k_mac_update_vif_offload(&ahvif->deflink);
}
-static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
+int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
{
struct ath12k_hw *ah = ar->ah;
struct ath12k_base *ab = ar->ab;
struct ieee80211_hw *hw = ah->hw;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct ath12k_wmi_vdev_create_arg vdev_arg = {0};
struct ath12k_wmi_peer_create_arg peer_param;
+ struct ieee80211_bss_conf *link_conf;
u32 param_id, param_value;
u16 nss;
int i;
int ret, vdev_id;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
+
+ link_conf = wiphy_dereference(hw->wiphy, vif->link_conf[arvif->link_id]);
+ if (!link_conf) {
+ ath12k_warn(ar->ab, "unable to access bss link conf in vdev create for vif %pM link %u\n",
+ vif->addr, arvif->link_id);
+ return -ENOLINK;
+ }
+
+ memcpy(arvif->bssid, link_conf->addr, ETH_ALEN);
arvif->ar = ar;
vdev_id = __ffs64(ab->free_vdev_map);
arvif->vdev_id = vdev_id;
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
+ ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
switch (vif->type) {
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
- arvif->vdev_type = WMI_VDEV_TYPE_STA;
+ ahvif->vdev_type = WMI_VDEV_TYPE_STA;
if (vif->p2p)
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
+ ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
break;
case NL80211_IFTYPE_MESH_POINT:
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
+ ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
fallthrough;
case NL80211_IFTYPE_AP:
- arvif->vdev_type = WMI_VDEV_TYPE_AP;
+ ahvif->vdev_type = WMI_VDEV_TYPE_AP;
if (vif->p2p)
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
+ ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
break;
case NL80211_IFTYPE_MONITOR:
- arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
+ ahvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
ar->monitor_vdev_id = vdev_id;
break;
case NL80211_IFTYPE_P2P_DEVICE:
- arvif->vdev_type = WMI_VDEV_TYPE_STA;
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
+ ahvif->vdev_type = WMI_VDEV_TYPE_STA;
+ ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
break;
default:
WARN_ON(1);
@@ -6470,7 +6895,7 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
}
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n",
- arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+ arvif->vdev_id, ahvif->vdev_type, ahvif->vdev_subtype,
ab->free_vdev_map);
vif->cab_queue = arvif->vdev_id % (ATH12K_HW_MAX_QUEUES - 1);
@@ -6484,11 +6909,11 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
goto err;
}
- ret = ath12k_wmi_vdev_create(ar, vif->addr, &vdev_arg);
+ ret = ath12k_wmi_vdev_create(ar, arvif->bssid, &vdev_arg);
if (ret) {
ath12k_warn(ab, "failed to create WMI vdev %d: %d\n",
arvif->vdev_id, ret);
- goto err;
+ return ret;
}
ar->num_created_vdevs++;
@@ -6513,10 +6938,10 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
goto err_vdev_del;
}
- switch (arvif->vdev_type) {
+ switch (ahvif->vdev_type) {
case WMI_VDEV_TYPE_AP:
peer_param.vdev_id = arvif->vdev_id;
- peer_param.peer_addr = vif->addr;
+ peer_param.peer_addr = arvif->bssid;
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
ret = ath12k_peer_create(ar, arvif, NULL, &peer_param);
if (ret) {
@@ -6589,29 +7014,28 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
}
ath12k_dp_vdev_tx_attach(ar, arvif);
-
if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled)
ath12k_mac_monitor_vdev_create(ar);
- arvif->ar = ar;
return ret;
err_peer_del:
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
reinit_completion(&ar->peer_delete_done);
- ret = ath12k_wmi_send_peer_delete_cmd(ar, vif->addr,
+ ret = ath12k_wmi_send_peer_delete_cmd(ar, arvif->bssid,
arvif->vdev_id);
if (ret) {
ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
- arvif->vdev_id, vif->addr);
+ arvif->vdev_id, arvif->bssid);
goto err;
}
ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id,
- vif->addr);
+ arvif->bssid);
if (ret)
- goto err;
+ /* KVALO: why not goto err? */
+ return ret;
ar->num_peers--;
}
@@ -6633,21 +7057,56 @@ err:
return ret;
}
-static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif *vif)
+static void ath12k_mac_vif_flush_key_cache(struct ath12k_link_vif *arvif)
+{
+ struct ath12k_key_conf *key_conf, *tmp;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ath12k_hw *ah = ahvif->ah;
+ struct ath12k_sta *ahsta;
+ struct ath12k_link_sta *arsta;
+ struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id];
+ int ret;
+
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) {
+ arsta = NULL;
+ if (key_conf->sta) {
+ ahsta = ath12k_sta_to_ahsta(key_conf->sta);
+ arsta = wiphy_dereference(ah->hw->wiphy,
+ ahsta->link[arvif->link_id]);
+ if (!arsta)
+ goto free_cache;
+ }
+
+ ret = ath12k_mac_set_key(arvif->ar, key_conf->cmd,
+ arvif, arsta,
+ key_conf->key);
+ if (ret)
+ ath12k_warn(arvif->ar->ab, "unable to apply set key param to vdev %d ret %d\n",
+ arvif->vdev_id, ret);
+free_cache:
+ list_del(&key_conf->list);
+ kfree(key_conf);
+ }
+}
+
+static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ath12k_link_vif *arvif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_vif_cache *cache = arvif->cache;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+ struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id];
struct ath12k_base *ab = ar->ab;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (!cache)
return;
if (cache->tx_conf.changed) {
- ret = ath12k_mac_conf_tx(arvif, 0, cache->tx_conf.ac,
+ ret = ath12k_mac_conf_tx(arvif, cache->tx_conf.ac,
&cache->tx_conf.tx_queue_params);
if (ret)
ath12k_warn(ab,
@@ -6660,26 +7119,25 @@ static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif
cache->bss_conf_changed);
}
- if (cache->key_conf.changed) {
- ret = ath12k_mac_set_key(ar, cache->key_conf.cmd, vif, NULL,
- cache->key_conf.key);
- if (ret)
- ath12k_warn(ab, "unable to apply set key param to vdev %d ret %d\n",
- arvif->vdev_id, ret);
- }
- ath12k_arvif_put_cache(arvif);
+ if (!list_empty(&cache->key_conf.list))
+ ath12k_mac_vif_flush_key_cache(arvif);
+
+ ath12k_ahvif_put_link_cache(ahvif, arvif->link_id);
}
static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
+ struct ath12k_link_vif *arvif,
struct ieee80211_chanctx_conf *ctx)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ath12k_hw *ah = hw->priv;
- struct ath12k *ar, *prev_ar;
+ struct ath12k *ar;
struct ath12k_base *ab;
+ u8 link_id = arvif->link_id;
int ret;
+ lockdep_assert_wiphy(hw->wiphy);
+
if (ah->num_radio == 1)
ar = ah->radio;
else if (ctx)
@@ -6708,27 +7166,20 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
if (WARN_ON(arvif->is_started))
return NULL;
- /* backup the previously used ar ptr since arvif->ar would
- * be set to NULL after vdev delete is done
- */
- prev_ar = arvif->ar;
- mutex_lock(&prev_ar->conf_mutex);
- ret = ath12k_mac_vdev_delete(prev_ar, vif);
-
- if (ret)
- ath12k_warn(prev_ar->ab, "unable to delete vdev %d\n",
- ret);
- mutex_unlock(&prev_ar->conf_mutex);
+ ath12k_mac_remove_link_interface(hw, arvif);
+ ath12k_mac_unassign_link_vif(arvif);
}
}
ab = ar->ab;
- mutex_lock(&ar->conf_mutex);
-
if (arvif->is_created)
goto flush;
+ /* Assign arvif again here since previous radio switch block
+ * would've unassigned and cleared it.
+ */
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
if (vif->type == NL80211_IFTYPE_AP &&
ar->num_peers > (ar->max_num_peers - 1)) {
ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
@@ -6741,7 +7192,7 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
goto unlock;
}
- ret = ath12k_mac_vdev_create(ar, vif);
+ ret = ath12k_mac_vdev_create(ar, arvif);
if (ret) {
ath12k_warn(ab, "failed to create vdev %pM ret %d", vif->addr, ret);
goto unlock;
@@ -6752,21 +7203,27 @@ flush:
* add_interface(), Apply any parameters for the vdev which were received
* after add_interface, corresponding to this vif.
*/
- ath12k_mac_vif_cache_flush(ar, vif);
+ ath12k_mac_vif_cache_flush(ar, arvif);
unlock:
- mutex_unlock(&ar->conf_mutex);
return arvif->ar;
}
static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
int i;
- memset(arvif, 0, sizeof(*arvif));
+ lockdep_assert_wiphy(hw->wiphy);
- arvif->vif = vif;
+ memset(ahvif, 0, sizeof(*ahvif));
+
+ ahvif->ah = ah;
+ ahvif->vif = vif;
+ arvif = &ahvif->deflink;
+ arvif->ahvif = ahvif;
INIT_LIST_HEAD(&arvif->list);
INIT_DELAYED_WORK(&arvif->connection_loss_work,
@@ -6786,13 +7243,14 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE;
vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
-
- /* For single radio wiphy(i.e ah->num_radio is 1), create the vdev
- * during add_interface itself, for multi radio wiphy, defer the vdev
- * creation until channel_assign to determine the radio on which the
- * vdev needs to be created
+ /* For non-ml vifs, vif->addr is the actual vdev address but for
+ * ML vif link(link BSSID) address is the vdev address and it can be a
+ * different one from vif->addr (i.e ML address).
+ * Defer vdev creation until assign_chanctx or hw_scan is initiated as driver
+ * will not know if this interface is an ML vif at this point.
*/
- ath12k_mac_assign_vif_to_vdev(hw, vif, NULL);
+ ath12k_mac_assign_vif_to_vdev(hw, arvif, NULL);
+
return 0;
}
@@ -6821,14 +7279,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
}
}
-static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
+static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct ath12k_base *ab = ar->ab;
unsigned long time_left;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
reinit_completion(&ar->vdev_delete_done);
ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
@@ -6849,7 +7309,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
ar->num_created_vdevs--;
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ar->monitor_vdev_id = -1;
ar->monitor_vdev_created = false;
} else if (ar->monitor_vdev_created && !ar->monitor_started) {
@@ -6865,7 +7325,7 @@ err_vdev_del:
spin_unlock_bh(&ar->data_lock);
ath12k_peer_cleanup(ar, arvif->vdev_id);
- ath12k_arvif_put_cache(arvif);
+ ath12k_ahvif_put_link_cache(ahvif, arvif->link_id);
idr_for_each(&ar->txmgmt_idr,
ath12k_mac_vif_txmgmt_idr_remove, vif);
@@ -6886,39 +7346,24 @@ err_vdev_del:
static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_base *ab;
- struct ath12k *ar;
- int ret;
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ u8 link_id;
- if (!arvif->is_created) {
+ lockdep_assert_wiphy(hw->wiphy);
+
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
/* if we cached some config but never received assign chanctx,
* free the allocated cache.
*/
- ath12k_arvif_put_cache(arvif);
- return;
- }
-
- ar = arvif->ar;
- ab = ar->ab;
-
- cancel_delayed_work_sync(&arvif->connection_loss_work);
-
- mutex_lock(&ar->conf_mutex);
-
- ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
- arvif->vdev_id);
+ ath12k_ahvif_put_link_cache(ahvif, link_id);
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+ if (!arvif || !arvif->is_created)
+ continue;
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr);
- if (ret)
- ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
- arvif->vdev_id, ret);
+ ath12k_mac_remove_link_interface(hw, arvif);
+ ath12k_mac_unassign_link_vif(arvif);
}
-
- ath12k_mac_vdev_delete(ar, vif);
-
- mutex_unlock(&ar->conf_mutex);
}
/* FIXME: Has to be verified. */
@@ -6937,7 +7382,7 @@ static void ath12k_mac_configure_filter(struct ath12k *ar,
bool reset_flag;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ar->filter_flags = total_flags;
@@ -6962,14 +7407,12 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
- ar = ath12k_ah_to_ar(ah, 0);
+ lockdep_assert_wiphy(hw->wiphy);
- mutex_lock(&ar->conf_mutex);
+ ar = ath12k_ah_to_ar(ah, 0);
*total_flags &= SUPPORTED_FILTERS;
ath12k_mac_configure_filter(ar, *total_flags);
-
- mutex_unlock(&ar->conf_mutex);
}
static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
@@ -6979,11 +7422,11 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *
struct ath12k *ar;
int i;
+ lockdep_assert_wiphy(hw->wiphy);
+
for_each_ar(ah, ar, i) {
- mutex_lock(&ar->conf_mutex);
antennas_rx = max_t(u32, antennas_rx, ar->cfg_rx_chainmask);
antennas_tx = max_t(u32, antennas_tx, ar->cfg_tx_chainmask);
- mutex_unlock(&ar->conf_mutex);
}
*tx_ant = antennas_tx;
@@ -6999,10 +7442,10 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx
int ret = 0;
int i;
+ lockdep_assert_wiphy(hw->wiphy);
+
for_each_ar(ah, ar, i) {
- mutex_lock(&ar->conf_mutex);
ret = __ath12k_set_antenna(ar, tx_ant, rx_ant);
- mutex_unlock(&ar->conf_mutex);
if (ret)
break;
}
@@ -7010,13 +7453,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx
return ret;
}
-static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif,
+static int ath12k_mac_ampdu_action(struct ath12k_link_vif *arvif,
struct ieee80211_ampdu_params *params)
{
struct ath12k *ar = arvif->ar;
int ret = -EINVAL;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
switch (params->action) {
case IEEE80211_AMPDU_RX_START:
@@ -7046,19 +7489,20 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
{
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
int ret = -EINVAL;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_get_ar_by_vif(hw, vif);
if (!ar)
return -EINVAL;
ar = ath12k_ah_to_ar(ah, 0);
+ arvif = &ahvif->deflink;
- mutex_lock(&ar->conf_mutex);
ret = ath12k_mac_ampdu_action(arvif, params);
- mutex_unlock(&ar->conf_mutex);
-
if (ret)
ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n",
ar->pdev_idx, params->action, ret);
@@ -7072,6 +7516,8 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
struct ath12k *ar;
struct ath12k_base *ab;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_get_ar_by_ctx(hw, ctx);
if (!ar)
return -EINVAL;
@@ -7082,8 +7528,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
"mac chanctx add freq %u width %d ptr %p\n",
ctx->def.chan->center_freq, ctx->def.width, ctx);
- mutex_lock(&ar->conf_mutex);
-
spin_lock_bh(&ar->data_lock);
/* TODO: In case of multiple channel context, populate rx_channel from
* Rx PPDU desc information.
@@ -7091,8 +7535,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
ar->rx_channel = ctx->def.chan;
spin_unlock_bh(&ar->data_lock);
- mutex_unlock(&ar->conf_mutex);
-
return 0;
}
@@ -7102,6 +7544,8 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
struct ath12k *ar;
struct ath12k_base *ab;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_get_ar_by_ctx(hw, ctx);
if (!ar)
return;
@@ -7112,16 +7556,12 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
"mac chanctx remove freq %u width %d ptr %p\n",
ctx->def.chan->center_freq, ctx->def.width, ctx);
- mutex_lock(&ar->conf_mutex);
-
spin_lock_bh(&ar->data_lock);
/* TODO: In case of there is one more channel context left, populate
* rx_channel with the channel of that remaining channel context.
*/
ar->rx_channel = NULL;
spin_unlock_bh(&ar->data_lock);
-
- mutex_unlock(&ar->conf_mutex);
}
static enum wmi_phy_mode
@@ -7188,7 +7628,7 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar,
}
static int
-ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
+ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif,
struct ieee80211_chanctx_conf *ctx,
bool restart)
{
@@ -7196,10 +7636,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
struct ath12k_base *ab = ar->ab;
struct wmi_vdev_start_req_arg arg = {};
const struct cfg80211_chan_def *chandef = &ctx->def;
- int he_support = arvif->vif->bss_conf.he_support;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ int he_support = ahvif->vif->bss_conf.he_support;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->vdev_setup_done);
@@ -7215,7 +7656,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode,
chandef->chan->band,
- arvif->vif->type);
+ ahvif->vif->type);
arg.min_power = 0;
arg.max_power = chandef->chan->max_power * 2;
arg.max_reg_power = chandef->chan->max_reg_power * 2;
@@ -7235,10 +7676,10 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
return ret;
}
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- arg.ssid = arvif->u.ap.ssid;
- arg.ssid_len = arvif->u.ap.ssid_len;
- arg.hidden_ssid = arvif->u.ap.hidden_ssid;
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ arg.ssid = ahvif->u.ap.ssid;
+ arg.ssid_len = ahvif->u.ap.ssid_len;
+ arg.hidden_ssid = ahvif->u.ap.hidden_ssid;
/* For now allow DFS for AP mode */
arg.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
@@ -7285,7 +7726,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
ar->num_started_vdevs++;
ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n",
- arvif->vif->addr, arvif->vdev_id);
+ ahvif->vif->addr, arvif->vdev_id);
/* Enable CAC Flag in the driver by checking the channel DFS cac time,
* i.e dfs_cac_ms value which will be valid only for radar channels
@@ -7294,7 +7735,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
* during CAC.
*/
/* TODO: Set the flag for other interface types as required */
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP &&
+ if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP &&
chandef->chan->dfs_cac_ms &&
chandef->chan->dfs_state == NL80211_DFS_USABLE) {
set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
@@ -7311,13 +7752,13 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
return 0;
}
-static int ath12k_mac_vdev_start(struct ath12k_vif *arvif,
+static int ath12k_mac_vdev_start(struct ath12k_link_vif *arvif,
struct ieee80211_chanctx_conf *ctx)
{
return ath12k_mac_vdev_start_restart(arvif, ctx, false);
}
-static int ath12k_mac_vdev_restart(struct ath12k_vif *arvif,
+static int ath12k_mac_vdev_restart(struct ath12k_link_vif *arvif,
struct ieee80211_chanctx_conf *ctx)
{
return ath12k_mac_vdev_start_restart(arvif, ctx, true);
@@ -7335,8 +7776,13 @@ static void
ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_mac_change_chanctx_arg *arg = data;
+ struct ath12k_link_vif *arvif;
+
+ lockdep_assert_wiphy(ahvif->ah->hw->wiphy);
+
+ arvif = &ahvif->deflink;
if (arvif->ar != arg->ar)
return;
@@ -7351,9 +7797,14 @@ static void
ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_mac_change_chanctx_arg *arg = data;
struct ieee80211_chanctx_conf *ctx;
+ struct ath12k_link_vif *arvif;
+
+ lockdep_assert_wiphy(ahvif->ah->hw->wiphy);
+
+ arvif = &ahvif->deflink;
if (arvif->ar != arg->ar)
return;
@@ -7397,13 +7848,13 @@ static u32 ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width)
}
static int ath12k_mac_update_peer_puncturing_width(struct ath12k *ar,
- struct ath12k_vif *arvif,
+ struct ath12k_link_vif *arvif,
struct cfg80211_chan_def def)
{
u32 param_id, param_value;
int ret;
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA)
return 0;
param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP;
@@ -7429,17 +7880,19 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
{
struct ath12k_wmi_vdev_up_params params = {};
struct ath12k_base *ab = ar->ab;
+ struct ath12k_link_vif *arvif;
struct ieee80211_vif *vif;
- struct ath12k_vif *arvif;
+ struct ath12k_vif *ahvif;
int ret;
int i;
bool monitor_vif = false;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
for (i = 0; i < n_vifs; i++) {
vif = vifs[i].vif;
- arvif = ath12k_vif_to_arvif(vif);
+ ahvif = ath12k_vif_to_ahvif(vif);
+ arvif = &ahvif->deflink;
if (vif->type == NL80211_IFTYPE_MONITOR)
monitor_vif = true;
@@ -7489,10 +7942,14 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
memset(&params, 0, sizeof(params));
params.vdev_id = arvif->vdev_id;
- params.aid = arvif->aid;
+ params.aid = ahvif->aid;
params.bssid = arvif->bssid;
if (vif->mbssid_tx_vif) {
- params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid;
+ struct ath12k_vif *ahvif =
+ ath12k_vif_to_ahvif(vif->mbssid_tx_vif);
+ struct ath12k_link_vif *arvif = &ahvif->deflink;
+
+ params.tx_bssid = arvif->bssid;
params.nontx_profile_idx = vif->bss_conf.bssid_index;
params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator;
}
@@ -7528,7 +7985,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar,
struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx, .ar = ar };
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ieee80211_iterate_active_interfaces_atomic(hw,
IEEE80211_IFACE_ITER_NORMAL,
@@ -7558,14 +8015,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
struct ath12k *ar;
struct ath12k_base *ab;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_get_ar_by_ctx(hw, ctx);
if (!ar)
return;
ab = ar->ab;
- mutex_lock(&ar->conf_mutex);
-
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx change freq %u width %d ptr %p changed %x\n",
ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
@@ -7574,7 +8031,7 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
* switch_vif_chanctx().
*/
if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
- goto unlock;
+ return;
if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH ||
changed & IEEE80211_CHANCTX_CHANGE_RADAR ||
@@ -7582,16 +8039,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
ath12k_mac_update_active_vif_chan(ar, ctx);
/* TODO: Recalc radar detection */
-
-unlock:
- mutex_unlock(&ar->conf_mutex);
}
static int ath12k_start_vdev_delay(struct ath12k *ar,
- struct ath12k_vif *arvif)
+ struct ath12k_link_vif *arvif)
{
struct ath12k_base *ab = ar->ab;
- struct ieee80211_vif *vif = arvif->vif;
+ struct ath12k_vif *ahvif = arvif->ahvif;
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
int ret;
if (WARN_ON(arvif->is_started))
@@ -7605,7 +8060,7 @@ static int ath12k_start_vdev_delay(struct ath12k *ar,
return ret;
}
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ret = ath12k_monitor_vdev_up(ar, arvif->vdev_id);
if (ret) {
ath12k_warn(ab, "failed put monitor up: %d\n", ret);
@@ -7625,24 +8080,37 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx)
{
+ struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
struct ath12k_base *ab;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ u8 link_id = link_conf->link_id;
+ struct ath12k_link_vif *arvif;
int ret;
+ lockdep_assert_wiphy(hw->wiphy);
+
/* For multi radio wiphy, the vdev was not created during add_interface
* create now since we have a channel ctx now to assign to a specific ar/fw
*/
- ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx);
- if (!ar) {
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
+ if (!arvif) {
WARN_ON(1);
+ return -ENOMEM;
+ }
+
+ if (!arvif->is_started) {
+ ar = ath12k_mac_assign_vif_to_vdev(hw, arvif, ctx);
+ if (!ar)
+ return -EINVAL;
+ } else {
+ ath12k_warn(arvif->ar->ab, "failed to assign chanctx for vif %pM link id %u link vif is already started",
+ vif->addr, link_id);
return -EINVAL;
}
ab = ar->ab;
- mutex_lock(&ar->conf_mutex);
-
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx assign ptr %p vdev_id %i\n",
ctx, arvif->vdev_id);
@@ -7651,8 +8119,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
/* for some targets bss peer must be created before vdev_start */
if (ab->hw_params->vdev_start_delay &&
- arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
+ ahvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
!ath12k_peer_exist_by_vdev_id(ab, arvif->vdev_id)) {
memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
ret = 0;
@@ -7664,10 +8132,11 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out;
}
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ret = ath12k_mac_monitor_start(ar);
if (ret)
goto out;
+
arvif->is_started = true;
goto out;
}
@@ -7680,7 +8149,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out;
}
- if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created)
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created)
ath12k_mac_monitor_start(ar);
arvif->is_started = true;
@@ -7688,8 +8157,6 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
/* TODO: Setup ps and cts/rts protection */
out:
- mutex_unlock(&ar->conf_mutex);
-
return ret;
}
@@ -7701,9 +8168,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
{
struct ath12k *ar;
struct ath12k_base *ab;
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
+ u8 link_id = link_conf->link_id;
int ret;
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
+
/* The vif is expected to be attached to an ar's VDEV.
* We leave the vif/vdev in this function as is
* and not delete the vdev symmetric to assign_vif_chanctx()
@@ -7711,32 +8184,28 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
* remove_interface() or when there is a change in channel
* that moves the vif to a new ar
*/
- if (!arvif->is_created)
+ if (!arvif || !arvif->is_created)
return;
ar = arvif->ar;
ab = ar->ab;
- mutex_lock(&ar->conf_mutex);
-
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx unassign ptr %p vdev_id %i\n",
ctx, arvif->vdev_id);
WARN_ON(!arvif->is_started);
- if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
+ if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ret = ath12k_mac_monitor_stop(ar);
- if (ret) {
- mutex_unlock(&ar->conf_mutex);
+ if (ret)
return;
- }
arvif->is_started = false;
}
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA &&
- arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_STA &&
+ ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
ath12k_bss_disassoc(ar, arvif);
ret = ath12k_mac_vdev_stop(arvif);
if (ret)
@@ -7745,11 +8214,12 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
}
arvif->is_started = false;
- if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
ar->num_started_vdevs == 1 && ar->monitor_vdev_created)
ath12k_mac_monitor_stop(ar);
- mutex_unlock(&ar->conf_mutex);
+ ath12k_mac_remove_link_interface(hw, arvif);
+ ath12k_mac_unassign_link_vif(arvif);
}
static int
@@ -7760,35 +8230,32 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
{
struct ath12k *ar;
+ lockdep_assert_wiphy(hw->wiphy);
+
ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
if (!ar)
return -EINVAL;
- mutex_lock(&ar->conf_mutex);
-
/* Switching channels across radio is not allowed */
- if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) {
- mutex_unlock(&ar->conf_mutex);
+ if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx))
return -EINVAL;
- }
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"mac chanctx switch n_vifs %d mode %d\n",
n_vifs, mode);
ath12k_mac_update_vif_chan(ar, vifs, n_vifs);
- mutex_unlock(&ar->conf_mutex);
-
return 0;
}
static int
ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret = 0;
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+
list_for_each_entry(arvif, &ar->arvifs, list) {
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "setting mac vdev %d param %d value %d\n",
param, arvif->vdev_id, value);
@@ -7801,7 +8268,7 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value)
break;
}
}
- mutex_unlock(&ar->conf_mutex);
+
return ret;
}
@@ -7814,6 +8281,8 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
struct ath12k *ar;
int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i;
+ lockdep_assert_wiphy(hw->wiphy);
+
/* Currently we set the rts threshold value to all the vifs across
* all radios of the single wiphy.
* TODO Once support for vif specific RTS threshold in mac80211 is
@@ -7843,6 +8312,9 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
* supported. This effectively prevents mac80211 from doing frame
* fragmentation in software.
*/
+
+ lockdep_assert_wiphy(hw->wiphy);
+
return -EOPNOTSUPP;
}
@@ -7887,6 +8359,8 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v
struct ath12k *ar;
int i;
+ lockdep_assert_wiphy(hw->wiphy);
+
if (drop)
return;
@@ -8020,14 +8494,14 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar,
return 0;
}
-static int ath12k_mac_set_fixed_rate_params(struct ath12k_vif *arvif,
+static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif,
u32 rate, u8 nss, u8 sgi, u8 ldpc)
{
struct ath12k *ar = arvif->ar;
u32 vdev_param;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n",
arvif->vdev_id, rate, nss, sgi);
@@ -8099,8 +8573,9 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar,
static void ath12k_mac_set_bitrate_mask_iter(void *data,
struct ieee80211_sta *sta)
{
- struct ath12k_vif *arvif = data;
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
+ struct ath12k_link_vif *arvif = data;
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+ struct ath12k_link_sta *arsta = &ahsta->deflink;
struct ath12k *ar = arvif->ar;
if (arsta->arvif != arvif)
@@ -8110,14 +8585,15 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data,
arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
spin_unlock_bh(&ar->data_lock);
- ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk);
+ wiphy_work_queue(ath12k_ar_to_hw(ar)->wiphy, &arsta->update_wk);
}
static void ath12k_mac_disable_peer_fixed_rate(void *data,
struct ieee80211_sta *sta)
{
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
- struct ath12k_vif *arvif = data;
+ struct ath12k_link_vif *arvif = data;
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+ struct ath12k_link_sta *arsta = &ahsta->deflink;
struct ath12k *ar = arvif->ar;
int ret;
@@ -8139,9 +8615,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_link_vif *arvif;
struct cfg80211_chan_def def;
- struct ath12k *ar = arvif->ar;
+ struct ath12k *ar;
enum nl80211_band band;
const u8 *ht_mcs_mask;
const u16 *vht_mcs_mask;
@@ -8153,8 +8630,15 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
int ret;
int num_rates;
- if (ath12k_mac_vif_chan(vif, &def))
- return -EPERM;
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
+
+ ar = arvif->ar;
+ if (ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) {
+ ret = -EPERM;
+ goto out;
+ }
band = def.chan->band;
ht_mcs_mask = mask->control[band].ht_mcs;
@@ -8183,9 +8667,9 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
goto out;
}
- ieee80211_iterate_stations_atomic(hw,
- ath12k_mac_disable_peer_fixed_rate,
- arvif);
+ ieee80211_iterate_stations_mtx(hw,
+ ath12k_mac_disable_peer_fixed_rate,
+ arvif);
} else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask,
&single_nss)) {
rate = WMI_FIXED_RATE_NONE;
@@ -8226,34 +8710,25 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
*/
ath12k_warn(ar->ab,
"Setting more than one MCS Value in bitrate mask not supported\n");
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- ieee80211_iterate_stations_atomic(hw,
- ath12k_mac_disable_peer_fixed_rate,
- arvif);
-
- mutex_lock(&ar->conf_mutex);
+ ieee80211_iterate_stations_mtx(hw,
+ ath12k_mac_disable_peer_fixed_rate,
+ arvif);
arvif->bitrate_mask = *mask;
- ieee80211_iterate_stations_atomic(hw,
- ath12k_mac_set_bitrate_mask_iter,
- arvif);
-
- mutex_unlock(&ar->conf_mutex);
+ ieee80211_iterate_stations_mtx(hw,
+ ath12k_mac_set_bitrate_mask_iter,
+ arvif);
}
- mutex_lock(&ar->conf_mutex);
-
ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
if (ret) {
ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n",
arvif->vdev_id, ret);
}
- mutex_unlock(&ar->conf_mutex);
-
out:
return ret;
}
@@ -8265,9 +8740,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar;
struct ath12k_base *ab;
- struct ath12k_vif *arvif;
+ struct ath12k_vif *ahvif;
+ struct ath12k_link_vif *arvif;
int recovery_count, i;
+ lockdep_assert_wiphy(hw->wiphy);
+
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;
@@ -8280,8 +8758,6 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
ieee80211_wake_queues(hw);
for_each_ar(ah, ar, i) {
- mutex_lock(&ar->conf_mutex);
-
ab = ar->ab;
ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
@@ -8306,11 +8782,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
}
list_for_each_entry(arvif, &ar->arvifs, list) {
+ ahvif = arvif->ahvif;
ath12k_dbg(ab, ATH12K_DBG_BOOT,
"reconfig cipher %d up %d vdev type %d\n",
- arvif->key_cipher,
+ ahvif->key_cipher,
arvif->is_up,
- arvif->vdev_type);
+ ahvif->vdev_type);
/* After trigger disconnect, then upper layer will
* trigger connect again, then the PN number of
@@ -8318,16 +8795,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
* side, hence PN number mismatch will not happen.
*/
if (arvif->is_up &&
- arvif->vdev_type == WMI_VDEV_TYPE_STA &&
- arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
- ieee80211_hw_restart_disconnect(arvif->vif);
+ ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
+ ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
+ ieee80211_hw_restart_disconnect(ahvif->vif);
ath12k_dbg(ab, ATH12K_DBG_BOOT,
"restart disconnect\n");
}
}
-
- mutex_unlock(&ar->conf_mutex);
}
}
@@ -8338,7 +8813,7 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar,
int ret;
enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) ||
ar->rx_channel != channel)
@@ -8370,6 +8845,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
struct ieee80211_supported_band *sband;
struct survey_info *ar_survey;
+ lockdep_assert_wiphy(hw->wiphy);
+
if (idx >= ATH12K_NUM_CHANS)
return -ENOENT;
@@ -8403,8 +8880,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
ar_survey = &ar->survey[idx];
- mutex_lock(&ar->conf_mutex);
-
ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
spin_lock_bh(&ar->data_lock);
@@ -8416,7 +8891,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
if (ar->rx_channel == survey->channel)
survey->filled |= SURVEY_INFO_IN_USE;
- mutex_unlock(&ar->conf_mutex);
return 0;
}
@@ -8425,7 +8899,12 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
- struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
+ struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
+ struct ath12k_link_sta *arsta;
+
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arsta = &ahsta->deflink;
sinfo->rx_duration = arsta->rx_duration;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
@@ -8462,7 +8941,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
ar = ath12k_ah_to_ar(ah, 0);
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
spin_lock_bh(&ar->data_lock);
ar->scan.roc_notify = false;
@@ -8470,8 +8949,6 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
ath12k_scan_abort(ar);
- mutex_unlock(&ar->conf_mutex);
-
cancel_delayed_work_sync(&ar->scan.timeout);
return 0;
@@ -8483,24 +8960,31 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
int duration,
enum ieee80211_roc_type type)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k_wmi_scan_req_arg arg;
- struct ath12k *ar, *prev_ar;
+ struct ath12k_link_vif *arvif;
+ struct ath12k *ar;
u32 scan_time_msec;
bool create = true;
+ u8 link_id;
int ret;
- if (ah->num_radio == 1) {
- WARN_ON(!arvif->is_created);
- ar = ath12k_ah_to_ar(ah, 0);
- goto scan;
- }
+ lockdep_assert_wiphy(hw->wiphy);
ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq);
- if (!ar)
- return -EINVAL;
+ if (!ar) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ /* check if any of the links of ML VIF is already started on
+ * radio(ar) correpsondig to given scan frequency and use it,
+ * if not use deflink(link 0) for scan purpose.
+ */
+
+ link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar);
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
/* If the vif is already assigned to a specific vdev of an ar,
* check whether its already started, vdev which is started
* are not allowed to switch to a new radio.
@@ -8511,44 +8995,35 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
* always on the same band for the vif
*/
if (arvif->is_created) {
- if (WARN_ON(!arvif->ar))
- return -EINVAL;
+ if (WARN_ON(!arvif->ar)) {
+ ret = -EINVAL;
+ goto exit;
+ }
- if (ar != arvif->ar && arvif->is_started)
- return -EBUSY;
+ if (ar != arvif->ar && arvif->is_started) {
+ ret = -EBUSY;
+ goto exit;
+ }
if (ar != arvif->ar) {
- /* backup the previously used ar ptr, since the vdev delete
- * would assign the arvif->ar to NULL after the call
- */
- prev_ar = arvif->ar;
- mutex_lock(&prev_ar->conf_mutex);
- ret = ath12k_mac_vdev_delete(prev_ar, vif);
- mutex_unlock(&prev_ar->conf_mutex);
- if (ret) {
- ath12k_warn(prev_ar->ab,
- "unable to delete scan vdev for roc: %d\n",
- ret);
- return ret;
- }
+ ath12k_mac_remove_link_interface(hw, arvif);
+ ath12k_mac_unassign_link_vif(arvif);
} else {
create = false;
}
}
if (create) {
- mutex_lock(&ar->conf_mutex);
- ret = ath12k_mac_vdev_create(ar, vif);
- mutex_unlock(&ar->conf_mutex);
+ arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
+
+ ret = ath12k_mac_vdev_create(ar, arvif);
if (ret) {
ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n",
ret);
- return -EINVAL;
+ goto exit;
}
}
-scan:
- mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
switch (ar->scan.state) {
@@ -8623,9 +9098,8 @@ scan:
free_chan_list:
kfree(arg.chan_list);
-exit:
- mutex_unlock(&ar->conf_mutex);
+exit:
return ret;
}
@@ -8633,16 +9107,20 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_gtk_rekey_data *data)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
- struct ath12k_rekey_data *rekey_data = &arvif->rekey_data;
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ struct ath12k_rekey_data *rekey_data;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
+ struct ath12k_link_vif *arvif;
+
+ lockdep_assert_wiphy(hw->wiphy);
+
+ arvif = &ahvif->deflink;
+ rekey_data = &arvif->rekey_data;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set rekey data vdev %d\n",
arvif->vdev_id);
- mutex_lock(&ar->conf_mutex);
-
memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN);
memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN);
@@ -8659,8 +9137,6 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw,
rekey_data->kck, NL80211_KEK_LEN);
ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "replay ctr", NULL,
&rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr));
-
- mutex_unlock(&ar->conf_mutex);
}
static const struct ieee80211_ops ath12k_ops = {
@@ -8673,7 +9149,9 @@ static const struct ieee80211_ops ath12k_ops = {
.remove_interface = ath12k_mac_op_remove_interface,
.update_vif_offload = ath12k_mac_op_update_vif_offload,
.config = ath12k_mac_op_config,
- .bss_info_changed = ath12k_mac_op_bss_info_changed,
+ .link_info_changed = ath12k_mac_op_link_info_changed,
+ .vif_cfg_changed = ath12k_mac_op_vif_cfg_changed,
+ .change_vif_links = ath12k_mac_op_change_vif_links,
.configure_filter = ath12k_mac_op_configure_filter,
.hw_scan = ath12k_mac_op_hw_scan,
.cancel_hw_scan = ath12k_mac_op_cancel_hw_scan,
@@ -8681,7 +9159,7 @@ static const struct ieee80211_ops ath12k_ops = {
.set_rekey_data = ath12k_mac_op_set_rekey_data,
.sta_state = ath12k_mac_op_sta_state,
.sta_set_txpwr = ath12k_mac_op_sta_set_txpwr,
- .sta_rc_update = ath12k_mac_op_sta_rc_update,
+ .link_sta_rc_update = ath12k_mac_op_sta_rc_update,
.conf_tx = ath12k_mac_op_conf_tx,
.set_antenna = ath12k_mac_op_set_antenna,
.get_antenna = ath12k_mac_op_get_antenna,
@@ -9320,7 +9798,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
spin_lock_init(&ar->data_lock);
INIT_LIST_HEAD(&ar->arvifs);
INIT_LIST_HEAD(&ar->ppdu_stats_info);
- mutex_init(&ar->conf_mutex);
+
init_completion(&ar->vdev_setup_done);
init_completion(&ar->vdev_delete_done);
init_completion(&ar->peer_assoc_done);
@@ -9501,7 +9979,7 @@ err:
return ret;
}
-int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif,
+int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
enum wmi_sta_keepalive_method method,
u32 interval)
{
@@ -9509,9 +9987,9 @@ int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif,
struct ath12k *ar = arvif->ar;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA)
return 0;
if (!test_bit(WMI_TLV_SERVICE_STA_KEEP_ALIVE, ar->ab->wmi_ab.svc_map))
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 5efbb6822628..d382337ba649 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -41,6 +41,9 @@ struct ath12k_generic_iter {
#define ATH12K_TX_POWER_MAX_VAL 70
#define ATH12K_TX_POWER_MIN_VAL 0
+#define ATH12K_DEFAULT_LINK_ID 0
+#define ATH12K_INVALID_LINK_ID 255
+
enum ath12k_supported_bw {
ATH12K_BW_20 = 0,
ATH12K_BW_40 = 1,
@@ -65,9 +68,9 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
void __ath12k_mac_scan_finish(struct ath12k *ar);
void ath12k_mac_scan_finish(struct ath12k *ar);
-struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id);
-struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
- u32 vdev_id);
+struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id);
+struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
+ u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
@@ -82,7 +85,7 @@ int ath12k_mac_rfkill_config(struct ath12k *ar);
int ath12k_mac_wait_tx_complete(struct ath12k *ar);
void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb);
void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id);
-int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif,
+int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
enum wmi_sta_keepalive_method method,
u32 interval);
u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar);
diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c
index df96b0f91f54..2f6d14382ed7 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.c
+++ b/drivers/net/wireless/ath/ath12k/mhi.c
@@ -649,3 +649,8 @@ void ath12k_mhi_resume(struct ath12k_pci *ab_pci)
{
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME);
}
+
+void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic)
+{
+ mhi_download_rddm_image(mhi_ctrl, in_panic);
+}
diff --git a/drivers/net/wireless/ath/ath12k/mhi.h b/drivers/net/wireless/ath/ath12k/mhi.h
index 9362ad1958c3..7358b8477536 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.h
+++ b/drivers/net/wireless/ath/ath12k/mhi.h
@@ -43,5 +43,5 @@ void ath12k_mhi_clear_vector(struct ath12k_base *ab);
void ath12k_mhi_suspend(struct ath12k_pci *ar_pci);
void ath12k_mhi_resume(struct ath12k_pci *ar_pci);
-
+void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c
index 3a851ee15b2f..84cccf7d91e7 100644
--- a/drivers/net/wireless/ath/ath12k/p2p.c
+++ b/drivers/net/wireless/ath/ath12k/p2p.c
@@ -69,20 +69,20 @@ static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info
return len;
}
-static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie,
+static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif *arvif, void *ie,
size_t len)
{
struct ath12k *ar = arvif->ar;
lockdep_assert_held(&ar->data_lock);
- kfree(arvif->u.ap.noa_data);
+ kfree(arvif->ahvif->u.ap.noa_data);
- arvif->u.ap.noa_data = ie;
- arvif->u.ap.noa_len = len;
+ arvif->ahvif->u.ap.noa_data = ie;
+ arvif->ahvif->u.ap.noa_len = len;
}
-static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif,
+static void __ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
const struct ath12k_wmi_p2p_noa_info *noa)
{
struct ath12k *ar = arvif->ar;
@@ -105,7 +105,7 @@ static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif,
ath12k_p2p_noa_ie_assign(arvif, ie, len);
}
-void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
+void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
const struct ath12k_wmi_p2p_noa_info *noa)
{
struct ath12k *ar = arvif->ar;
@@ -118,9 +118,12 @@ void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+ struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_p2p_noa_arg *arg = data;
+ struct ath12k_link_vif *arvif;
+ WARN_ON(!rcu_read_lock_any_held());
+ arvif = &ahvif->deflink;
if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
return;
diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h
index b2eec51a9900..03ee877e6d6b 100644
--- a/drivers/net/wireless/ath/ath12k/p2p.h
+++ b/drivers/net/wireless/ath/ath12k/p2p.h
@@ -16,7 +16,7 @@ struct ath12k_p2p_noa_arg {
const struct ath12k_wmi_p2p_noa_info *noa;
};
-void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
+void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
const struct ath12k_wmi_p2p_noa_info *noa);
void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id,
const struct ath12k_wmi_p2p_noa_info *noa);
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index bd269aa1740b..cf907550e6a4 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -7,6 +7,8 @@
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
#include "pci.h"
#include "core.h"
@@ -425,9 +427,9 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab)
}
}
-static void ath12k_pci_ce_tasklet(struct tasklet_struct *t)
+static void ath12k_pci_ce_workqueue(struct work_struct *work)
{
- struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
+ struct ath12k_ce_pipe *ce_pipe = from_work(ce_pipe, work, intr_wq);
int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
@@ -449,7 +451,7 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)
disable_irq_nosync(ab->irq_num[irq_idx]);
- tasklet_schedule(&ce_pipe->intr_tq);
+ queue_work(system_bh_wq, &ce_pipe->intr_wq);
return IRQ_HANDLED;
}
@@ -675,7 +677,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab)
irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;
- tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet);
+ INIT_WORK(&ce_pipe->intr_wq, ath12k_pci_ce_workqueue);
ret = request_irq(irq, ath12k_pci_ce_interrupt_handler,
ab_pci->irq_flags, irq_name[irq_idx],
@@ -962,7 +964,7 @@ static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci)
PCI_EXP_LNKCTL_ASPMC);
}
-static void ath12k_pci_kill_tasklets(struct ath12k_base *ab)
+static void ath12k_pci_cancel_workqueue(struct ath12k_base *ab)
{
int i;
@@ -972,7 +974,7 @@ static void ath12k_pci_kill_tasklets(struct ath12k_base *ab)
if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
continue;
- tasklet_kill(&ce_pipe->intr_tq);
+ cancel_work_sync(&ce_pipe->intr_wq);
}
}
@@ -980,7 +982,7 @@ static void ath12k_pci_ce_irq_disable_sync(struct ath12k_base *ab)
{
ath12k_pci_ce_irqs_disable(ab);
ath12k_pci_sync_ce_irqs(ab);
- ath12k_pci_kill_tasklets(ab);
+ ath12k_pci_cancel_workqueue(ab);
}
int ath12k_pci_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,
@@ -1259,6 +1261,186 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)
ab_pci->pci_ops->release(ab);
}
+#ifdef CONFIG_ATH12K_COREDUMP
+static int ath12k_pci_coredump_calculate_size(struct ath12k_base *ab, u32 *dump_seg_sz)
+{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
+ struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
+ struct image_info *rddm_img, *fw_img;
+ struct ath12k_tlv_dump_data *dump_tlv;
+ enum ath12k_fw_crash_dump_type mem_type;
+ u32 len = 0, rddm_tlv_sz = 0, paging_tlv_sz = 0;
+ struct ath12k_dump_file_data *file_data;
+ int i;
+
+ rddm_img = mhi_ctrl->rddm_image;
+ if (!rddm_img) {
+ ath12k_err(ab, "No RDDM dump found\n");
+ return 0;
+ }
+
+ fw_img = mhi_ctrl->fbc_image;
+
+ for (i = 0; i < fw_img->entries ; i++) {
+ if (!fw_img->mhi_buf[i].buf)
+ continue;
+
+ paging_tlv_sz += fw_img->mhi_buf[i].len;
+ }
+ dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA] = paging_tlv_sz;
+
+ for (i = 0; i < rddm_img->entries; i++) {
+ if (!rddm_img->mhi_buf[i].buf)
+ continue;
+
+ rddm_tlv_sz += rddm_img->mhi_buf[i].len;
+ }
+ dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA] = rddm_tlv_sz;
+
+ for (i = 0; i < ab->qmi.mem_seg_count; i++) {
+ mem_type = ath12k_coredump_get_dump_type(ab->qmi.target_mem[i].type);
+
+ if (mem_type == FW_CRASH_DUMP_NONE)
+ continue;
+
+ if (mem_type == FW_CRASH_DUMP_TYPE_MAX) {
+ ath12k_dbg(ab, ATH12K_DBG_PCI,
+ "target mem region type %d not supported",
+ ab->qmi.target_mem[i].type);
+ continue;
+ }
+
+ if (!ab->qmi.target_mem[i].paddr)
+ continue;
+
+ dump_seg_sz[mem_type] += ab->qmi.target_mem[i].size;
+ }
+
+ for (i = 0; i < FW_CRASH_DUMP_TYPE_MAX; i++) {
+ if (!dump_seg_sz[i])
+ continue;
+
+ len += sizeof(*dump_tlv) + dump_seg_sz[i];
+ }
+
+ if (len)
+ len += sizeof(*file_data);
+
+ return len;
+}
+
+static void ath12k_pci_coredump_download(struct ath12k_base *ab)
+{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
+ struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
+ struct image_info *rddm_img, *fw_img;
+ struct timespec64 timestamp;
+ int i, len, mem_idx;
+ enum ath12k_fw_crash_dump_type mem_type;
+ struct ath12k_dump_file_data *file_data;
+ struct ath12k_tlv_dump_data *dump_tlv;
+ size_t hdr_len = sizeof(*file_data);
+ void *buf;
+ u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 };
+
+ ath12k_mhi_coredump(mhi_ctrl, false);
+
+ len = ath12k_pci_coredump_calculate_size(ab, dump_seg_sz);
+ if (!len) {
+ ath12k_warn(ab, "No crash dump data found for devcoredump");
+ return;
+ }
+
+ rddm_img = mhi_ctrl->rddm_image;
+ fw_img = mhi_ctrl->fbc_image;
+
+ /* dev_coredumpv() requires vmalloc data */
+ buf = vzalloc(len);
+ if (!buf)
+ return;
+
+ ab->dump_data = buf;
+ ab->ath12k_coredump_len = len;
+ file_data = ab->dump_data;
+ strscpy(file_data->df_magic, "ATH12K-FW-DUMP", sizeof(file_data->df_magic));
+ file_data->len = cpu_to_le32(len);
+ file_data->version = cpu_to_le32(ATH12K_FW_CRASH_DUMP_V2);
+ file_data->chip_id = cpu_to_le32(ab_pci->dev_id);
+ file_data->qrtr_id = cpu_to_le32(ab_pci->ab->qmi.service_ins_id);
+ file_data->bus_id = cpu_to_le32(pci_domain_nr(ab_pci->pdev->bus));
+ guid_gen(&file_data->guid);
+ ktime_get_real_ts64(&timestamp);
+ file_data->tv_sec = cpu_to_le64(timestamp.tv_sec);
+ file_data->tv_nsec = cpu_to_le64(timestamp.tv_nsec);
+ buf += hdr_len;
+ dump_tlv = buf;
+ dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_PAGING_DATA);
+ dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA]);
+ buf += COREDUMP_TLV_HDR_SIZE;
+
+ /* append all segments together as they are all part of a single contiguous
+ * block of memory
+ */
+ for (i = 0; i < fw_img->entries ; i++) {
+ if (!fw_img->mhi_buf[i].buf)
+ continue;
+
+ memcpy_fromio(buf, (void const __iomem *)fw_img->mhi_buf[i].buf,
+ fw_img->mhi_buf[i].len);
+ buf += fw_img->mhi_buf[i].len;
+ }
+
+ dump_tlv = buf;
+ dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_RDDM_DATA);
+ dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA]);
+ buf += COREDUMP_TLV_HDR_SIZE;
+
+ /* append all segments together as they are all part of a single contiguous
+ * block of memory
+ */
+ for (i = 0; i < rddm_img->entries; i++) {
+ if (!rddm_img->mhi_buf[i].buf)
+ continue;
+
+ memcpy_fromio(buf, (void const __iomem *)rddm_img->mhi_buf[i].buf,
+ rddm_img->mhi_buf[i].len);
+ buf += rddm_img->mhi_buf[i].len;
+ }
+
+ mem_idx = FW_CRASH_DUMP_REMOTE_MEM_DATA;
+ for (; mem_idx < FW_CRASH_DUMP_TYPE_MAX; mem_idx++) {
+ if (!dump_seg_sz[mem_idx] || mem_idx == FW_CRASH_DUMP_NONE)
+ continue;
+
+ dump_tlv = buf;
+ dump_tlv->type = cpu_to_le32(mem_idx);
+ dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[mem_idx]);
+ buf += COREDUMP_TLV_HDR_SIZE;
+
+ for (i = 0; i < ab->qmi.mem_seg_count; i++) {
+ mem_type = ath12k_coredump_get_dump_type
+ (ab->qmi.target_mem[i].type);
+
+ if (mem_type != mem_idx)
+ continue;
+
+ if (!ab->qmi.target_mem[i].paddr) {
+ ath12k_dbg(ab, ATH12K_DBG_PCI,
+ "Skipping mem region type %d",
+ ab->qmi.target_mem[i].type);
+ continue;
+ }
+
+ memcpy_fromio(buf, ab->qmi.target_mem[i].v.ioaddr,
+ ab->qmi.target_mem[i].size);
+ buf += ab->qmi.target_mem[i].size;
+ }
+ }
+
+ queue_work(ab->workqueue, &ab->dump_work);
+}
+#endif
+
int ath12k_pci_power_up(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
@@ -1329,6 +1511,9 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
.ce_irq_disable = ath12k_pci_hif_ce_irq_disable,
.get_ce_msi_idx = ath12k_pci_get_ce_msi_idx,
.panic_handler = ath12k_pci_panic_handler,
+#ifdef CONFIG_ATH12K_COREDUMP
+ .coredump_download = ath12k_pci_coredump_download,
+#endif
};
static
@@ -1538,6 +1723,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
set_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags);
cancel_work_sync(&ab->reset_work);
+ cancel_work_sync(&ab->dump_work);
ath12k_core_deinit(ab);
qmi_fail:
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 19c0626fbff1..7a62665b8af9 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.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-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
@@ -186,7 +186,7 @@ void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id)
struct ath12k_peer *peer, *tmp;
struct ath12k_base *ab = ar->ab;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
spin_lock_bh(&ab->base_lock);
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
@@ -235,7 +235,7 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)
{
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
reinit_completion(&ar->peer_delete_done);
@@ -261,14 +261,15 @@ static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8
return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
}
-int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
+int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct ieee80211_sta *sta,
struct ath12k_wmi_peer_create_arg *arg)
{
+ struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ath12k_peer *peer;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
if (ar->num_peers > (ar->max_num_peers - 1)) {
ath12k_warn(ar->ab,
@@ -326,7 +327,7 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
peer->pdev_idx = ar->pdev_idx;
peer->sta = sta;
- if (arvif->vif->type == NL80211_IFTYPE_STATION) {
+ if (vif->type == NL80211_IFTYPE_STATION) {
arvif->ast_hash = peer->ast_hash;
arvif->ast_idx = peer->hw_peer_id;
}
diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
index 7b3500b5c8c2..b955f0cdf598 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-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_PEER_H
@@ -59,7 +59,7 @@ struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab,
struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, int peer_id);
void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id);
int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr);
-int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
+int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct ieee80211_sta *sta,
struct ath12k_wmi_peer_create_arg *arg);
int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
index a0db6702a189..10366bbe9999 100644
--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
@@ -684,18 +684,17 @@ enum rx_msdu_start_reception_type {
#define RX_MSDU_END_INFO5_SA_IDX_TIMEOUT BIT(0)
#define RX_MSDU_END_INFO5_DA_IDX_TIMEOUT BIT(1)
+#define RX_MSDU_END_INFO5_TO_DS BIT(2)
+#define RX_MSDU_END_INFO5_TID GENMASK(6, 3)
#define RX_MSDU_END_INFO5_SA_IS_VALID BIT(7)
#define RX_MSDU_END_INFO5_DA_IS_VALID BIT(8)
#define RX_MSDU_END_INFO5_DA_IS_MCBC BIT(9)
#define RX_MSDU_END_INFO5_L3_HDR_PADDING GENMASK(11, 10)
#define RX_MSDU_END_INFO5_FIRST_MSDU BIT(12)
#define RX_MSDU_END_INFO5_LAST_MSDU BIT(13)
+#define RX_MSDU_END_INFO5_FROM_DS BIT(14)
#define RX_MSDU_END_INFO5_IP_CHKSUM_FAIL_COPY BIT(15)
-#define RX_MSDU_END_QCN9274_INFO5_TO_DS BIT(2)
-#define RX_MSDU_END_QCN9274_INFO5_TID GENMASK(6, 3)
-#define RX_MSDU_END_QCN9274_INFO5_FROM_DS BIT(14)
-
#define RX_MSDU_END_INFO6_MSDU_DROP BIT(0)
#define RX_MSDU_END_INFO6_REO_DEST_IND GENMASK(5, 1)
#define RX_MSDU_END_INFO6_FLOW_IDX GENMASK(25, 6)
@@ -709,14 +708,14 @@ enum rx_msdu_start_reception_type {
#define RX_MSDU_END_INFO7_FLOW_AGGR_CONTN BIT(8)
#define RX_MSDU_END_INFO7_FISA_TIMEOUT BIT(9)
-#define RX_MSDU_END_QCN9274_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10)
-#define RX_MSDU_END_QCN9274_INFO7_MSDU_LIMIT_ERROR BIT(11)
-#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_TIMEOUT BIT(12)
-#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_INVALID BIT(13)
-#define RX_MSDU_END_QCN9274_INFO7_CCE_MATCH BIT(14)
-#define RX_MSDU_END_QCN9274_INFO7_AMSDU_PARSER_ERR BIT(15)
+#define RX_MSDU_END_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10)
+#define RX_MSDU_END_INFO7_MSDU_LIMIT_ERROR BIT(11)
+#define RX_MSDU_END_INFO7_FLOW_IDX_TIMEOUT BIT(12)
+#define RX_MSDU_END_INFO7_FLOW_IDX_INVALID BIT(13)
+#define RX_MSDU_END_INFO7_CCE_MATCH BIT(14)
+#define RX_MSDU_END_INFO7_AMSDU_PARSER_ERR BIT(15)
-#define RX_MSDU_END_QCN9274_INFO8_KEY_ID GENMASK(7, 0)
+#define RX_MSDU_END_INFO8_KEY_ID GENMASK(7, 0)
#define RX_MSDU_END_INFO9_SERVICE_CODE GENMASK(14, 6)
#define RX_MSDU_END_INFO9_PRIORITY_VALID BIT(15)
@@ -758,8 +757,8 @@ enum rx_msdu_start_reception_type {
#define RX_MSDU_END_INFO12_RECV_BW GENMASK(20, 18)
#define RX_MSDU_END_INFO12_RECEPTION_TYPE GENMASK(23, 21)
-#define RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP GENMASK(30, 24)
-#define RX_MSDU_END_QCN9274_INFO12_MIMO_DONE_COPY BIT(31)
+#define RX_MSDU_END_INFO12_MIMO_SS_BITMAP GENMASK(30, 24)
+#define RX_MSDU_END_INFO12_MIMO_DONE_COPY BIT(31)
#define RX_MSDU_END_INFO13_FIRST_MPDU BIT(0)
#define RX_MSDU_END_INFO13_MCAST_BCAST BIT(2)
@@ -791,7 +790,7 @@ enum rx_msdu_start_reception_type {
#define RX_MSDU_END_INFO13_UNDECRYPT_FRAME_ERR BIT(30)
#define RX_MSDU_END_INFO13_FCS_ERR BIT(31)
-#define RX_MSDU_END_QCN9274_INFO13_WIFI_PARSER_ERR BIT(15)
+#define RX_MSDU_END_INFO13_WIFI_PARSER_ERR BIT(15)
#define RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE GENMASK(12, 10)
#define RX_MSDU_END_INFO14_RX_BITMAP_NOT_UPDED BIT(13)
@@ -889,65 +888,6 @@ struct rx_msdu_end_qcn9274_compact {
__le32 info14;
} __packed;
-/* These macro definitions are only used for WCN7850 */
-#define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0)
-
-#define RX_MSDU_END_WCN7850_INFO5_MSDU_LIMIT_ERR BIT(2)
-#define RX_MSDU_END_WCN7850_INFO5_IDX_TIMEOUT BIT(3)
-#define RX_MSDU_END_WCN7850_INFO5_IDX_INVALID BIT(4)
-#define RX_MSDU_END_WCN7850_INFO5_WIFI_PARSE_ERR BIT(5)
-#define RX_MSDU_END_WCN7850_INFO5_AMSDU_PARSER_ERR BIT(6)
-#define RX_MSDU_END_WCN7850_INFO5_TCPUDP_CSUM_FAIL_CPY BIT(14)
-
-#define RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP GENMASK(31, 24)
-
-#define RX_MSDU_END_WCN7850_INFO13_FRAGMENT_FLAG BIT(13)
-#define RX_MSDU_END_WCN7850_INFO13_CCE_MATCH BIT(15)
-
-struct rx_msdu_end_wcn7850 {
- __le16 info0;
- __le16 phy_ppdu_id;
- __le16 ip_hdr_cksum;
- __le16 info1;
- __le16 info2;
- __le16 cumulative_l3_checksum;
- __le32 rule_indication0;
- __le32 rule_indication1;
- __le16 info3;
- __le16 l3_type;
- __le32 ipv6_options_crc;
- __le32 tcp_seq_num;
- __le32 tcp_ack_num;
- __le16 info4;
- __le16 window_size;
- __le16 tcp_udp_chksum;
- __le16 info5;
- __le16 sa_idx;
- __le16 da_idx_or_sw_peer_id;
- __le32 info6;
- __le32 fse_metadata;
- __le16 cce_metadata;
- __le16 sa_sw_peer_id;
- __le16 info7;
- __le16 rsvd0;
- __le16 cumulative_l4_checksum;
- __le16 cumulative_ip_length;
- __le32 info9;
- __le32 info10;
- __le32 info11;
- __le32 toeplitz_hash_2_or_4;
- __le32 flow_id_toeplitz;
- __le32 info12;
- __le32 ppdu_start_timestamp_31_0;
- __le32 ppdu_start_timestamp_63_32;
- __le32 phy_meta_data;
- __le16 vlan_ctag_ci;
- __le16 vlan_stag_ci;
- __le32 rsvd[3];
- __le32 info13;
- __le32 info14;
-} __packed;
-
/* rx_msdu_end
*
* rxpcu_mpdu_filter_in_category
@@ -1578,7 +1518,7 @@ struct rx_pkt_hdr_tlv {
struct hal_rx_desc_wcn7850 {
__le64 msdu_end_tag;
- struct rx_msdu_end_wcn7850 msdu_end;
+ struct rx_msdu_end_qcn9274 msdu_end;
u8 rx_padding0[RX_BE_PADDING0_BYTES];
__le64 mpdu_start_tag;
struct rx_mpdu_start_qcn9274 mpdu_start;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 2cd3ff9b0164..dced2aa9ba1a 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6687,7 +6687,8 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
const u32 *vdev_ids)
{
int i;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
+ struct ath12k_vif *ahvif;
/* Finish CSA once the switch count becomes NULL */
if (ev->current_switch_count)
@@ -6702,9 +6703,10 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
vdev_ids[i]);
continue;
}
+ ahvif = arvif->ahvif;
- if (arvif->is_up && arvif->vif->bss_conf.csa_active)
- ieee80211_csa_finish(arvif->vif, 0);
+ if (arvif->is_up && ahvif->vif->bss_conf.csa_active)
+ ieee80211_csa_finish(ahvif->vif, 0);
}
rcu_read_unlock();
}
@@ -7098,7 +7100,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
struct sk_buff *skb)
{
const struct wmi_gtk_offload_status_event *ev;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
__be64 replay_ctr_be;
u64 replay_ctr;
const void **tb;
@@ -7136,7 +7138,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
/* supplicant expects big-endian replay counter */
replay_ctr_be = cpu_to_be64(replay_ctr);
- ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid,
+ ieee80211_gtk_rekey_notify(arvif->ahvif->vif, arvif->bssid,
(void *)&replay_ctr_be, GFP_ATOMIC);
rcu_read_unlock();
@@ -7284,9 +7286,11 @@ static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab,
u32 pdev_idx)
{
int status;
- u32 svc_id[] = { ATH12K_HTC_SVC_ID_WMI_CONTROL,
- ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1,
- ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 };
+ static const u32 svc_id[] = {
+ ATH12K_HTC_SVC_ID_WMI_CONTROL,
+ ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1,
+ ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2
+ };
struct ath12k_htc_svc_conn_req conn_req = {};
struct ath12k_htc_svc_conn_resp conn_resp = {};
@@ -7372,13 +7376,13 @@ ath12k_wmi_send_unit_test_cmd(struct ath12k *ar,
int ath12k_wmi_simulate_radar(struct ath12k *ar)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
u32 dfs_args[DFS_MAX_TEST_ARGS];
struct wmi_unit_test_cmd wmi_ut;
bool arvif_found = false;
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ if (arvif->is_started && arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
arvif_found = true;
break;
}
@@ -7940,7 +7944,7 @@ static void ath12k_wmi_fill_arp_offload(struct ath12k *ar,
}
int ath12k_wmi_arp_ns_offload(struct ath12k *ar,
- struct ath12k_vif *arvif,
+ struct ath12k_link_vif *arvif,
struct wmi_arp_ns_offload_arg *offload,
bool enable)
{
@@ -7989,7 +7993,7 @@ int ath12k_wmi_arp_ns_offload(struct ath12k *ar,
}
int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar,
- struct ath12k_vif *arvif, bool enable)
+ struct ath12k_link_vif *arvif, bool enable)
{
struct ath12k_rekey_data *rekey_data = &arvif->rekey_data;
struct wmi_gtk_rekey_offload_cmd *cmd;
@@ -8026,7 +8030,7 @@ int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar,
}
int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar,
- struct ath12k_vif *arvif)
+ struct ath12k_link_vif *arvif)
{
struct wmi_gtk_rekey_offload_cmd *cmd;
struct sk_buff *skb;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 6a913f9b8315..6f55dbdf629d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -24,7 +24,7 @@
struct ath12k_base;
struct ath12k;
-struct ath12k_vif;
+struct ath12k_link_vif;
/* There is no signed version of __le32, so for a temporary solution come
* up with our own version. The idea is from fs/ntfs/endian.h.
@@ -5627,13 +5627,13 @@ int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id,
int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar,
struct wmi_hw_data_filter_arg *arg);
int ath12k_wmi_arp_ns_offload(struct ath12k *ar,
- struct ath12k_vif *arvif,
+ struct ath12k_link_vif *arvif,
struct wmi_arp_ns_offload_arg *offload,
bool enable);
int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar,
- struct ath12k_vif *arvif, bool enable);
+ struct ath12k_link_vif *arvif, bool enable);
int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar,
- struct ath12k_vif *arvif);
+ struct ath12k_link_vif *arvif);
int ath12k_wmi_sta_keepalive(struct ath12k *ar,
const struct wmi_sta_keepalive_arg *arg);
diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c
index 9b8684abbe40..9e1c0bfd212f 100644
--- a/drivers/net/wireless/ath/ath12k/wow.c
+++ b/drivers/net/wireless/ath/ath12k/wow.c
@@ -29,11 +29,11 @@ static const struct wiphy_wowlan_support ath12k_wowlan_support = {
.max_pkt_offset = WOW_MAX_PKT_OFFSET,
};
-static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *arvif)
+static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *ahvif)
{
- return (arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE ||
- arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT ||
- arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO);
+ return (ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE ||
+ ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT ||
+ ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO);
}
int ath12k_wow_enable(struct ath12k *ar)
@@ -101,7 +101,7 @@ int ath12k_wow_wakeup(struct ath12k *ar)
return 0;
}
-static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif)
+static int ath12k_wow_vif_cleanup(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
int i, ret;
@@ -129,10 +129,10 @@ static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif)
static int ath12k_wow_cleanup(struct ath12k *ar)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
ret = ath12k_wow_vif_cleanup(arvif);
@@ -191,7 +191,7 @@ ath12k_wow_convert_8023_to_80211(struct ath12k *ar,
memcpy(bytemask, eth_bytemask, eth_pat_len);
pat_len = eth_pat_len;
- } else if (eth_pkt_ofs + eth_pat_len < prot_ofs) {
+ } else if (size_add(eth_pkt_ofs, eth_pat_len) < prot_ofs) {
memcpy(pat, eth_pat, ETH_ALEN - eth_pkt_ofs);
memcpy(bytemask, eth_bytemask, ETH_ALEN - eth_pkt_ofs);
@@ -354,7 +354,7 @@ ath12k_wow_pno_check_and_convert(struct ath12k *ar, u32 vdev_id,
return 0;
}
-static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif,
+static int ath12k_wow_vif_set_wakeups(struct ath12k_link_vif *arvif,
struct cfg80211_wowlan *wowlan)
{
const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
@@ -364,7 +364,7 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif,
int ret, i, j;
/* Setup requested WOW features */
- switch (arvif->vdev_type) {
+ switch (arvif->ahvif->vdev_type) {
case WMI_VDEV_TYPE_IBSS:
__set_bit(WOW_BEACON_EVENT, &wow_mask);
fallthrough;
@@ -473,13 +473,13 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif,
static int ath12k_wow_set_wakeups(struct ath12k *ar,
struct cfg80211_wowlan *wowlan)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (ath12k_wow_is_p2p_vdev(arvif))
+ if (ath12k_wow_is_p2p_vdev(arvif->ahvif))
continue;
ret = ath12k_wow_vif_set_wakeups(arvif, wowlan);
if (ret) {
@@ -518,11 +518,11 @@ out:
return ret;
}
-static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif)
+static int ath12k_wow_vif_clean_nlo(struct ath12k_link_vif *arvif)
{
struct ath12k *ar = arvif->ar;
- switch (arvif->vdev_type) {
+ switch (arvif->ahvif->vdev_type) {
case WMI_VDEV_TYPE_STA:
return ath12k_wow_vdev_clean_nlo(ar, arvif->vdev_id);
default:
@@ -532,13 +532,13 @@ static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif)
static int ath12k_wow_nlo_cleanup(struct ath12k *ar)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (ath12k_wow_is_p2p_vdev(arvif))
+ if (ath12k_wow_is_p2p_vdev(arvif->ahvif))
continue;
ret = ath12k_wow_vif_clean_nlo(arvif);
@@ -555,13 +555,13 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar)
static int ath12k_wow_set_hw_filter(struct ath12k *ar)
{
struct wmi_hw_data_filter_arg arg;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA)
continue;
arg.vdev_id = arvif->vdev_id;
@@ -581,13 +581,13 @@ static int ath12k_wow_set_hw_filter(struct ath12k *ar)
static int ath12k_wow_clear_hw_filter(struct ath12k *ar)
{
struct wmi_hw_data_filter_arg arg;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA)
continue;
arg.vdev_id = arvif->vdev_id;
@@ -626,10 +626,10 @@ static void ath12k_wow_generate_ns_mc_addr(struct ath12k_base *ab,
}
}
-static void ath12k_wow_prepare_ns_offload(struct ath12k_vif *arvif,
+static void ath12k_wow_prepare_ns_offload(struct ath12k_link_vif *arvif,
struct wmi_arp_ns_offload_arg *offload)
{
- struct net_device *ndev = ieee80211_vif_to_wdev(arvif->vif)->netdev;
+ struct net_device *ndev = ieee80211_vif_to_wdev(arvif->ahvif->vif)->netdev;
struct ath12k_base *ab = arvif->ar->ab;
struct inet6_ifaddr *ifa6;
struct ifacaddr6 *ifaca6;
@@ -710,10 +710,10 @@ unlock:
ath12k_wow_generate_ns_mc_addr(ab, offload);
}
-static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif,
+static void ath12k_wow_prepare_arp_offload(struct ath12k_link_vif *arvif,
struct wmi_arp_ns_offload_arg *offload)
{
- struct ieee80211_vif *vif = arvif->vif;
+ struct ieee80211_vif *vif = arvif->ahvif->vif;
struct ieee80211_vif_cfg vif_cfg = vif->cfg;
struct ath12k_base *ab = arvif->ar->ab;
u32 ipv4_cnt;
@@ -732,22 +732,25 @@ static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif,
static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable)
{
struct wmi_arp_ns_offload_arg *offload;
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
+ struct ath12k_vif *ahvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
offload = kmalloc(sizeof(*offload), GFP_KERNEL);
if (!offload)
return -ENOMEM;
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ ahvif = arvif->ahvif;
+
+ if (ahvif->vdev_type != WMI_VDEV_TYPE_STA)
continue;
memset(offload, 0, sizeof(*offload));
- memcpy(offload->mac_addr, arvif->vif->addr, ETH_ALEN);
+ memcpy(offload->mac_addr, ahvif->vif->addr, ETH_ALEN);
ath12k_wow_prepare_ns_offload(arvif, offload);
ath12k_wow_prepare_arp_offload(arvif, offload);
@@ -766,13 +769,13 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable)
static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
- if (arvif->vdev_type != WMI_VDEV_TYPE_STA ||
+ if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA ||
!arvif->is_up ||
!arvif->rekey_data.enable_offload)
continue;
@@ -824,10 +827,10 @@ static int ath12k_wow_set_keepalive(struct ath12k *ar,
enum wmi_sta_keepalive_method method,
u32 interval)
{
- struct ath12k_vif *arvif;
+ struct ath12k_link_vif *arvif;
int ret;
- lockdep_assert_held(&ar->conf_mutex);
+ lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
list_for_each_entry(arvif, &ar->arvifs, list) {
ret = ath12k_mac_vif_set_keepalive(arvif, method, interval);
@@ -845,7 +848,7 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw,
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
int ret;
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
ret = ath12k_wow_cleanup(ar);
if (ret) {
@@ -913,7 +916,6 @@ cleanup:
ath12k_wow_cleanup(ar);
exit:
- mutex_unlock(&ar->conf_mutex);
return ret ? 1 : 0;
}
@@ -922,9 +924,9 @@ void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
+
device_set_wakeup_enable(ar->ab->dev, enabled);
- mutex_unlock(&ar->conf_mutex);
}
int ath12k_wow_op_resume(struct ieee80211_hw *hw)
@@ -933,7 +935,7 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw)
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
int ret;
- mutex_lock(&ar->conf_mutex);
+ lockdep_assert_wiphy(hw->wiphy);
ret = ath12k_hif_resume(ar->ab);
if (ret) {
@@ -995,7 +997,6 @@ exit:
}
}
- mutex_unlock(&ar->conf_mutex);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index f27308ccb2f1..cb3e891ee1bd 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -218,10 +218,10 @@ static void ath_ahb_remove(struct platform_device *pdev)
}
static struct platform_driver ath_ahb_driver = {
- .probe = ath_ahb_probe,
- .remove_new = ath_ahb_remove,
- .driver = {
- .name = "ar231x-wmac",
+ .probe = ath_ahb_probe,
+ .remove = ath_ahb_remove,
+ .driver = {
+ .name = "ar231x-wmac",
},
};
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index b51fce5ae260..f5ca2fe0d074 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -46,6 +46,8 @@ static const struct pci_device_id ath5k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
{ PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
{ PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
+ { PCI_VDEVICE(ATHEROS, 0xff16) }, /* Gigaset SX76[23] AR241[34]A */
+ { PCI_VDEVICE(ATHEROS, 0xff1a) }, /* Arcadyan ARV45XX AR2417 */
{ PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */
{ 0 }
};
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index b4fcfb72991c..68384159870b 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1249,7 +1249,7 @@ struct wmi_rssi_threshold_params_cmd {
/* highest of upper */
a_sle16 thresh_above6_val;
- /* lowest of bellow */
+ /* lowest of below */
a_sle16 thresh_below1_val;
a_sle16 thresh_below2_val;
@@ -1257,7 +1257,7 @@ struct wmi_rssi_threshold_params_cmd {
a_sle16 thresh_below4_val;
a_sle16 thresh_below5_val;
- /* highest of bellow */
+ /* highest of below */
a_sle16 thresh_below6_val;
/* "alpha" */
@@ -1287,13 +1287,13 @@ struct wmi_snr_threshold_params_cmd {
/* highest of upper */
u8 thresh_above4_val;
- /* lowest of bellow */
+ /* lowest of below */
u8 thresh_below1_val;
u8 thresh_below2_val;
u8 thresh_below3_val;
- /* highest of bellow */
+ /* highest of below */
u8 thresh_below4_val;
u8 reserved[3];
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 1a6697b6e3b4..d4805e02b927 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -158,12 +158,12 @@ static void ath_ahb_remove(struct platform_device *pdev)
}
static struct platform_driver ath_ahb_driver = {
- .probe = ath_ahb_probe,
- .remove_new = ath_ahb_remove,
- .driver = {
- .name = "ath9k",
+ .probe = ath_ahb_probe,
+ .remove = ath_ahb_remove,
+ .driver = {
+ .name = "ath9k",
},
- .id_table = ath9k_platform_id_table,
+ .id_table = ath9k_platform_id_table,
};
MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
index d0f1e8bcc846..45a7ca660f47 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c
@@ -409,13 +409,11 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
sram.valid = true;
sram.rot_dir_att_db =
- min(max(rot_dir_path_att_db,
- (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
- ATH_AIC_MAX_ROT_DIR_ATT_DB);
+ clamp(rot_dir_path_att_db, (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB,
+ ATH_AIC_MAX_ROT_DIR_ATT_DB);
sram.rot_quad_att_db =
- min(max(rot_quad_path_att_db,
- (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
- ATH_AIC_MAX_ROT_QUAD_ATT_DB);
+ clamp(rot_quad_path_att_db, (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB,
+ ATH_AIC_MAX_ROT_QUAD_ATT_DB);
aic->aic_sram[i] = (SM(sram.vga_dir_sign,
AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
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 004ca5f536be..fe1013a3a588 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
+++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
@@ -18,7 +18,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/ath9k_platform.h>
#include <linux/nvmem-consumer.h>
#include <linux/workqueue.h>
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 9b393a8f7c3a..ad3a3fda1b9c 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -16,7 +16,6 @@
#include <linux/export.h>
#include <linux/types.h>
-#include <linux/ath9k_platform.h>
#include "hw.h"
enum ath_bt_mode {
@@ -115,23 +114,14 @@ static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio,
u8 btactive_gpio, u8 btpriority_gpio)
{
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- struct ath9k_platform_data *pdata = ah->dev->platform_data;
if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE &&
btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE)
return;
- /* bt priority GPIO will be ignored by 2 wire scheme */
- if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin ||
- pdata->wlan_active_pin)) {
- btcoex_hw->btactive_gpio = pdata->bt_active_pin;
- btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin;
- btcoex_hw->btpriority_gpio = pdata->bt_priority_pin;
- } else {
- btcoex_hw->btactive_gpio = btactive_gpio;
- btcoex_hw->wlanactive_gpio = wlanactive_gpio;
- btcoex_hw->btpriority_gpio = btpriority_gpio;
- }
+ btcoex_hw->btactive_gpio = btactive_gpio;
+ btcoex_hw->wlanactive_gpio = wlanactive_gpio;
+ btcoex_hw->btpriority_gpio = btpriority_gpio;
}
void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index efb7889142d4..df58dc02e104 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -15,7 +15,6 @@
*/
#include "hw.h"
-#include <linux/ath9k_platform.h>
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
{
@@ -119,14 +118,6 @@ static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
return true;
}
-static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
- off_t offset, u16 *data)
-{
- return ath9k_hw_nvram_read_array(pdata->eeprom_data,
- ARRAY_SIZE(pdata->eeprom_data),
- offset, data);
-}
-
static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
off_t offset, u16 *data)
{
@@ -146,15 +137,12 @@ static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_platform_data *pdata = ah->dev->platform_data;
bool ret;
if (ah->nvmem_blob)
ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
else if (ah->eeprom_blob)
ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
- else if (pdata && !pdata->use_eeprom)
- ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
else
ret = common->bus_ops->eeprom_read(common, off, data);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 8a03bcc2789e..57094bd45d98 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1357,8 +1357,10 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, u32 changed)
+ struct ieee80211_link_sta *link_sta,
+ u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED))
@@ -1883,7 +1885,7 @@ struct ieee80211_ops ath9k_htc_ops = {
.sta_add = ath9k_htc_sta_add,
.sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx,
- .sta_rc_update = ath9k_htc_sta_rc_update,
+ .link_sta_rc_update = ath9k_htc_sta_rc_update,
.bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key,
.get_tsf = ath9k_htc_get_tsf,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index eb631fd3336d..b5257b2b4aa5 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -294,6 +294,9 @@ int htc_connect_service(struct htc_target *target,
return -ETIMEDOUT;
}
+ if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX)
+ return -EINVAL;
+
*conn_rsp_epid = target->conn_rsp_epid;
return 0;
err:
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c3a6368bfc68..e2bef099adb3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -490,7 +490,7 @@ static void ath9k_hw_init_macaddr(struct ath_hw *ah)
u16 eeval;
static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
- /* MAC address may already be loaded via ath9k_platform_data */
+ /* MAC address may already be loaded via NVMEM */
if (is_valid_ether_addr(common->macaddr))
return;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 7fad7e75af6a..f9e77c4624d9 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -18,7 +18,6 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <linux/ath9k_platform.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_net.h>
@@ -583,8 +582,8 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
/* nvmem cell might not be defined, or the nvmem
* subsystem isn't included. In this case, follow
- * the established "just return 0;" convention of
- * ath9k_init_platform to say:
+ * the established "just return 0;" convention
+ * to say:
* "All good. Nothing to see here. Please go on."
*/
if (err == -ENOENT || err == -EOPNOTSUPP)
@@ -620,49 +619,6 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
return 0;
}
-static int ath9k_init_platform(struct ath_softc *sc)
-{
- struct ath9k_platform_data *pdata = sc->dev->platform_data;
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
- int ret;
-
- if (!pdata)
- return 0;
-
- if (!pdata->use_eeprom) {
- ah->ah_flags &= ~AH_USE_EEPROM;
- ah->gpio_mask = pdata->gpio_mask;
- ah->gpio_val = pdata->gpio_val;
- ah->led_pin = pdata->led_pin;
- ah->is_clk_25mhz = pdata->is_clk_25mhz;
- ah->get_mac_revision = pdata->get_mac_revision;
- ah->external_reset = pdata->external_reset;
- ah->disable_2ghz = pdata->disable_2ghz;
- ah->disable_5ghz = pdata->disable_5ghz;
-
- if (!pdata->endian_check)
- ah->ah_flags |= AH_NO_EEP_SWAP;
- }
-
- if (pdata->eeprom_name) {
- ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
- if (ret)
- return ret;
- }
-
- if (pdata->led_active_high)
- ah->config.led_active_high = true;
-
- if (pdata->tx_gain_buffalo)
- ah->config.tx_gain_buffalo = true;
-
- if (pdata->macaddr)
- ether_addr_copy(common->macaddr, pdata->macaddr);
-
- return 0;
-}
-
static int ath9k_of_init(struct ath_softc *sc)
{
struct device_node *np = sc->dev->of_node;
@@ -748,10 +704,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
*/
ath9k_init_pcoem_platform(sc);
- ret = ath9k_init_platform(sc);
- if (ret)
- return ret;
-
ret = ath9k_of_init(sc);
if (ret)
return ret;
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 408776562a7e..8557d4826a46 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -1679,10 +1679,10 @@ static const struct of_device_id wcn36xx_of_match[] = {
MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = {
- .probe = wcn36xx_probe,
- .remove_new = wcn36xx_remove,
- .driver = {
- .name = "wcn36xx",
+ .probe = wcn36xx_probe,
+ .remove = wcn36xx_remove,
+ .driver = {
+ .name = "wcn36xx",
.of_match_table = wcn36xx_of_match,
},
};
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index bccc27de848d..7ee79593cd23 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -167,7 +167,7 @@ struct wcn36xx_vif {
* @dpu_desc_index: DPU descriptor index is returned from HW after config_sta
* call and is used in TX BD.
* @bss_sta_index: STA index is returned from HW after config_bss call and is
- * used in both SMD channel and TX BD. See table bellow when it is used.
+ * used in both SMD channel and TX BD. See table below when it is used.
* @bss_dpu_desc_index: DPU descriptor index is returned from HW after
* config_bss call and is used in TX BD.
* ______________________________________________
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index e8f1d30a8d73..a1a0a9223e74 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1493,6 +1493,7 @@ out:
}
static int wil_cfg80211_set_channel(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index f29ac6de7139..19702b6f09c3 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -306,7 +306,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
struct sk_buff *skb)
{
struct wil6210_rtap {
- struct ieee80211_radiotap_header rthdr;
+ struct ieee80211_radiotap_header_fixed rthdr;
/* fields should be in the order of bits in rthdr.it_present */
/* flags */
u8 flags;
diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig
index 3a1a35b5672f..19d0c003f626 100644
--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig
+++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig
@@ -27,6 +27,7 @@ source "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig"
config BRCM_TRACING
bool "Broadcom device tracing"
depends on BRCMSMAC || BRCMFMAC
+ depends on TRACING
help
If you say Y here, the Broadcom wireless drivers will register
with ftrace to dump event information into the trace ringbuffer.
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index d35262335eaf..42d991d9f8cb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -770,7 +770,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
sdiodev->settings->bus.sdio.txglomsz);
- nents += (nents >> 4) + 1;
+ nents *= 2;
WARN_ON(nents > sdiodev->max_segment_count);
@@ -947,8 +947,8 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
/* try to attach to the target device */
sdiodev->bus = brcmf_sdio_probe(sdiodev);
- if (!sdiodev->bus) {
- ret = -ENODEV;
+ if (IS_ERR(sdiodev->bus)) {
+ ret = PTR_ERR(sdiodev->bus);
goto out;
}
brcmf_sdiod_host_fixup(sdiodev->func2->card->host);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 349aa3439502..297a7c738c01 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -7820,13 +7820,6 @@ s32 brcmf_cfg80211_down(struct net_device *ndev)
return err;
}
-enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
-{
- struct wireless_dev *wdev = &ifp->vif->wdev;
-
- return wdev->iftype;
-}
-
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
unsigned long state)
{
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index dc3a6a537507..2abae8894614 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -443,7 +443,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev);
struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings);
-enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index b24faae35873..cfcf01eb0daa 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -561,7 +561,8 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
if (!found) {
/* No platform data for this device, try OF and DMI data */
brcmf_dmi_probe(settings, chip, chiprev);
- brcmf_of_probe(dev, bus_type, settings);
+ if (brcmf_of_probe(dev, bus_type, settings) == -EPROBE_DEFER)
+ return ERR_PTR(-EPROBE_DEFER);
brcmf_acpi_probe(dev, bus_type, settings);
}
return settings;
@@ -593,7 +594,7 @@ static void brcmf_common_pd_remove(struct platform_device *pdev)
}
static struct platform_driver brcmf_pd = {
- .remove_new = brcmf_common_pd_remove,
+ .remove = brcmf_common_pd_remove,
.driver = {
.name = BRCMFMAC_PDATA_NAME,
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index fe4f65756105..c1f18e2fe540 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -6,6 +6,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_net.h>
+#include <linux/clk.h>
#include <defs.h>
#include "debug.h"
@@ -65,12 +66,13 @@ static int brcmf_of_get_country_codes(struct device *dev,
return 0;
}
-void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
- struct brcmf_mp_device *settings)
+int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings)
{
struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio;
struct device_node *root, *np = dev->of_node;
struct of_phandle_args oirq;
+ struct clk *clk;
const char *prop;
int irq;
int err;
@@ -106,16 +108,21 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
if (!board_type) {
of_node_put(root);
- return;
+ return 0;
}
strreplace(board_type, '/', '-');
settings->board_type = board_type;
-
- of_node_put(root);
}
+ of_node_put(root);
+
+ clk = devm_clk_get_optional_enabled_with_rate(dev, "lpo", 32768);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ brcmf_dbg(INFO, "%s LPO clock\n", clk ? "enable" : "no");
if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
- return;
+ return 0;
err = brcmf_of_get_country_codes(dev, settings);
if (err)
@@ -124,23 +131,25 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
of_get_mac_address(np, settings->mac);
if (bus_type != BRCMF_BUSTYPE_SDIO)
- return;
+ return 0;
if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
sdio->drive_strength = val;
/* make sure there are interrupts defined in the node */
if (of_irq_parse_one(np, 0, &oirq))
- return;
+ return 0;
irq = irq_create_of_mapping(&oirq);
if (!irq) {
brcmf_err("interrupt could not be mapped\n");
- return;
+ return 0;
}
- irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
+ irqf = irq_get_trigger_type(irq);
sdio->oob_irq_supported = true;
sdio->oob_irq_nr = irq;
sdio->oob_irq_flags = irqf;
+
+ return 0;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
index 10bf52253337..ae124c73fc3b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
@@ -3,11 +3,12 @@
* Copyright (c) 2014 Broadcom Corporation
*/
#ifdef CONFIG_OF
-void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
- struct brcmf_mp_device *settings);
+int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings);
#else
-static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
- struct brcmf_mp_device *settings)
+static int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
+ struct brcmf_mp_device *settings)
{
+ return 0;
}
#endif /* CONFIG_OF */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 5dee54819fbd..e4395b1f8c11 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -66,6 +66,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie");
BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie");
BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");
BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");
+BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-pcie");
BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie");
BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie");
BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie");
@@ -104,6 +105,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
+ BRCMF_FW_ENTRY(BRCM_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752),
BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* revision ID 4 */
BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */
BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */
@@ -353,6 +355,7 @@ struct brcmf_pciedev_info {
u16 value);
struct brcmf_mp_device *settings;
struct brcmf_otp_params otp;
+ bool fwseed;
#ifdef DEBUG
u32 console_interval;
bool console_active;
@@ -1715,14 +1718,14 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
memcpy_toio(devinfo->tcm + address, nvram, nvram_len);
brcmf_fw_nvram_free(nvram);
- if (devinfo->otp.valid) {
+ if (devinfo->fwseed) {
size_t rand_len = BRCMF_RANDOM_SEED_LENGTH;
struct brcmf_random_seed_footer footer = {
.length = cpu_to_le32(rand_len),
.magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC),
};
- /* Some Apple chips/firmwares expect a buffer of random
+ /* Some chips/firmwares expect a buffer of random
* data to be present before NVRAM
*/
brcmf_dbg(PCIE, "Download random seed\n");
@@ -2394,6 +2397,37 @@ static void brcmf_pcie_debugfs_create(struct device *dev)
}
#endif
+struct brcmf_pcie_drvdata {
+ enum brcmf_fwvendor vendor;
+ bool fw_seed;
+};
+
+enum {
+ BRCMF_DRVDATA_CYW,
+ BRCMF_DRVDATA_BCA,
+ BRCMF_DRVDATA_WCC,
+ BRCMF_DRVDATA_WCC_SEED,
+};
+
+static const struct brcmf_pcie_drvdata drvdata[] = {
+ [BRCMF_DRVDATA_CYW] = {
+ .vendor = BRCMF_FWVENDOR_CYW,
+ .fw_seed = false,
+ },
+ [BRCMF_DRVDATA_BCA] = {
+ .vendor = BRCMF_FWVENDOR_BCA,
+ .fw_seed = false,
+ },
+ [BRCMF_DRVDATA_WCC] = {
+ .vendor = BRCMF_FWVENDOR_WCC,
+ .fw_seed = false,
+ },
+ [BRCMF_DRVDATA_WCC_SEED] = {
+ .vendor = BRCMF_FWVENDOR_WCC,
+ .fw_seed = true,
+ },
+};
+
/* Forward declaration for pci_match_id() call */
static const struct pci_device_id brcmf_pcie_devid_table[];
@@ -2452,6 +2486,9 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOMEM;
goto fail;
}
+ ret = PTR_ERR_OR_ZERO(devinfo->settings);
+ if (ret < 0)
+ goto fail;
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus) {
@@ -2472,9 +2509,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
bus->bus_priv.pcie = pcie_bus_dev;
bus->ops = &brcmf_pcie_bus_ops;
bus->proto_type = BRCMF_PROTO_MSGBUF;
- bus->fwvid = id->driver_data;
bus->chip = devinfo->coreid;
bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
+ bus->fwvid = drvdata[id->driver_data].vendor;
+ devinfo->fwseed = drvdata[id->driver_data].fw_seed;
dev_set_drvdata(&pdev->dev, bus);
ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings);
@@ -2660,14 +2698,14 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \
PCI_ANY_ID, PCI_ANY_ID, \
PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \
- BRCMF_FWVENDOR_ ## fw_vend \
+ BRCMF_DRVDATA_ ## fw_vend \
}
#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev, fw_vend) \
{ \
BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \
(subvend), (subdev), \
PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \
- BRCMF_FWVENDOR_ ## fw_vend \
+ BRCMF_DRVDATA_ ## fw_vend \
}
static const struct pci_device_id brcmf_pcie_devid_table[] = {
@@ -2695,9 +2733,10 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = {
BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID, BCA),
BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID, WCC),
BRCMF_PCIE_DEVICE(BRCM_PCIE_43596_DEVICE_ID, CYW),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC),
- BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC_SEED),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC_SEED),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC_SEED),
+ BRCMF_PCIE_DEVICE(BRCM_PCIE_43752_DEVICE_ID, WCC_SEED),
{ /* end: all zeroes */ }
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 7b936668c1b6..b1727f35217b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -3943,7 +3943,7 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
.write32 = brcmf_sdio_buscore_write32,
};
-static bool
+static int
brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiodev;
@@ -3953,6 +3953,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
u32 reg_val;
u32 drivestrength;
u32 enum_base;
+ int ret = -EBADE;
sdiodev = bus->sdiodev;
sdio_claim_host(sdiodev->func1);
@@ -4001,8 +4002,9 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
BRCMF_BUSTYPE_SDIO,
bus->ci->chip,
bus->ci->chiprev);
- if (!sdiodev->settings) {
+ if (IS_ERR_OR_NULL(sdiodev->settings)) {
brcmf_err("Failed to get device parameters\n");
+ ret = PTR_ERR_OR_ZERO(sdiodev->settings);
goto fail;
}
/* platform specific configuration:
@@ -4071,7 +4073,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
/* allocate header buffer */
bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL);
if (!bus->hdrbuf)
- return false;
+ return -ENOMEM;
/* Locate an appropriately-aligned portion of hdrbuf */
bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
bus->head_align);
@@ -4082,11 +4084,11 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
if (bus->poll)
bus->pollrate = 1;
- return true;
+ return 0;
fail:
sdio_release_host(sdiodev->func1);
- return false;
+ return ret;
}
static int
@@ -4451,8 +4453,10 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
/* Allocate private bus interface state */
bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
- if (!bus)
+ if (!bus) {
+ ret = -ENOMEM;
goto fail;
+ }
bus->sdiodev = sdiodev;
sdiodev->bus = bus;
@@ -4467,6 +4471,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
dev_name(&sdiodev->func1->dev));
if (!wq) {
brcmf_err("insufficient memory to create txworkqueue\n");
+ ret = -ENOMEM;
goto fail;
}
brcmf_sdiod_freezer_count(sdiodev);
@@ -4474,7 +4479,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->brcmf_wq = wq;
/* attempt to attach to the dongle */
- if (!(brcmf_sdio_probe_attach(bus))) {
+ ret = brcmf_sdio_probe_attach(bus);
+ if (ret < 0) {
brcmf_err("brcmf_sdio_probe_attach failed\n");
goto fail;
}
@@ -4546,7 +4552,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
fail:
brcmf_sdio_remove(bus);
- return NULL;
+ return ERR_PTR(ret);
}
/* Detach and free everything */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 8afbf529c745..2821c27f317e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1272,6 +1272,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
ret = -ENOMEM;
goto fail;
}
+ ret = PTR_ERR_OR_ZERO(devinfo->settings);
+ if (ret < 0)
+ goto fail;
if (!brcmf_usb_dlneeded(devinfo)) {
ret = brcmf_alloc(devinfo->dev, devinfo->settings);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
index 6d776ef6ff54..81df41c7fbb5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c
@@ -56,11 +56,6 @@ void brcms_debugfs_detach(struct brcms_pub *drvr)
debugfs_remove_recursive(drvr->dbgfs_dir);
}
-struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr)
-{
- return drvr->dbgfs_dir;
-}
-
static
int brcms_debugfs_hardware_read(struct seq_file *s, void *data)
{
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h
index 56898e6d789d..d30a9fa30f1b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h
@@ -70,7 +70,6 @@ void brcms_debugfs_init(void);
void brcms_debugfs_exit(void);
void brcms_debugfs_attach(struct brcms_pub *drvr);
void brcms_debugfs_detach(struct brcms_pub *drvr);
-struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr);
void brcms_debugfs_create_files(struct brcms_pub *drvr);
#endif /* _BRCMS_DEBUG_H_ */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
index bd480239368a..80c35027787a 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
@@ -1426,15 +1426,6 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
return -ENOSPC;
}
-void dma_txflush(struct dma_pub *pub)
-{
- struct dma_info *di = container_of(pub, struct dma_info, dma);
- struct brcms_ampdu_session *session = &di->ampdu_session;
-
- if (!skb_queue_empty(&session->skb_list))
- ampdu_finalize(di);
-}
-
int dma_txpending(struct dma_pub *pub)
{
struct dma_info *di = container_of(pub, struct dma_info, dma);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h
index ff5b80b09046..7905fd081721 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h
@@ -88,7 +88,6 @@ bool dma_txreset(struct dma_pub *pub);
void dma_txinit(struct dma_pub *pub);
int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
struct sk_buff *p0);
-void dma_txflush(struct dma_pub *pub);
int dma_txpending(struct dma_pub *pub);
void dma_kick_tx(struct dma_pub *pub);
void dma_txsuspend(struct dma_pub *pub);
diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
index 44684bf1b9ac..c1e22c589d85 100644
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
@@ -52,6 +52,7 @@
#define BRCM_CC_43664_CHIP_ID 43664
#define BRCM_CC_43666_CHIP_ID 43666
#define BRCM_CC_4371_CHIP_ID 0x4371
+#define BRCM_CC_43752_CHIP_ID 43752
#define BRCM_CC_4377_CHIP_ID 0x4377
#define BRCM_CC_4378_CHIP_ID 0x4378
#define BRCM_CC_4387_CHIP_ID 0x4387
@@ -94,6 +95,7 @@
#define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5
#define BRCM_PCIE_4371_DEVICE_ID 0x440d
#define BRCM_PCIE_43596_DEVICE_ID 0x4415
+#define BRCM_PCIE_43752_DEVICE_ID 0x449d
#define BRCM_PCIE_4377_DEVICE_ID 0x4488
#define BRCM_PCIE_4378_DEVICE_ID 0x4425
#define BRCM_PCIE_4387_DEVICE_ID 0x4433
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig
index 1650d5865aa0..b92df91adb3a 100644
--- a/drivers/net/wireless/intel/ipw2x00/Kconfig
+++ b/drivers/net/wireless/intel/ipw2x00/Kconfig
@@ -7,10 +7,8 @@ config IPW2100
tristate "Intel PRO/Wireless 2100 Network Connection"
depends on PCI && CFG80211
select WIRELESS_EXT
- select WEXT_SPY
select WEXT_PRIV
select FW_LOADER
- select LIB80211
select LIBIPW
help
A driver for the Intel PRO/Wireless 2100 Network
@@ -67,12 +65,9 @@ config IPW2100_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
depends on PCI && CFG80211
- select CFG80211_WEXT_EXPORT
select WIRELESS_EXT
- select WEXT_SPY
select WEXT_PRIV
select FW_LOADER
- select LIB80211
select LIBIPW
help
A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
@@ -158,14 +153,10 @@ config LIBIPW
tristate
depends on PCI && CFG80211
select WIRELESS_EXT
- select WEXT_SPY
select CRYPTO
select CRYPTO_MICHAEL_MIC
+ select CRYPTO_LIB_ARC4
select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
help
This option enables the hardware independent IEEE 802.11
networking stack. This component is deprecated in favor of the
diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile
index e1ec50359dff..91e6091c4ebf 100644
--- a/drivers/net/wireless/intel/ipw2x00/Makefile
+++ b/drivers/net/wireless/intel/ipw2x00/Makefile
@@ -12,4 +12,9 @@ libipw-objs := \
libipw_tx.o \
libipw_rx.o \
libipw_wx.o \
- libipw_geo.o
+ libipw_geo.o \
+ libipw_spy.o \
+ libipw_crypto.o \
+ libipw_crypto_ccmp.o \
+ libipw_crypto_tkip.o \
+ libipw_crypto_wep.o
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index b6636002c7d2..215814861cbd 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -148,9 +148,6 @@ that only one external action is invoked at a time.
#include <linux/acpi.h>
#include <linux/ctype.h>
#include <linux/pm_qos.h>
-
-#include <net/lib80211.h>
-
#include "ipw2100.h"
#include "ipw.h"
@@ -2518,7 +2515,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
* to build this manually element by element, we can write it much
* more efficiently than we can parse it. ORDER MATTERS HERE */
struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
+ struct ieee80211_radiotap_header_fixed rt_hdr;
s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
} *ipw_rt;
@@ -6025,8 +6022,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
dev->netdev_ops = &ipw2100_netdev_ops;
dev->ethtool_ops = &ipw2100_ethtool_ops;
dev->wireless_handlers = &ipw2100_wx_handler_def;
- priv->wireless_data.libipw = priv->ieee;
- dev->wireless_data = &priv->wireless_data;
dev->watchdog_timeo = 3 * HZ;
dev->irq = 0;
dev->min_mtu = 68;
@@ -7571,7 +7566,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev,
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
+ struct libipw_crypt_data *crypt;
unsigned long flags;
int ret = 0;
@@ -7663,7 +7658,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev,
{
struct ipw2100_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
+ struct libipw_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
switch (param->flags & IW_AUTH_INDEX) {
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
index b34085ade3aa..6f81f509b9cb 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
@@ -554,8 +554,6 @@ struct ipw2100_priv {
struct net_device *net_dev;
struct iw_statistics wstats;
- struct iw_public_data wireless_data;
-
struct tasklet_struct irq_tasklet;
struct delayed_work reset_work;
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index eed9ef17bc29..be1d971b3d32 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -6463,6 +6463,14 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv,
* WE-18 support
*/
+static int ipw_wx_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ strcpy(wrqu->name, "IEEE 802.11");
+ return 0;
+}
+
/* SIOCSIWGENIE */
static int ipw_wx_set_genie(struct net_device *dev,
struct iw_request_info *info,
@@ -6549,7 +6557,7 @@ static int ipw_wx_set_auth(struct net_device *dev,
struct ipw_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
+ struct libipw_crypt_data *crypt;
unsigned long flags;
int ret = 0;
@@ -6648,7 +6656,7 @@ static int ipw_wx_get_auth(struct net_device *dev,
{
struct ipw_priv *priv = libipw_priv(dev);
struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
+ struct libipw_crypt_data *crypt;
struct iw_param *param = &wrqu->param;
switch (param->flags & IW_AUTH_INDEX) {
@@ -9826,7 +9834,7 @@ static int ipw_wx_sw_reset(struct net_device *dev,
/* Rebase the WE IOCTLs to zero for the handler array */
static iw_handler ipw_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
+ IW_HANDLER(SIOCGIWNAME, ipw_wx_get_name),
IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),
IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),
IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode),
@@ -9856,10 +9864,10 @@ static iw_handler ipw_wx_handlers[] = {
IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
- 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(SIOCSIWSPY, ipw_wx_set_spy),
+ IW_HANDLER(SIOCGIWSPY, ipw_wx_get_spy),
+ IW_HANDLER(SIOCSIWTHRSPY, ipw_wx_set_thrspy),
+ IW_HANDLER(SIOCGIWTHRSPY, ipw_wx_get_thrspy),
IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
@@ -11636,8 +11644,7 @@ static int ipw_pci_probe(struct pci_dev *pdev,
priv->ieee->worst_rssi = -85;
net_dev->netdev_ops = &ipw_netdev_ops;
- priv->wireless_data.spy_data = &priv->ieee->spy_data;
- net_dev->wireless_data = &priv->wireless_data;
+ priv->ieee->spy_enabled = true;
net_dev->wireless_handlers = &ipw_wx_handler_def;
net_dev->ethtool_ops = &ipw_ethtool_ops;
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
index 8ebf09121e17..19310fd0d8eb 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
@@ -31,8 +31,6 @@
#include <linux/wireless.h>
#include <linux/jiffies.h>
#include <asm/io.h>
-
-#include <net/lib80211.h>
#include <net/ieee80211_radiotap.h>
#define DRV_NAME "ipw2200"
@@ -1143,7 +1141,7 @@ struct ipw_prom_priv {
* structure is provided regardless of any bits unset.
*/
struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
+ struct ieee80211_radiotap_header_fixed rt_hdr;
u64 rt_tsf; /* TSF */ /* XXX */
u8 rt_flags; /* radiotap packet flags */
u8 rt_rate; /* rate in 500kb/s */
@@ -1276,8 +1274,6 @@ struct ipw_priv {
struct iw_statistics wstats;
- struct iw_public_data wireless_data;
-
int user_requested_scan;
u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
u8 direct_scan_ssid_len;
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
index bad080d33c07..3c20353e5a41 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ b/drivers/net/wireless/intel/ipw2x00/libipw.h
@@ -25,8 +25,6 @@
#include <linux/kernel.h> /* ARRAY_SIZE */
#include <linux/wireless.h>
#include <linux/ieee80211.h>
-
-#include <net/lib80211.h>
#include <net/cfg80211.h>
#define LIBIPW_VERSION "git-1.1.13"
@@ -699,6 +697,76 @@ struct libipw_geo {
struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
};
+#define NUM_WEP_KEYS 4
+
+enum {
+ IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
+};
+
+struct module;
+
+struct libipw_crypto_ops {
+ const char *name;
+ struct list_head list;
+
+ /* init new crypto context (e.g., allocate private data space,
+ * select IV, etc.); returns NULL on failure or pointer to allocated
+ * private data on success */
+ void *(*init) (int keyidx);
+
+ /* deinitialize crypto context and free allocated private data */
+ void (*deinit) (void *priv);
+
+ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
+ * value from decrypt_mpdu is passed as the keyidx value for
+ * decrypt_msdu. skb must have enough head and tail room for the
+ * encryption; if not, error will be returned; these functions are
+ * called for all MPDUs (i.e., fragments).
+ */
+ int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+ int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
+
+ /* These functions are called for full MSDUs, i.e. full frames.
+ * These can be NULL if full MSDU operations are not needed. */
+ int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
+ int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
+ void *priv);
+
+ int (*set_key) (void *key, int len, u8 * seq, void *priv);
+ int (*get_key) (void *key, int len, u8 * seq, void *priv);
+
+ /* procfs handler for printing out key information and possible
+ * statistics */
+ void (*print_stats) (struct seq_file *m, void *priv);
+
+ /* Crypto specific flag get/set for configuration settings */
+ unsigned long (*get_flags) (void *priv);
+ unsigned long (*set_flags) (unsigned long flags, void *priv);
+
+ /* maximum number of bytes added by encryption; encrypt buf is
+ * allocated with extra_prefix_len bytes, copy of in_buf, and
+ * extra_postfix_len; encrypt need not use all this space, but
+ * the result must start at the beginning of the buffer and correct
+ * length must be returned */
+ int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
+ int extra_msdu_prefix_len, extra_msdu_postfix_len;
+
+ struct module *owner;
+};
+
+struct libipw_crypt_info {
+ char *name;
+ /* Most clients will already have a lock,
+ so just point to that. */
+ spinlock_t *lock;
+
+ struct libipw_crypt_data *crypt[NUM_WEP_KEYS];
+ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+ struct list_head crypt_deinit_list;
+ struct timer_list crypt_deinit_timer;
+ int crypt_quiesced;
+};
+
struct libipw_device {
struct net_device *dev;
struct wireless_dev wdev;
@@ -720,6 +788,7 @@ struct libipw_device {
int iw_mode; /* operating mode (IW_MODE_*) */
struct iw_spy_data spy_data; /* iwspy support */
+ bool spy_enabled;
spinlock_t lock;
@@ -751,7 +820,7 @@ struct libipw_device {
size_t wpa_ie_len;
u8 *wpa_ie;
- struct lib80211_crypt_info crypt_info;
+ struct libipw_crypt_info crypt_info;
int bcrx_sta_key; /* use individual keys to override default keys even
* with RX of broad/multicast frames */
@@ -988,4 +1057,43 @@ static inline int libipw_get_scans(struct libipw_device *ieee)
return ieee->scans;
}
+struct libipw_crypt_data {
+ struct list_head list; /* delayed deletion list */
+ const struct libipw_crypto_ops *ops;
+ void *priv;
+ atomic_t refcnt;
+};
+
+int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name,
+ spinlock_t *lock);
+void libipw_crypt_info_free(struct libipw_crypt_info *info);
+int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops);
+int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops);
+const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name);
+void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info,
+ struct libipw_crypt_data **crypt);
+
+/* must be called in the listed order */
+int libipw_crypto_init(void);
+int libipw_crypto_ccmp_init(void);
+int libipw_crypto_tkip_init(void);
+int libipw_crypto_wep_init(void);
+
+void libipw_crypto_wep_exit(void);
+void libipw_crypto_tkip_exit(void);
+void libipw_crypto_ccmp_exit(void);
+void libipw_crypto_exit(void);
+
+
+int ipw_wx_set_spy(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+int ipw_wx_get_spy(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+int ipw_wx_set_thrspy(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+int ipw_wx_get_thrspy(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+void libipw_spy_update(struct net_device *dev, unsigned char *address,
+ struct iw_quality *wstats);
+
#endif /* LIBIPW_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c
new file mode 100644
index 000000000000..32639e0e8430
--- /dev/null
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * libipw -- common bits for IPW drivers
+ *
+ * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
+ *
+ * Portions copied from old ieee80211 component, w/ original copyright
+ * notices below:
+ *
+ * Host AP crypto routines
+ *
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/ieee80211.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "libipw.h"
+
+struct libipw_crypto_alg {
+ struct list_head list;
+ const struct libipw_crypto_ops *ops;
+};
+
+static LIST_HEAD(libipw_crypto_algs);
+static DEFINE_SPINLOCK(libipw_crypto_lock);
+
+static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info,
+ int force);
+static void libipw_crypt_quiescing(struct libipw_crypt_info *info);
+static void libipw_crypt_deinit_handler(struct timer_list *t);
+
+int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name,
+ spinlock_t *lock)
+{
+ memset(info, 0, sizeof(*info));
+
+ info->name = name;
+ info->lock = lock;
+
+ INIT_LIST_HEAD(&info->crypt_deinit_list);
+ timer_setup(&info->crypt_deinit_timer, libipw_crypt_deinit_handler,
+ 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(libipw_crypt_info_init);
+
+void libipw_crypt_info_free(struct libipw_crypt_info *info)
+{
+ int i;
+
+ libipw_crypt_quiescing(info);
+ del_timer_sync(&info->crypt_deinit_timer);
+ libipw_crypt_deinit_entries(info, 1);
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ struct libipw_crypt_data *crypt = info->crypt[i];
+ if (crypt) {
+ if (crypt->ops) {
+ crypt->ops->deinit(crypt->priv);
+ module_put(crypt->ops->owner);
+ }
+ kfree(crypt);
+ info->crypt[i] = NULL;
+ }
+ }
+}
+EXPORT_SYMBOL(libipw_crypt_info_free);
+
+static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info,
+ int force)
+{
+ struct libipw_crypt_data *entry, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(info->lock, flags);
+ list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
+ if (atomic_read(&entry->refcnt) != 0 && !force)
+ continue;
+
+ list_del(&entry->list);
+
+ if (entry->ops) {
+ entry->ops->deinit(entry->priv);
+ module_put(entry->ops->owner);
+ }
+ kfree(entry);
+ }
+ spin_unlock_irqrestore(info->lock, flags);
+}
+
+/* After this, crypt_deinit_list won't accept new members */
+static void libipw_crypt_quiescing(struct libipw_crypt_info *info)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(info->lock, flags);
+ info->crypt_quiesced = 1;
+ spin_unlock_irqrestore(info->lock, flags);
+}
+
+static void libipw_crypt_deinit_handler(struct timer_list *t)
+{
+ struct libipw_crypt_info *info = from_timer(info, t,
+ crypt_deinit_timer);
+ unsigned long flags;
+
+ libipw_crypt_deinit_entries(info, 0);
+
+ spin_lock_irqsave(info->lock, flags);
+ if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
+ printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
+ "deletion list\n", info->name);
+ info->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&info->crypt_deinit_timer);
+ }
+ spin_unlock_irqrestore(info->lock, flags);
+}
+
+void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info,
+ struct libipw_crypt_data **crypt)
+{
+ struct libipw_crypt_data *tmp;
+ unsigned long flags;
+
+ if (*crypt == NULL)
+ return;
+
+ tmp = *crypt;
+ *crypt = NULL;
+
+ /* must not run ops->deinit() while there may be pending encrypt or
+ * decrypt operations. Use a list of delayed deinits to avoid needing
+ * locking. */
+
+ spin_lock_irqsave(info->lock, flags);
+ if (!info->crypt_quiesced) {
+ list_add(&tmp->list, &info->crypt_deinit_list);
+ if (!timer_pending(&info->crypt_deinit_timer)) {
+ info->crypt_deinit_timer.expires = jiffies + HZ;
+ add_timer(&info->crypt_deinit_timer);
+ }
+ }
+ spin_unlock_irqrestore(info->lock, flags);
+}
+EXPORT_SYMBOL(libipw_crypt_delayed_deinit);
+
+int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops)
+{
+ unsigned long flags;
+ struct libipw_crypto_alg *alg;
+
+ alg = kzalloc(sizeof(*alg), GFP_KERNEL);
+ if (alg == NULL)
+ return -ENOMEM;
+
+ alg->ops = ops;
+
+ spin_lock_irqsave(&libipw_crypto_lock, flags);
+ list_add(&alg->list, &libipw_crypto_algs);
+ spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+
+ printk(KERN_DEBUG "libipw_crypt: registered algorithm '%s'\n",
+ ops->name);
+
+ return 0;
+}
+EXPORT_SYMBOL(libipw_register_crypto_ops);
+
+int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops)
+{
+ struct libipw_crypto_alg *alg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&libipw_crypto_lock, flags);
+ list_for_each_entry(alg, &libipw_crypto_algs, list) {
+ if (alg->ops == ops)
+ goto found;
+ }
+ spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+ return -EINVAL;
+
+ found:
+ printk(KERN_DEBUG "libipw_crypt: unregistered algorithm '%s'\n",
+ ops->name);
+ list_del(&alg->list);
+ spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+ kfree(alg);
+ return 0;
+}
+EXPORT_SYMBOL(libipw_unregister_crypto_ops);
+
+const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name)
+{
+ struct libipw_crypto_alg *alg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&libipw_crypto_lock, flags);
+ list_for_each_entry(alg, &libipw_crypto_algs, list) {
+ if (strcmp(alg->ops->name, name) == 0)
+ goto found;
+ }
+ spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+ return NULL;
+
+ found:
+ spin_unlock_irqrestore(&libipw_crypto_lock, flags);
+ return alg->ops;
+}
+EXPORT_SYMBOL(libipw_get_crypto_ops);
+
+static void *libipw_crypt_null_init(int keyidx)
+{
+ return (void *)1;
+}
+
+static void libipw_crypt_null_deinit(void *priv)
+{
+}
+
+static const struct libipw_crypto_ops libipw_crypt_null = {
+ .name = "NULL",
+ .init = libipw_crypt_null_init,
+ .deinit = libipw_crypt_null_deinit,
+ .owner = THIS_MODULE,
+};
+
+int __init libipw_crypto_init(void)
+{
+ return libipw_register_crypto_ops(&libipw_crypt_null);
+}
+
+void libipw_crypto_exit(void)
+{
+ libipw_unregister_crypto_ops(&libipw_crypt_null);
+ BUG_ON(!list_empty(&libipw_crypto_algs));
+}
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c
index 5aad139130e1..bf900d8c8ad3 100644
--- a/net/wireless/lib80211_crypt_ccmp.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * lib80211 crypt: host-based CCMP encryption implementation for lib80211
+ * libipw crypt: host-based CCMP encryption implementation for libipw
*
* Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
@@ -18,17 +18,10 @@
#include <linux/if_arp.h>
#include <asm/string.h>
#include <linux/wireless.h>
-
#include <linux/ieee80211.h>
-
#include <linux/crypto.h>
#include <crypto/aead.h>
-
-#include <net/lib80211.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP crypt: CCMP");
-MODULE_LICENSE("GPL");
+#include "libipw.h"
#define AES_BLOCK_LEN 16
#define CCMP_HDR_LEN 8
@@ -36,7 +29,7 @@ MODULE_LICENSE("GPL");
#define CCMP_TK_LEN 16
#define CCMP_PN_LEN 6
-struct lib80211_ccmp_data {
+struct libipw_ccmp_data {
u8 key[CCMP_TK_LEN];
int key_set;
@@ -56,9 +49,9 @@ struct lib80211_ccmp_data {
u8 rx_aad[2 * AES_BLOCK_LEN];
};
-static void *lib80211_ccmp_init(int key_idx)
+static void *libipw_ccmp_init(int key_idx)
{
- struct lib80211_ccmp_data *priv;
+ struct libipw_ccmp_data *priv;
priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
if (priv == NULL)
@@ -83,9 +76,9 @@ static void *lib80211_ccmp_init(int key_idx)
return NULL;
}
-static void lib80211_ccmp_deinit(void *priv)
+static void libipw_ccmp_deinit(void *priv)
{
- struct lib80211_ccmp_data *_priv = priv;
+ struct libipw_ccmp_data *_priv = priv;
if (_priv && _priv->tfm)
crypto_free_aead(_priv->tfm);
kfree(priv);
@@ -150,10 +143,10 @@ static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr,
return aad_len;
}
-static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
+static int libipw_ccmp_hdr(struct sk_buff *skb, int hdr_len,
u8 *aeskey, int keylen, void *priv)
{
- struct lib80211_ccmp_data *key = priv;
+ struct libipw_ccmp_data *key = priv;
int i;
u8 *pos;
@@ -187,9 +180,9 @@ static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
return CCMP_HDR_LEN;
}
-static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_ccmp_data *key = priv;
+ struct libipw_ccmp_data *key = priv;
struct ieee80211_hdr *hdr;
struct aead_request *req;
struct scatterlist sg[2];
@@ -202,7 +195,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
return -1;
data_len = skb->len - hdr_len;
- len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
+ len = libipw_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
if (len < 0)
return -1;
@@ -251,9 +244,9 @@ static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o)
return 0;
}
-static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_ccmp_data *key = priv;
+ struct libipw_ccmp_data *key = priv;
u8 keyidx, *pos;
struct ieee80211_hdr *hdr;
struct aead_request *req;
@@ -299,7 +292,7 @@ static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += 8;
if (ccmp_replay_check(pn, key->rx_pn)) {
-#ifdef CONFIG_LIB80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
net_dbg_ratelimited("CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x\n",
hdr->addr2,
key->rx_pn[0], key->rx_pn[1], key->rx_pn[2],
@@ -344,9 +337,9 @@ static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return keyidx;
}
-static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_ccmp_data *data = priv;
+ struct libipw_ccmp_data *data = priv;
int keyidx;
struct crypto_aead *tfm = data->tfm;
@@ -376,9 +369,9 @@ static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv)
return 0;
}
-static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_ccmp_data *data = priv;
+ struct libipw_ccmp_data *data = priv;
if (len < CCMP_TK_LEN)
return -1;
@@ -399,9 +392,9 @@ static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv)
return CCMP_TK_LEN;
}
-static void lib80211_ccmp_print_stats(struct seq_file *m, void *priv)
+static void libipw_ccmp_print_stats(struct seq_file *m, void *priv)
{
- struct lib80211_ccmp_data *ccmp = priv;
+ struct libipw_ccmp_data *ccmp = priv;
seq_printf(m,
"key[%d] alg=CCMP key_set=%d "
@@ -418,31 +411,28 @@ static void lib80211_ccmp_print_stats(struct seq_file *m, void *priv)
ccmp->dot11RSNAStatsCCMPDecryptErrors);
}
-static const struct lib80211_crypto_ops lib80211_crypt_ccmp = {
+static const struct libipw_crypto_ops libipw_crypt_ccmp = {
.name = "CCMP",
- .init = lib80211_ccmp_init,
- .deinit = lib80211_ccmp_deinit,
- .encrypt_mpdu = lib80211_ccmp_encrypt,
- .decrypt_mpdu = lib80211_ccmp_decrypt,
+ .init = libipw_ccmp_init,
+ .deinit = libipw_ccmp_deinit,
+ .encrypt_mpdu = libipw_ccmp_encrypt,
+ .decrypt_mpdu = libipw_ccmp_decrypt,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
- .set_key = lib80211_ccmp_set_key,
- .get_key = lib80211_ccmp_get_key,
- .print_stats = lib80211_ccmp_print_stats,
+ .set_key = libipw_ccmp_set_key,
+ .get_key = libipw_ccmp_get_key,
+ .print_stats = libipw_ccmp_print_stats,
.extra_mpdu_prefix_len = CCMP_HDR_LEN,
.extra_mpdu_postfix_len = CCMP_MIC_LEN,
.owner = THIS_MODULE,
};
-static int __init lib80211_crypto_ccmp_init(void)
+int __init libipw_crypto_ccmp_init(void)
{
- return lib80211_register_crypto_ops(&lib80211_crypt_ccmp);
+ return libipw_register_crypto_ops(&libipw_crypt_ccmp);
}
-static void __exit lib80211_crypto_ccmp_exit(void)
+void libipw_crypto_ccmp_exit(void)
{
- lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp);
+ libipw_unregister_crypto_ops(&libipw_crypt_ccmp);
}
-
-module_init(lib80211_crypto_ccmp_init);
-module_exit(lib80211_crypto_ccmp_exit);
diff --git a/net/wireless/lib80211_crypt_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
index 63e68e5e121e..32288697da4f 100644
--- a/net/wireless/lib80211_crypt_tkip.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * lib80211 crypt: host-based TKIP encryption implementation for lib80211
+ * libipw crypt: host-based TKIP encryption implementation for libipw
*
* Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
@@ -21,25 +21,18 @@
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <asm/string.h>
-
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
-
#include <crypto/arc4.h>
#include <crypto/hash.h>
#include <linux/crypto.h>
#include <linux/crc32.h>
-
-#include <net/lib80211.h>
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("lib80211 crypt: TKIP");
-MODULE_LICENSE("GPL");
+#include "libipw.h"
#define TKIP_HDR_LEN 8
-struct lib80211_tkip_data {
+struct libipw_tkip_data {
#define TKIP_KEY_LEN 32
u8 key[TKIP_KEY_LEN];
int key_set;
@@ -73,23 +66,23 @@ struct lib80211_tkip_data {
unsigned long flags;
};
-static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv)
+static unsigned long libipw_tkip_set_flags(unsigned long flags, void *priv)
{
- struct lib80211_tkip_data *_priv = priv;
+ struct libipw_tkip_data *_priv = priv;
unsigned long old_flags = _priv->flags;
_priv->flags = flags;
return old_flags;
}
-static unsigned long lib80211_tkip_get_flags(void *priv)
+static unsigned long libipw_tkip_get_flags(void *priv)
{
- struct lib80211_tkip_data *_priv = priv;
+ struct libipw_tkip_data *_priv = priv;
return _priv->flags;
}
-static void *lib80211_tkip_init(int key_idx)
+static void *libipw_tkip_init(int key_idx)
{
- struct lib80211_tkip_data *priv;
+ struct libipw_tkip_data *priv;
if (fips_enabled)
return NULL;
@@ -124,9 +117,9 @@ static void *lib80211_tkip_init(int key_idx)
return NULL;
}
-static void lib80211_tkip_deinit(void *priv)
+static void libipw_tkip_deinit(void *priv)
{
- struct lib80211_tkip_data *_priv = priv;
+ struct libipw_tkip_data *_priv = priv;
if (_priv) {
crypto_free_shash(_priv->tx_tfm_michael);
crypto_free_shash(_priv->rx_tfm_michael);
@@ -280,10 +273,10 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
#endif
}
-static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
+static int libipw_tkip_hdr(struct sk_buff *skb, int hdr_len,
u8 * rc4key, int keylen, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
u8 *pos;
struct ieee80211_hdr *hdr;
@@ -324,9 +317,9 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
return TKIP_HDR_LEN;
}
-static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
int len;
u8 rc4key[16], *pos, *icv;
u32 crc;
@@ -344,7 +337,7 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
len = skb->len - hdr_len;
pos = skb->data + hdr_len;
- if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
+ if ((libipw_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
return -1;
crc = ~crc32_le(~0, pos, len);
@@ -373,9 +366,9 @@ static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
return 0;
}
-static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
u8 rc4key[16];
u8 keyidx, *pos;
u32 iv32;
@@ -419,7 +412,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
pos += TKIP_HDR_LEN;
if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
-#ifdef CONFIG_LIB80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n",
hdr->addr2, tkey->rx_iv32, tkey->rx_iv16,
iv32, iv16);
@@ -450,7 +443,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
* it needs to be recalculated for the next packet. */
tkey->rx_phase1_done = 0;
}
-#ifdef CONFIG_LIB80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n",
hdr->addr2);
#endif
@@ -538,10 +531,10 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
}
-static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
+static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len,
void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
u8 *pos;
if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
@@ -560,7 +553,7 @@ static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
return 0;
}
-static void lib80211_michael_mic_failure(struct net_device *dev,
+static void libipw_michael_mic_failure(struct net_device *dev,
struct ieee80211_hdr *hdr,
int keyidx)
{
@@ -581,10 +574,10 @@ static void lib80211_michael_mic_failure(struct net_device *dev,
wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
}
-static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
+static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
int hdr_len, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
u8 mic[8];
if (!tkey->key_set)
@@ -602,7 +595,7 @@ static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
skb->dev ? skb->dev->name : "N/A", hdr->addr2,
keyidx);
if (skb->dev)
- lib80211_michael_mic_failure(skb->dev, hdr, keyidx);
+ libipw_michael_mic_failure(skb->dev, hdr, keyidx);
tkey->dot11RSNAStatsTKIPLocalMICFailures++;
return -1;
}
@@ -617,9 +610,9 @@ static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
return 0;
}
-static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
int keyidx;
struct crypto_shash *tfm = tkey->tx_tfm_michael;
struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4;
@@ -650,9 +643,9 @@ static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
return 0;
}
-static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_tkip_get_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_tkip_data *tkey = priv;
+ struct libipw_tkip_data *tkey = priv;
if (len < TKIP_KEY_LEN)
return -1;
@@ -679,9 +672,9 @@ static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
return TKIP_KEY_LEN;
}
-static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
+static void libipw_tkip_print_stats(struct seq_file *m, void *priv)
{
- struct lib80211_tkip_data *tkip = priv;
+ struct libipw_tkip_data *tkip = priv;
seq_printf(m,
"key[%d] alg=TKIP key_set=%d "
"tx_pn=%02x%02x%02x%02x%02x%02x "
@@ -705,34 +698,31 @@ static void lib80211_tkip_print_stats(struct seq_file *m, void *priv)
tkip->dot11RSNAStatsTKIPLocalMICFailures);
}
-static const struct lib80211_crypto_ops lib80211_crypt_tkip = {
+static const struct libipw_crypto_ops libipw_crypt_tkip = {
.name = "TKIP",
- .init = lib80211_tkip_init,
- .deinit = lib80211_tkip_deinit,
- .encrypt_mpdu = lib80211_tkip_encrypt,
- .decrypt_mpdu = lib80211_tkip_decrypt,
- .encrypt_msdu = lib80211_michael_mic_add,
- .decrypt_msdu = lib80211_michael_mic_verify,
- .set_key = lib80211_tkip_set_key,
- .get_key = lib80211_tkip_get_key,
- .print_stats = lib80211_tkip_print_stats,
+ .init = libipw_tkip_init,
+ .deinit = libipw_tkip_deinit,
+ .encrypt_mpdu = libipw_tkip_encrypt,
+ .decrypt_mpdu = libipw_tkip_decrypt,
+ .encrypt_msdu = libipw_michael_mic_add,
+ .decrypt_msdu = libipw_michael_mic_verify,
+ .set_key = libipw_tkip_set_key,
+ .get_key = libipw_tkip_get_key,
+ .print_stats = libipw_tkip_print_stats,
.extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
.extra_mpdu_postfix_len = 4, /* ICV */
.extra_msdu_postfix_len = 8, /* MIC */
- .get_flags = lib80211_tkip_get_flags,
- .set_flags = lib80211_tkip_set_flags,
+ .get_flags = libipw_tkip_get_flags,
+ .set_flags = libipw_tkip_set_flags,
.owner = THIS_MODULE,
};
-static int __init lib80211_crypto_tkip_init(void)
+int __init libipw_crypto_tkip_init(void)
{
- return lib80211_register_crypto_ops(&lib80211_crypt_tkip);
+ return libipw_register_crypto_ops(&libipw_crypt_tkip);
}
-static void __exit lib80211_crypto_tkip_exit(void)
+void libipw_crypto_tkip_exit(void)
{
- lib80211_unregister_crypto_ops(&lib80211_crypt_tkip);
+ libipw_unregister_crypto_ops(&libipw_crypt_tkip);
}
-
-module_init(lib80211_crypto_tkip_init);
-module_exit(lib80211_crypto_tkip_exit);
diff --git a/net/wireless/lib80211_crypt_wep.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c
index 3b148c7bef85..c3a4ccb9de17 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * lib80211 crypt: host-based WEP encryption implementation for lib80211
+ * libipw crypt: host-based WEP encryption implementation for libipw
*
* Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
@@ -16,17 +16,11 @@
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <asm/string.h>
-
-#include <net/lib80211.h>
-
#include <crypto/arc4.h>
#include <linux/crc32.h>
+#include "libipw.h"
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("lib80211 crypt: WEP");
-MODULE_LICENSE("GPL");
-
-struct lib80211_wep_data {
+struct libipw_wep_data {
u32 iv;
#define WEP_KEY_LEN 13
u8 key[WEP_KEY_LEN + 1];
@@ -36,9 +30,9 @@ struct lib80211_wep_data {
struct arc4_ctx rx_ctx;
};
-static void *lib80211_wep_init(int keyidx)
+static void *libipw_wep_init(int keyidx)
{
- struct lib80211_wep_data *priv;
+ struct libipw_wep_data *priv;
if (fips_enabled)
return NULL;
@@ -54,16 +48,16 @@ static void *lib80211_wep_init(int keyidx)
return priv;
}
-static void lib80211_wep_deinit(void *priv)
+static void libipw_wep_deinit(void *priv)
{
kfree_sensitive(priv);
}
/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
-static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
+static int libipw_wep_build_iv(struct sk_buff *skb, int hdr_len,
u8 *key, int keylen, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
u32 klen;
u8 *pos;
@@ -102,19 +96,19 @@ static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len,
*
* WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
*/
-static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
u32 crc, klen, len;
u8 *pos, *icv;
u8 key[WEP_KEY_LEN + 3];
- /* other checks are in lib80211_wep_build_iv */
+ /* other checks are in libipw_wep_build_iv */
if (skb_tailroom(skb) < 4)
return -1;
/* add the IV to the frame */
- if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv))
+ if (libipw_wep_build_iv(skb, hdr_len, NULL, 0, priv))
return -1;
/* Copy the IV into the first 3 bytes of the key */
@@ -148,9 +142,9 @@ static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
* Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
* failure. If frame is OK, IV and ICV will be removed.
*/
-static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
+static int libipw_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
u32 crc, klen, plen;
u8 key[WEP_KEY_LEN + 3];
u8 keyidx, *pos, icv[4];
@@ -195,9 +189,9 @@ static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return 0;
}
-static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_wep_set_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
if (len < 0 || len > WEP_KEY_LEN)
return -1;
@@ -208,9 +202,9 @@ static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv)
return 0;
}
-static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
+static int libipw_wep_get_key(void *key, int len, u8 * seq, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
if (len < wep->key_len)
return -1;
@@ -220,37 +214,34 @@ static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv)
return wep->key_len;
}
-static void lib80211_wep_print_stats(struct seq_file *m, void *priv)
+static void libipw_wep_print_stats(struct seq_file *m, void *priv)
{
- struct lib80211_wep_data *wep = priv;
+ struct libipw_wep_data *wep = priv;
seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
}
-static const struct lib80211_crypto_ops lib80211_crypt_wep = {
+static const struct libipw_crypto_ops libipw_crypt_wep = {
.name = "WEP",
- .init = lib80211_wep_init,
- .deinit = lib80211_wep_deinit,
- .encrypt_mpdu = lib80211_wep_encrypt,
- .decrypt_mpdu = lib80211_wep_decrypt,
+ .init = libipw_wep_init,
+ .deinit = libipw_wep_deinit,
+ .encrypt_mpdu = libipw_wep_encrypt,
+ .decrypt_mpdu = libipw_wep_decrypt,
.encrypt_msdu = NULL,
.decrypt_msdu = NULL,
- .set_key = lib80211_wep_set_key,
- .get_key = lib80211_wep_get_key,
- .print_stats = lib80211_wep_print_stats,
+ .set_key = libipw_wep_set_key,
+ .get_key = libipw_wep_get_key,
+ .print_stats = libipw_wep_print_stats,
.extra_mpdu_prefix_len = 4, /* IV */
.extra_mpdu_postfix_len = 4, /* ICV */
.owner = THIS_MODULE,
};
-static int __init lib80211_crypto_wep_init(void)
+int __init libipw_crypto_wep_init(void)
{
- return lib80211_register_crypto_ops(&lib80211_crypt_wep);
+ return libipw_register_crypto_ops(&libipw_crypt_wep);
}
-static void __exit lib80211_crypto_wep_exit(void)
+void __exit libipw_crypto_wep_exit(void)
{
- lib80211_unregister_crypto_ops(&lib80211_crypt_wep);
+ libipw_unregister_crypto_ops(&libipw_crypt_wep);
}
-
-module_init(lib80211_crypto_wep_init);
-module_exit(lib80211_crypto_wep_exit);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
index 43bab92a4148..0a16127bfd68 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
@@ -169,7 +169,7 @@ struct net_device *alloc_libipw(int sizeof_priv, int monitor)
spin_lock_init(&ieee->lock);
- lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
+ libipw_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
ieee->wpa_enabled = 0;
ieee->drop_unencrypted = 0;
@@ -191,7 +191,7 @@ void free_libipw(struct net_device *dev, int monitor)
{
struct libipw_device *ieee = netdev_priv(dev);
- lib80211_crypt_info_free(&ieee->crypt_info);
+ libipw_crypt_info_free(&ieee->crypt_info);
libipw_networks_free(ieee);
@@ -251,6 +251,7 @@ static const struct proc_ops debug_level_proc_ops = {
static int __init libipw_init(void)
{
+ int err;
#ifdef CONFIG_LIBIPW_DEBUG
struct proc_dir_entry *e;
@@ -273,7 +274,33 @@ static int __init libipw_init(void)
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ err = libipw_crypto_init();
+ if (err)
+ goto remove_debugfs;
+ err = libipw_crypto_ccmp_init();
+ if (err)
+ goto uninit_crypto;
+ err = libipw_crypto_tkip_init();
+ if (err)
+ goto uninit_crypto_ccmp;
+ err = libipw_crypto_wep_init();
+ if (err)
+ goto uninit_crypto_tkip;
+
return 0;
+uninit_crypto_tkip:
+ libipw_crypto_tkip_exit();
+uninit_crypto_ccmp:
+ libipw_crypto_ccmp_exit();
+uninit_crypto:
+ libipw_crypto_exit();
+remove_debugfs:
+#ifdef CONFIG_LIBIPW_DEBUG
+ remove_proc_entry("debug_level", libipw_proc);
+ remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
+ libipw_proc = NULL;
+#endif
+ return err;
}
static void __exit libipw_exit(void)
@@ -285,6 +312,11 @@ static void __exit libipw_exit(void)
libipw_proc = NULL;
}
#endif /* CONFIG_LIBIPW_DEBUG */
+
+ libipw_crypto_ccmp_exit();
+ libipw_crypto_tkip_exit();
+ libipw_crypto_wep_exit();
+ libipw_crypto_exit();
}
#ifdef CONFIG_LIBIPW_DEBUG
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
index 48d6870bbf4e..dc4e91f58bb4 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
@@ -27,9 +27,6 @@
#include <linux/etherdevice.h>
#include <linux/uaccess.h>
#include <linux/ctype.h>
-
-#include <net/lib80211.h>
-
#include "libipw.h"
static void libipw_monitor_rx(struct libipw_device *ieee,
@@ -266,7 +263,7 @@ static int libipw_is_eapol_frame(struct libipw_device *ieee,
/* Called only as a tasklet (software IRQ), by libipw_rx */
static int
libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
+ struct libipw_crypt_data *crypt)
{
struct libipw_hdr_3addr *hdr;
int res, hdrlen;
@@ -298,7 +295,7 @@ libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
static int
libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
struct sk_buff *skb, int keyidx,
- struct lib80211_crypt_data *crypt)
+ struct libipw_crypt_data *crypt)
{
struct libipw_hdr_3addr *hdr;
int res, hdrlen;
@@ -345,7 +342,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
#endif
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
+ struct libipw_crypt_data *crypt = NULL;
int keyidx = 0;
int can_be_decrypted = 0;
@@ -396,7 +393,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
wstats.updated |= IW_QUAL_QUAL_INVALID;
/* Update spy records */
- wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
+ libipw_spy_update(ieee->dev, hdr->addr2, &wstats);
}
#endif /* IW_WIRELESS_SPY */
#endif /* CONFIG_WIRELESS_EXT */
@@ -870,8 +867,8 @@ void libipw_rx_any(struct libipw_device *ieee,
switch (ieee->iw_mode) {
case IW_MODE_ADHOC:
/* our BSS and not from/to DS */
- if (ether_addr_equal(hdr->addr3, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
+ if (ether_addr_equal(hdr->addr3, ieee->bssid) &&
+ ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == 0)) {
/* promisc: get all */
if (ieee->dev->flags & IFF_PROMISC)
is_packet_for_us = 1;
@@ -885,8 +882,8 @@ void libipw_rx_any(struct libipw_device *ieee,
break;
case IW_MODE_INFRA:
/* our BSS (== from our AP) and from DS */
- if (ether_addr_equal(hdr->addr2, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
+ if (ether_addr_equal(hdr->addr2, ieee->bssid) &&
+ ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS)) {
/* promisc: get all */
if (ieee->dev->flags & IFF_PROMISC)
is_packet_for_us = 1;
diff --git a/net/wireless/wext-spy.c b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c
index b379a0371653..ba876e92f7f6 100644
--- a/net/wireless/wext-spy.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c
@@ -14,19 +14,21 @@
#include <net/iw_handler.h>
#include <net/arp.h>
#include <net/wext.h>
+#include "libipw.h"
-static inline struct iw_spy_data *get_spydata(struct net_device *dev)
+static struct iw_spy_data *get_spydata(struct net_device *dev)
{
- /* This is the new way */
- if (dev->wireless_data)
- return dev->wireless_data->spy_data;
+ struct libipw_device *ieee = netdev_priv(dev);
+
+ if (ieee->spy_enabled)
+ return &ieee->spy_data;
return NULL;
}
-int iw_handler_set_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+int ipw_wx_set_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
struct iw_spy_data * spydata = get_spydata(dev);
struct sockaddr * address = (struct sockaddr *) extra;
@@ -36,15 +38,15 @@ int iw_handler_set_spy(struct net_device * dev,
return -EOPNOTSUPP;
/* Disable spy collection while we copy the addresses.
- * While we copy addresses, any call to wireless_spy_update()
+ * While we copy addresses, any call to libipw_spy_update()
* will NOP. This is OK, as anyway the addresses are changing. */
spydata->spy_number = 0;
- /* We want to operate without locking, because wireless_spy_update()
+ /* We want to operate without locking, because libipw_spy_update()
* most likely will happen in the interrupt handler, and therefore
* have its own locking constraints and needs performance.
* The rtnl_lock() make sure we don't race with the other iw_handlers.
- * This make sure wireless_spy_update() "see" that the spy list
+ * This make sure libipw_spy_update() "see" that the spy list
* is temporarily disabled. */
smp_wmb();
@@ -69,12 +71,12 @@ int iw_handler_set_spy(struct net_device * dev,
return 0;
}
-EXPORT_SYMBOL(iw_handler_set_spy);
+EXPORT_SYMBOL(ipw_wx_set_spy);
-int iw_handler_get_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+int ipw_wx_get_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
struct iw_spy_data * spydata = get_spydata(dev);
struct sockaddr * address = (struct sockaddr *) extra;
@@ -101,16 +103,16 @@ int iw_handler_get_spy(struct net_device * dev,
spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
return 0;
}
-EXPORT_SYMBOL(iw_handler_get_spy);
+EXPORT_SYMBOL(ipw_wx_get_spy);
/*------------------------------------------------------------------*/
/*
* Standard Wireless Handler : set spy threshold
*/
-int iw_handler_set_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
+int ipw_wx_set_thrspy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
struct iw_spy_data * spydata = get_spydata(dev);
struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
@@ -128,16 +130,16 @@ int iw_handler_set_thrspy(struct net_device * dev,
return 0;
}
-EXPORT_SYMBOL(iw_handler_set_thrspy);
+EXPORT_SYMBOL(ipw_wx_set_thrspy);
/*------------------------------------------------------------------*/
/*
* Standard Wireless Handler : get spy threshold
*/
-int iw_handler_get_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
+int ipw_wx_get_thrspy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
struct iw_spy_data * spydata = get_spydata(dev);
struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
@@ -152,7 +154,7 @@ int iw_handler_get_thrspy(struct net_device * dev,
return 0;
}
-EXPORT_SYMBOL(iw_handler_get_thrspy);
+EXPORT_SYMBOL(ipw_wx_get_thrspy);
/*------------------------------------------------------------------*/
/*
@@ -189,9 +191,9 @@ static void iw_send_thrspy_event(struct net_device * dev,
* small, this is good enough. If we wanted to support larger number of
* spy addresses, we should use something more efficient...
*/
-void wireless_spy_update(struct net_device * dev,
- unsigned char * address,
- struct iw_quality * wstats)
+void libipw_spy_update(struct net_device * dev,
+ unsigned char * address,
+ struct iw_quality * wstats)
{
struct iw_spy_data * spydata = get_spydata(dev);
int i;
@@ -229,4 +231,3 @@ void wireless_spy_update(struct net_device * dev,
}
}
}
-EXPORT_SYMBOL(wireless_spy_update);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
index e22a6732a4c3..80edaa3dea9c 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
@@ -138,7 +138,7 @@ static int libipw_copy_snap(u8 * data, __be16 h_proto)
static int libipw_encrypt_fragment(struct libipw_device *ieee,
struct sk_buff *frag, int hdr_len)
{
- struct lib80211_crypt_data *crypt =
+ struct libipw_crypt_data *crypt =
ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
int res;
@@ -255,7 +255,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
.qos_ctl = 0
};
u8 dest[ETH_ALEN], src[ETH_ALEN];
- struct lib80211_crypt_data *crypt;
+ struct libipw_crypt_data *crypt;
int priority = skb->priority;
int snapped = 0;
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
index dbc7153d0a3d..db71d81b0d4f 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
@@ -21,10 +21,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/jiffies.h>
-
-#include <net/lib80211.h>
#include <linux/wireless.h>
-
#include "libipw.h"
static const char *libipw_modes[] = {
@@ -303,7 +300,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
.flags = 0
};
int i, key, key_provided, len;
- struct lib80211_crypt_data **crypt;
+ struct libipw_crypt_data **crypt;
int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
LIBIPW_DEBUG_WX("SET_ENCODE\n");
@@ -328,7 +325,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
if (key_provided && *crypt) {
LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
key);
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
} else
LIBIPW_DEBUG_WX("Disabling encryption.\n");
@@ -338,7 +335,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
if (ieee->crypt_info.crypt[i] != NULL) {
if (key_provided)
break;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info,
+ libipw_crypt_delayed_deinit(&ieee->crypt_info,
&ieee->crypt_info.crypt[i]);
}
}
@@ -361,21 +358,21 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
strcmp((*crypt)->ops->name, "WEP") != 0) {
/* changing to use WEP; deinit previously used algorithm
* on this key */
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
}
if (*crypt == NULL && host_crypto) {
- struct lib80211_crypt_data *new_crypt;
+ struct libipw_crypt_data *new_crypt;
/* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
+ new_crypt = kzalloc(sizeof(struct libipw_crypt_data),
GFP_KERNEL);
if (new_crypt == NULL)
return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
+ new_crypt->ops = libipw_get_crypto_ops("WEP");
if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
+ request_module("libipw_crypt_wep");
+ new_crypt->ops = libipw_get_crypto_ops("WEP");
}
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
@@ -386,7 +383,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee,
new_crypt = NULL;
printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module lib80211_crypt_wep\n", dev->name);
+ "load module libipw_crypt_wep\n", dev->name);
return -EOPNOTSUPP;
}
*crypt = new_crypt;
@@ -509,8 +506,8 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
int i, idx, ret = 0;
int group_key = 0;
const char *alg, *module;
- const struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
+ const struct libipw_crypto_ops *ops;
+ struct libipw_crypt_data **crypt;
struct libipw_security sec = {
.flags = 0,
@@ -541,7 +538,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
if ((encoding->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) {
if (*crypt)
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
for (i = 0; i < WEP_KEYS; i++)
if (ieee->crypt_info.crypt[i] != NULL)
@@ -567,15 +564,15 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
switch (ext->alg) {
case IW_ENCODE_ALG_WEP:
alg = "WEP";
- module = "lib80211_crypt_wep";
+ module = "libipw_crypt_wep";
break;
case IW_ENCODE_ALG_TKIP:
alg = "TKIP";
- module = "lib80211_crypt_tkip";
+ module = "libipw_crypt_tkip";
break;
case IW_ENCODE_ALG_CCMP:
alg = "CCMP";
- module = "lib80211_crypt_ccmp";
+ module = "libipw_crypt_ccmp";
break;
default:
LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -584,10 +581,10 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
goto done;
}
- ops = lib80211_get_crypto_ops(alg);
+ ops = libipw_get_crypto_ops(alg);
if (ops == NULL) {
request_module(module);
- ops = lib80211_get_crypto_ops(alg);
+ ops = libipw_get_crypto_ops(alg);
}
if (ops == NULL) {
LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
@@ -597,9 +594,9 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee,
}
if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
+ struct libipw_crypt_data *new_crypt;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
+ libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt);
new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
if (new_crypt == NULL) {
diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c
index 14d2331ee6cb..b0656b143f77 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945.c
@@ -566,7 +566,7 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) ||
!(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
D_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
- rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+ return;
}
/* Convert 3945's rssi indicator to dBm */
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index fcccde7bb659..05c4af41bdb9 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -664,7 +664,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
!(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
D_RX("Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status));
- rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+ return;
}
/* This will be used in several places later */
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 9d33a66a49b5..958dd4f9bc69 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -3122,6 +3122,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
struct il_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
+ u8 *out_payload;
u32 idx;
u16 fix_size;
@@ -3157,6 +3158,16 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
+ /* The payload is in the same place in regular and huge
+ * command buffers, but we need to let the compiler know when
+ * we're using a larger payload buffer to avoid "field-
+ * spanning write" warnings at run-time for huge commands.
+ */
+ if (cmd->flags & CMD_SIZE_HUGE)
+ out_payload = ((struct il_device_cmd_huge *)out_cmd)->cmd.payload;
+ else
+ out_payload = out_cmd->cmd.payload;
+
if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
spin_unlock_irqrestore(&il->hcmd_lock, flags);
return -ENOSPC;
@@ -3170,7 +3181,7 @@ il_enqueue_hcmd(struct il_priv *il, struct il_host_cmd *cmd)
out_meta->callback = cmd->callback;
out_cmd->hdr.cmd = cmd->id;
- memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+ memcpy(out_payload, cmd->data, cmd->len);
/* At this point, the out_cmd now has all of the incoming cmd
* information */
@@ -4962,6 +4973,8 @@ il_pci_resume(struct device *device)
*/
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+ _il_wr(il, CSR_INT, 0xffffffff);
+ _il_wr(il, CSR_FH_INT_STATUS, 0xffffffff);
il_enable_interrupts(il);
if (!(_il_rd(il, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h
index 2147781b5fff..725c2a88ddb7 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.h
+++ b/drivers/net/wireless/intel/iwlegacy/common.h
@@ -560,6 +560,18 @@ struct il_device_cmd {
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct il_device_cmd))
+/**
+ * struct il_device_cmd_huge
+ *
+ * For use when sending huge commands.
+ */
+struct il_device_cmd_huge {
+ struct il_cmd_header hdr; /* uCode API */
+ union {
+ u8 payload[IL_MAX_CMD_SIZE - sizeof(struct il_cmd_header)];
+ } __packed cmd;
+} __packed;
+
struct il_host_cmd {
const void *data;
unsigned long reply_page;
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index fa1be8c54d3c..cd1fe8490ae5 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -10,10 +10,10 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
-#define IWL_BZ_UCODE_API_MAX 93
+#define IWL_BZ_UCODE_API_MAX 94
/* Lowest firmware API version supported */
-#define IWL_BZ_UCODE_API_MIN 90
+#define IWL_BZ_UCODE_API_MIN 92
/* NVM versions */
#define IWL_BZ_NVM_VERSION 0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index f1dd1c29f305..fc5e6e44c6aa 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -10,10 +10,10 @@
#include "fw/api/txq.h"
/* Highest firmware API version supported */
-#define IWL_SC_UCODE_API_MAX 93
+#define IWL_SC_UCODE_API_MAX 94
/* Lowest firmware API version supported */
-#define IWL_SC_UCODE_API_MIN 90
+#define IWL_SC_UCODE_API_MIN 92
/* NVM versions */
#define IWL_SC_NVM_VERSION 0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index a7cea0a55b35..0bc32291815e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -429,38 +429,28 @@ out_free:
return ret;
}
-static int iwl_acpi_sar_set_profile(union acpi_object *table,
- struct iwl_sar_profile *profile,
- bool enabled, u8 num_chains,
- u8 num_sub_bands)
+static int
+iwl_acpi_parse_chains_table(union acpi_object *table,
+ struct iwl_sar_profile_chain *chains,
+ u8 num_chains, u8 num_sub_bands)
{
- int i, j, idx = 0;
-
- /*
- * The table from ACPI is flat, but we store it in a
- * structured array.
- */
- for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) {
- for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) {
+ for (u8 chain = 0; chain < num_chains; chain++) {
+ for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
+ subband++) {
/* if we don't have the values, use the default */
- if (i >= num_chains || j >= num_sub_bands) {
- profile->chains[i].subbands[j] = 0;
+ if (subband >= num_sub_bands) {
+ chains[chain].subbands[subband] = 0;
+ } else if (table->type != ACPI_TYPE_INTEGER ||
+ table->integer.value > U8_MAX) {
+ return -EINVAL;
} else {
- if (table[idx].type != ACPI_TYPE_INTEGER ||
- table[idx].integer.value > U8_MAX)
- return -EINVAL;
-
- profile->chains[i].subbands[j] =
- table[idx].integer.value;
-
- idx++;
+ chains[chain].subbands[subband] =
+ table->integer.value;
+ table++;
}
}
}
- /* Only if all values were valid can the profile be enabled */
- profile->enabled = enabled;
-
return 0;
}
@@ -543,9 +533,11 @@ read_table:
/* The profile from WRDS is officially profile 1, but goes
* into sar_profiles[0] (because we don't have a profile 0).
*/
- ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0],
- flags & IWL_SAR_ENABLE_MSK,
- num_chains, num_sub_bands);
+ ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
+ num_chains, num_sub_bands);
+ if (!ret && flags & IWL_SAR_ENABLE_MSK)
+ fwrt->sar_profiles[0].enabled = true;
+
out_free:
kfree(data);
return ret;
@@ -557,7 +549,7 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
bool enabled;
int i, n_profiles, tbl_rev, pos;
int ret = 0;
- u8 num_chains, num_sub_bands;
+ u8 num_sub_bands;
data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
if (IS_ERR(data))
@@ -573,7 +565,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}
- num_chains = ACPI_SAR_NUM_CHAINS_REV2;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
goto read_table;
@@ -589,7 +580,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}
- num_chains = ACPI_SAR_NUM_CHAINS_REV1;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
goto read_table;
@@ -605,7 +595,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}
- num_chains = ACPI_SAR_NUM_CHAINS_REV0;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
goto read_table;
@@ -637,23 +626,54 @@ read_table:
/* the tables start at element 3 */
pos = 3;
+ BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1);
+ BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0);
+
+ /* parse non-cdb chains for all profiles */
for (i = 0; i < n_profiles; i++) {
union acpi_object *table = &wifi_pkg->package.elements[pos];
+
/* The EWRD profiles officially go from 2 to 4, but we
* save them in sar_profiles[1-3] (because we don't
* have profile 0). So in the array we start from 1.
*/
- ret = iwl_acpi_sar_set_profile(table,
- &fwrt->sar_profiles[i + 1],
- enabled, num_chains,
- num_sub_bands);
+ ret = iwl_acpi_parse_chains_table(table,
+ fwrt->sar_profiles[i + 1].chains,
+ ACPI_SAR_NUM_CHAINS_REV0,
+ num_sub_bands);
if (ret < 0)
- break;
+ goto out_free;
/* go to the next table */
- pos += num_chains * num_sub_bands;
+ pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
}
+ /* non-cdb table revisions */
+ if (tbl_rev < 2)
+ goto set_enabled;
+
+ /* parse cdb chains for all profiles */
+ for (i = 0; i < n_profiles; i++) {
+ struct iwl_sar_profile_chain *chains;
+ union acpi_object *table;
+
+ table = &wifi_pkg->package.elements[pos];
+ chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0];
+ ret = iwl_acpi_parse_chains_table(table,
+ chains,
+ ACPI_SAR_NUM_CHAINS_REV0,
+ num_sub_bands);
+ if (ret < 0)
+ goto out_free;
+
+ /* go to the next table */
+ pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
+ }
+
+set_enabled:
+ for (i = 0; i < n_profiles; i++)
+ fwrt->sar_profiles[i + 1].enabled = enabled;
+
out_free:
kfree(data);
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h
index 2397fdc37fc5..9b942c4aabd9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h
@@ -56,8 +56,6 @@ struct iwl_binding_cmd {
} __packed; /* BINDING_CMD_API_S_VER_2 */
#define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1)
-#define IWL_LMAC_24G_INDEX 0
-#define IWL_LMAC_5G_INDEX 1
/* The maximal number of fragments in the FW's schedule session */
#define IWL_MVM_MAX_QUOTA 128
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h
index 1fa5678c1cd6..a9fa5f054ce0 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h
@@ -40,4 +40,7 @@ enum iwl_ctxt_action {
FW_CTXT_ACTION_REMOVE,
}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */
+#define IWL_LMAC_24G_INDEX 0
+#define IWL_LMAC_5G_INDEX 1
+
#endif /* __iwl_fw_api_context_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index ffee7927cf26..c2362bc786b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -368,7 +368,7 @@ enum iwl_wowlan_flags {
};
/**
- * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6)
+ * struct iwl_wowlan_config_cmd_v6 - WoWLAN configuration (versions 5 and 6)
* @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
* @non_qos_seq: non-QoS sequence counter to use next.
* Reserved if the struct has version >= 6.
@@ -380,7 +380,7 @@ enum iwl_wowlan_flags {
* @sta_id: station ID for wowlan.
* @reserved: reserved
*/
-struct iwl_wowlan_config_cmd {
+struct iwl_wowlan_config_cmd_v6 {
__le32 wakeup_filter;
__le16 non_qos_seq;
__le16 qos_seq[8];
@@ -390,7 +390,27 @@ struct iwl_wowlan_config_cmd {
u8 flags;
u8 sta_id;
u8 reserved;
-} __packed; /* WOWLAN_CONFIG_API_S_VER_5 */
+} __packed; /* WOWLAN_CONFIG_API_S_VER_6 */
+
+/**
+ * struct iwl_wowlan_config_cmd - WoWLAN configuration
+ * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
+ * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down
+ * @is_11n_connection: indicates HT connection
+ * @offloading_tid: TID reserved for firmware use
+ * @flags: extra flags, see &enum iwl_wowlan_flags
+ * @sta_id: station ID for wowlan.
+ * @reserved: reserved
+ */
+struct iwl_wowlan_config_cmd {
+ __le32 wakeup_filter;
+ u8 wowlan_ba_teardown_tids;
+ u8 is_11n_connection;
+ u8 offloading_tid;
+ u8 flags;
+ u8 sta_id;
+ u8 reserved[3];
+} __packed; /* WOWLAN_CONFIG_API_S_VER_7 */
#define IWL_NUM_RSC 16
#define WOWLAN_KEY_MAX_SIZE 32
@@ -890,7 +910,7 @@ struct iwl_wowlan_mlo_gtk {
} __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */
/**
- * struct iwl_wowlan_info_notif - WoWLAN information notification
+ * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification
* @gtk: GTK data
* @igtk: IGTK data
* @bigtk: BIGTK data
@@ -910,7 +930,7 @@ struct iwl_wowlan_mlo_gtk {
* @reserved2: reserved
* @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4
*/
-struct iwl_wowlan_info_notif {
+struct iwl_wowlan_info_notif_v4 {
struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
@@ -930,6 +950,45 @@ struct iwl_wowlan_info_notif {
} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */
/**
+ * struct iwl_wowlan_info_notif - WoWLAN information notification
+ * @gtk: GTK data
+ * @igtk: IGTK data
+ * @bigtk: BIGTK data
+ * @replay_ctr: GTK rekey replay counter
+ * @pattern_number: number of the matched patterns
+ * @qos_seq_ctr: QoS sequence counters to use next
+ * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
+ * @num_of_gtk_rekeys: number of GTK rekeys
+ * @transmitted_ndps: number of transmitted neighbor discovery packets
+ * @received_beacons: number of received beacons
+ * @tid_tear_down: bit mask of tids whose BA sessions were closed
+ * in suspend state
+ * @station_id: station id
+ * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs
+ * following this notif
+ * @tid_offloaded_tx: tid used by the firmware to transmit data packets
+ * while in wowlan
+ * @mlo_gtks: array of GTKs of size num_mlo_link_keys
+ */
+struct iwl_wowlan_info_notif {
+ struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
+ struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
+ struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
+ __le64 replay_ctr;
+ __le16 pattern_number;
+ __le16 qos_seq_ctr;
+ __le32 wakeup_reasons;
+ __le32 num_of_gtk_rekeys;
+ __le32 transmitted_ndps;
+ __le32 received_beacons;
+ u8 tid_tear_down;
+ u8 station_id;
+ u8 num_mlo_link_keys;
+ u8 tid_offloaded_tx;
+ struct iwl_wowlan_mlo_gtk mlo_gtks[];
+} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */
+
+/**
* struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification
* @wake_packet_length: wakeup packet length
* @station_id: station id
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
index 30a54c7fa001..b8dff139aa05 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h
@@ -616,6 +616,9 @@ struct iwl_tof_range_req_ap_entry_v2 {
* continue with the session and will provide the LMR feedback.
* @IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC: send an incorrect SAC in the
* first NDP exchange. This is used for testing.
+ * @IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF: use incorrect secure LTF tx key. This
+ * is used for testing. Only supported from version 15 of the range request
+ * command.
*/
enum iwl_initiator_ap_flags {
IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1),
@@ -633,6 +636,7 @@ enum iwl_initiator_ap_flags {
IWL_INITIATOR_AP_FLAGS_PMF = BIT(14),
IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15),
IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC = BIT(16),
+ IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF = BIT(17),
};
/**
@@ -767,7 +771,7 @@ enum iwl_location_cipher {
* @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of
* the number of measurement iterations (min 2^0 = 1, max 2^14)
* @sta_id: the station id of the AP. Only relevant when associated to the AP,
- * otherwise should be set to &IWL_MVM_INVALID_STA.
+ * otherwise should be set to &IWL_INVALID_STA.
* @cipher: pairwise cipher suite for secured measurement.
* &enum iwl_location_cipher.
* @hltk: HLTK to be used for secured 11az measurement
@@ -814,7 +818,7 @@ struct iwl_tof_range_req_ap_entry_v6 {
* @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of
* the number of measurement iterations (min 2^0 = 1, max 2^14)
* @sta_id: the station id of the AP. Only relevant when associated to the AP,
- * otherwise should be set to &IWL_MVM_INVALID_STA.
+ * otherwise should be set to &IWL_INVALID_STA.
* @cipher: pairwise cipher suite for secured measurement.
* &enum iwl_location_cipher.
* @hltk: HLTK to be used for secured 11az measurement
@@ -827,10 +831,10 @@ struct iwl_tof_range_req_ap_entry_v6 {
* &IWL_INITIATOR_AP_FLAGS_TB is set.
* @rx_pn: the next expected PN for protected management frames Rx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @tx_pn: the next PN to use for protected management frames Tx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
*/
struct iwl_tof_range_req_ap_entry_v7 {
__le32 initiator_ap_flags;
@@ -872,7 +876,7 @@ struct iwl_tof_range_req_ap_entry_v7 {
* @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of
* the number of measurement iterations (min 2^0 = 1, max 2^14)
* @sta_id: the station id of the AP. Only relevant when associated to the AP,
- * otherwise should be set to &IWL_MVM_INVALID_STA.
+ * otherwise should be set to &IWL_INVALID_STA.
* @cipher: pairwise cipher suite for secured measurement.
* &enum iwl_location_cipher.
* @hltk: HLTK to be used for secured 11az measurement
@@ -885,10 +889,10 @@ struct iwl_tof_range_req_ap_entry_v7 {
* &IWL_INITIATOR_AP_FLAGS_TB is set.
* @rx_pn: the next expected PN for protected management frames Rx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @tx_pn: the next PN to use for protected management frames Tx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @r2i_ndp_params: parameters for R2I NDP ranging negotiation.
* bits 0 - 2: max LTF repetitions
* bits 3 - 5: max number of spatial streams
@@ -946,7 +950,7 @@ struct iwl_tof_range_req_ap_entry_v8 {
* @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of
* the number of measurement iterations (min 2^0 = 1, max 2^14)
* @sta_id: the station id of the AP. Only relevant when associated to the AP,
- * otherwise should be set to &IWL_MVM_INVALID_STA.
+ * otherwise should be set to &IWL_INVALID_STA.
* @cipher: pairwise cipher suite for secured measurement.
* &enum iwl_location_cipher.
* @hltk: HLTK to be used for secured 11az measurement
@@ -961,10 +965,10 @@ struct iwl_tof_range_req_ap_entry_v8 {
* &IWL_INITIATOR_AP_FLAGS_TB or &IWL_INITIATOR_AP_FLAGS_NON_TB is set.
* @rx_pn: the next expected PN for protected management frames Rx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @tx_pn: the next PN to use for protected management frames Tx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @r2i_ndp_params: parameters for R2I NDP ranging negotiation.
* bits 0 - 2: max LTF repetitions
* bits 3 - 5: max number of spatial streams
@@ -1029,7 +1033,7 @@ struct iwl_tof_range_req_ap_entry_v9 {
* @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of
* the number of measurement iterations (min 2^0 = 1, max 2^14)
* @sta_id: the station id of the AP. Only relevant when associated to the AP,
- * otherwise should be set to &IWL_MVM_INVALID_STA.
+ * otherwise should be set to &IWL_INVALID_STA.
* @cipher: pairwise cipher suite for secured measurement.
* &enum iwl_location_cipher.
* @hltk: HLTK to be used for secured 11az measurement
@@ -1042,10 +1046,10 @@ struct iwl_tof_range_req_ap_entry_v9 {
* &IWL_INITIATOR_AP_FLAGS_TB is set.
* @rx_pn: the next expected PN for protected management frames Rx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @tx_pn: the next PN to use for protected management frames Tx. LE byte
* order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id
- * is set to &IWL_MVM_INVALID_STA.
+ * is set to &IWL_INVALID_STA.
* @r2i_ndp_params: parameters for R2I NDP ranging negotiation.
* bits 0 - 2: max LTF repetitions
* bits 3 - 5: max number of spatial streams
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index c46e24fc6a1e..b23d5fc4bbe6 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -382,6 +382,8 @@ struct iwl_mac_config_cmd {
* @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask.
* This flag can be set only if the MAC that this link relates to has
* eht_support set to true. No longer used since _VER_3 of this command.
+ * @LINK_CONTEXT_MODIFY_BANDWIDTH: Covers iwl_link_ctx_cfg_cmd::modify_bandwidth.
+ * Request RX OMI to the AP to modify bandwidth of this link.
* @LINK_CONTEXT_MODIFY_ALL: set all above flags
*/
enum iwl_link_ctx_modify_flags {
@@ -393,6 +395,7 @@ enum iwl_link_ctx_modify_flags {
LINK_CONTEXT_MODIFY_HE_PARAMS = BIT(5),
LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6),
LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7),
+ LINK_CONTEXT_MODIFY_BANDWIDTH = BIT(8),
LINK_CONTEXT_MODIFY_ALL = 0xff,
}; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */
@@ -434,6 +437,22 @@ enum iwl_link_ctx_flags {
}; /* LINK_CONTEXT_FLAG_E_VER_1 */
/**
+ * enum iwl_link_modify_bandwidth - link modify (RX OMI) bandwidth
+ * @IWL_LINK_MODIFY_BW_20: request 20 MHz
+ * @IWL_LINK_MODIFY_BW_40: request 40 MHz
+ * @IWL_LINK_MODIFY_BW_80: request 80 MHz
+ * @IWL_LINK_MODIFY_BW_160: request 160 MHz
+ * @IWL_LINK_MODIFY_BW_320: request 320 MHz
+ */
+enum iwl_link_modify_bandwidth {
+ IWL_LINK_MODIFY_BW_20,
+ IWL_LINK_MODIFY_BW_40,
+ IWL_LINK_MODIFY_BW_80,
+ IWL_LINK_MODIFY_BW_160,
+ IWL_LINK_MODIFY_BW_320,
+};
+
+/**
* struct iwl_link_config_cmd - command structure to configure the LINK context
* in MLD API
* ( LINK_CONFIG_CMD =0x9 )
@@ -457,6 +476,8 @@ enum iwl_link_ctx_flags {
* @block_tx: tell the firmware that this link can't Tx. This should be used
* only when a link is de-activated because of CSA with mode = 1.
* Available since version 5.
+ * @modify_bandwidth: bandwidth request value for RX OMI (see also
+ * %LINK_CONTEXT_MODIFY_BANDWIDTH), from &enum iwl_link_modify_bandwidth.
* @reserved1: in version 2, listen_lmac became reserved
* @cck_rates: basic rates available for CCK
* @ofdm_rates: basic rates available for OFDM
@@ -500,10 +521,11 @@ struct iwl_link_config_cmd {
__le32 modify_mask;
__le32 active;
union {
- __le32 listen_lmac;
+ __le32 listen_lmac; /* only _VER_1 */
struct {
- u8 block_tx;
- u8 reserved1[3];
+ u8 block_tx; /* since _VER_5 */
+ u8 modify_bandwidth; /* since _VER_6 */
+ u8 reserved1[2];
};
};
__le32 cck_rates;
@@ -524,7 +546,7 @@ struct iwl_link_config_cmd {
__le16 puncture_mask; /* removed in _VER_3 */
__le16 frame_time_rts_th;
__le32 flags;
- __le32 flags_mask;
+ __le32 flags_mask; /* removed in _VER_6 */
/* The below fields are for multi-bssid */
u8 ref_bssid_addr[6];
__le16 reserved_for_ref_bssid_addr;
@@ -535,7 +557,7 @@ struct iwl_link_config_cmd {
u8 ibss_bssid_addr[6];
__le16 reserved_for_ibss_bssid_addr;
__le32 reserved3[8];
-} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5 */
+} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6 */
/* Currently FW supports link ids in the range 0-3 and can have
* at most two active links for each vif.
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
index 977ca4ac166d..26301c0b06a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
@@ -17,7 +17,7 @@
#define NUM_MAC_INDEX_CDB (NUM_MAC_INDEX_DRIVER + 2)
#define IWL_STATION_COUNT_MAX 16
-#define IWL_MVM_INVALID_STA 0xFF
+#define IWL_INVALID_STA 0xFF
enum iwl_ac {
AC_BK,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 98d56e778d99..f4803b55adb9 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2019, 2021-2023 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2019, 2021-2024 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -327,18 +327,19 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt);
void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt,
u32 timepoint,
u32 timepoint_data);
+bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id);
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__)
+#define IWL_FW_CHECK_FAILED(_obj, ...) \
+ IWL_ERR_LIMIT(_obj, __VA_ARGS__)
#define IWL_FW_CHECK(_obj, _cond, _fmt, ...) \
({ \
bool __cond = (_cond); \
\
if (unlikely(__cond)) \
- IWL_FW_CHECK_FAILED(_obj, _fmt, __VA_ARGS__); \
+ IWL_FW_CHECK_FAILED(_obj, _fmt, ##__VA_ARGS__); \
\
unlikely(__cond); \
})
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
index 8f107ceec407..8e0c85a1240d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.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-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -530,3 +530,28 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
}
}
IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs);
+
+bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id)
+{
+ struct error_table_start {
+ /* cf. struct iwl_error_event_table */
+ u32 valid;
+ __le32 err_id;
+ } err_info = {};
+ int ret;
+
+ if (!base)
+ return false;
+
+ ret = iwl_trans_read_mem_bytes(trans, base,
+ &err_info, sizeof(err_info));
+
+ if (ret)
+ return true;
+
+ if (err_info.valid && err_id)
+ *err_id = le32_to_cpu(err_info.err_id);
+
+ return !!err_info.valid;
+}
+IWL_EXPORT_SYMBOL(iwl_fwrt_read_err_table);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c
index d8b083be5b6b..de87e0e3e072 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/init.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c
@@ -39,10 +39,12 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
+/* Assumes the appropriate lock is held by the caller */
void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)
{
iwl_fw_suspend_timestamp(fwrt);
- iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START, NULL);
+ iwl_dbg_tlv_time_point_sync(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START,
+ NULL);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 2abfc986701f..c620911a1193 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1413,25 +1413,35 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
const struct iwl_op_mode_ops *ops = op->ops;
struct dentry *dbgfs_dir = NULL;
struct iwl_op_mode *op_mode = NULL;
+ int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY;
/* also protects start/stop from racing against each other */
lockdep_assert_held(&iwlwifi_opmode_table_mtx);
+ for (retry = 0; retry <= max_retry; retry++) {
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
- drv->dbgfs_op_mode = debugfs_create_dir(op->name,
- drv->dbgfs_drv);
- dbgfs_dir = drv->dbgfs_op_mode;
+ drv->dbgfs_op_mode = debugfs_create_dir(op->name,
+ drv->dbgfs_drv);
+ dbgfs_dir = drv->dbgfs_op_mode;
#endif
- op_mode = ops->start(drv->trans, drv->trans->cfg,
- &drv->fw, dbgfs_dir);
- if (op_mode)
- return op_mode;
+ op_mode = ops->start(drv->trans, drv->trans->cfg,
+ &drv->fw, dbgfs_dir);
+
+ if (op_mode)
+ return op_mode;
+
+ if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status))
+ break;
+
+ IWL_ERR(drv, "retry init count %d\n", retry);
#ifdef CONFIG_IWLWIFI_DEBUGFS
- debugfs_remove_recursive(drv->dbgfs_op_mode);
- drv->dbgfs_op_mode = NULL;
+ debugfs_remove_recursive(drv->dbgfs_op_mode);
+ drv->dbgfs_op_mode = NULL;
#endif
+ }
return NULL;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
index 1549ff429549..6a1d31892417 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h
@@ -98,6 +98,9 @@ void iwl_drv_stop(struct iwl_drv *drv);
#define VISIBLE_IF_IWLWIFI_KUNIT static
#endif
+/* max retry for init flow */
+#define IWL_MAX_INIT_RETRY 2
+
#define FW_NAME_PRE_BUFSIZE 64
struct iwl_trans;
const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index e95ffe303547..c70da7281551 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -1074,12 +1074,13 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs,
void iwl_trans_debugfs_cleanup(struct iwl_trans *trans);
#endif
-#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \
- do { \
- if (__builtin_constant_p(bufsize)) \
- BUILD_BUG_ON((bufsize) % sizeof(u32)); \
- iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\
- } while (0)
+#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \
+ ({ \
+ if (__builtin_constant_p(bufsize)) \
+ BUILD_BUG_ON((bufsize) % sizeof(u32)); \
+ iwl_trans_read_mem(trans, addr, buf, \
+ (bufsize) / sizeof(u32)); \
+ })
int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr,
u64 src_addr, u32 byte_cnt);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
index b607961970e9..36726ea4b822 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
@@ -689,7 +689,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* Rssi update while not associated - can happen since the statistics
* are handled asynchronously
*/
- if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA)
+ if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA)
return;
/* No BT - reports should be disabled */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index ddf484027d4f..776600ddaea6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -17,7 +17,9 @@
#define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30
#define IWL_MVM_TPT_COUNT_WINDOW_SEC 5
#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5
-#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 11
+#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 15
+#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11
+#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH -72
#define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
#define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC)
@@ -57,7 +59,6 @@
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
#define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1
#define IWL_MVM_TOF_IS_RESPONDER 0
-#define IWL_MVM_HW_CSUM_DISABLE 0
#define IWL_MVM_ADWELL_ENABLE 1
#define IWL_MVM_ADWELL_MAX_BUDGET 0
#define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 49a6aff42376..f85c01e04ebf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -922,7 +922,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
static int
iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
struct cfg80211_wowlan *wowlan,
- struct iwl_wowlan_config_cmd *wowlan_config_cmd,
+ struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd,
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
struct ieee80211_sta *ap_sta)
{
@@ -948,7 +948,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret);
}
- iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7)
+ iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd);
if (wowlan->disconnect)
wowlan_config_cmd->wakeup_filter |=
@@ -1122,7 +1123,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
static int
iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
struct cfg80211_wowlan *wowlan,
- struct iwl_wowlan_config_cmd *wowlan_config_cmd,
+ struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd_v6,
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
struct iwl_mvm_vif_link_info *mvm_link,
struct ieee80211_sta *ap_sta)
@@ -1131,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
- mvm->offload_tid = wowlan_config_cmd->offloading_tid;
+ mvm->offload_tid = wowlan_config_cmd_v6->offloading_tid;
if (!unified_image) {
ret = iwl_mvm_switch_to_d3(mvm);
@@ -1147,9 +1148,26 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
if (ret)
return ret;
- ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
- sizeof(*wowlan_config_cmd),
- wowlan_config_cmd);
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) > 6) {
+ struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+ .wakeup_filter = wowlan_config_cmd_v6->wakeup_filter,
+ .wowlan_ba_teardown_tids =
+ wowlan_config_cmd_v6->wowlan_ba_teardown_tids,
+ .is_11n_connection =
+ wowlan_config_cmd_v6->is_11n_connection,
+ .offloading_tid = wowlan_config_cmd_v6->offloading_tid,
+ .flags = wowlan_config_cmd_v6->flags,
+ .sta_id = wowlan_config_cmd_v6->sta_id,
+ };
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
+ sizeof(wowlan_config_cmd),
+ &wowlan_config_cmd);
+ } else {
+ ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
+ sizeof(*wowlan_config_cmd_v6),
+ wowlan_config_cmd_v6);
+ }
if (ret)
return ret;
@@ -1288,7 +1306,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
goto out_noreset;
}
- if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) {
+ if (mvm_link->ap_sta_id == IWL_INVALID_STA) {
/* if we're not associated, this must be netdetect */
if (!wowlan->nd_config) {
ret = 1;
@@ -1302,7 +1320,7 @@ 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_v6 wowlan_config_cmd = {
.offloading_tid = 0,
};
@@ -1398,7 +1416,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
iwl_mvm_pause_tcm(mvm, true);
+ mutex_lock(&mvm->mutex);
iwl_fw_runtime_suspend(&mvm->fwrt);
+ mutex_unlock(&mvm->mutex);
return __iwl_mvm_suspend(hw, wowlan, false);
}
@@ -1423,6 +1443,7 @@ struct iwl_wowlan_status_data {
u16 non_qos_seq_ctr;
u16 qos_seq_ctr[8];
u8 tid_tear_down;
+ u8 tid_offloaded_tx;
struct {
/* including RX MIC key for TKIP */
@@ -2472,7 +2493,64 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,
static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
struct iwl_wowlan_info_notif *data,
struct iwl_wowlan_status_data *status,
- u32 len, bool has_mlo_keys)
+ u32 len)
+{
+ u32 expected_len = sizeof(*data) +
+ data->num_mlo_link_keys * sizeof(status->mlo_keys[0]);
+
+ if (!data) {
+ IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n");
+ status = NULL;
+ return;
+ }
+
+ if (len < expected_len) {
+ IWL_ERR(mvm, "Invalid WoWLAN info notification!\n");
+ status = NULL;
+ return;
+ }
+
+ if (mvm->fast_resume)
+ return;
+
+ iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);
+ iwl_mvm_convert_gtk_v3(status, data->gtk);
+ iwl_mvm_convert_igtk(status, &data->igtk[0]);
+ iwl_mvm_convert_bigtk(status, data->bigtk);
+ status->replay_ctr = le64_to_cpu(data->replay_ctr);
+ status->pattern_number = le16_to_cpu(data->pattern_number);
+ status->tid_offloaded_tx = data->tid_offloaded_tx;
+ if (IWL_FW_CHECK(mvm,
+ data->tid_offloaded_tx >=
+ ARRAY_SIZE(status->qos_seq_ctr),
+ "tid_offloaded_tx is out of bound %d\n",
+ data->tid_offloaded_tx))
+ data->tid_offloaded_tx = 0;
+ status->qos_seq_ctr[data->tid_offloaded_tx] =
+ le16_to_cpu(data->qos_seq_ctr);
+ status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons);
+ status->num_of_gtk_rekeys =
+ le32_to_cpu(data->num_of_gtk_rekeys);
+ status->received_beacons = le32_to_cpu(data->received_beacons);
+ status->tid_tear_down = data->tid_tear_down;
+
+ if (data->num_mlo_link_keys) {
+ status->num_mlo_keys = data->num_mlo_link_keys;
+ if (IWL_FW_CHECK(mvm,
+ status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS,
+ "Too many mlo keys: %d, max %d\n",
+ status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS))
+ status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS;
+ memcpy(status->mlo_keys, data->mlo_gtks,
+ status->num_mlo_keys * sizeof(status->mlo_keys[0]));
+ }
+}
+
+static void
+iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm,
+ struct iwl_wowlan_info_notif_v4 *data,
+ struct iwl_wowlan_status_data *status,
+ u32 len, bool has_mlo_keys)
{
u32 i;
u32 expected_len = sizeof(*data);
@@ -2744,6 +2822,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int link_id = vif->active_links ? __ffs(vif->active_links) : 0;
struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];
+ int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw,
+ PROT_OFFLOAD_GROUP,
+ WOWLAN_INFO_NOTIFICATION,
+ IWL_FW_CMD_VER_UNKNOWN);
if (WARN_ON(!mvm_link))
goto out_unlock;
@@ -2758,11 +2840,14 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
if (!mvm_ap_sta)
goto out_unlock;
- for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
- u16 seq = status->qos_seq_ctr[i];
- /* firmware stores last-used value, we store next value */
- seq += 0x10;
- mvm_ap_sta->tid_data[i].seq_number = seq;
+ /* firmware stores last-used value, we store next value */
+ if (wowlan_info_ver >= 5) {
+ mvm_ap_sta->tid_data[status->tid_offloaded_tx].seq_number =
+ status->qos_seq_ctr[status->tid_offloaded_tx] + 0x10;
+ } else {
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++)
+ mvm_ap_sta->tid_data[i].seq_number =
+ status->qos_seq_ctr[i] + 0x10;
}
if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
@@ -3024,34 +3109,15 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
ieee80211_resume_disconnect(vif);
}
-static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id)
-{
- struct error_table_start {
- /* cf. struct iwl_error_event_table */
- u32 valid;
- __le32 err_id;
- } err_info;
-
- if (!base)
- return false;
-
- iwl_trans_read_mem_bytes(trans, base,
- &err_info, sizeof(err_info));
- if (err_info.valid && err_id)
- *err_id = le32_to_cpu(err_info.err_id);
-
- return !!err_info.valid;
-}
-
static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
u32 err_id;
/* check for lmac1 error */
- if (iwl_mvm_rt_status(mvm->trans,
- mvm->trans->dbg.lmac_error_event_table[0],
- &err_id)) {
+ if (iwl_fwrt_read_err_table(mvm->trans,
+ mvm->trans->dbg.lmac_error_event_table[0],
+ &err_id)) {
if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {
struct cfg80211_wowlan_wakeup wakeup = {
.rfkill_release = true,
@@ -3063,13 +3129,15 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
}
/* check if we have lmac2 set and check for error */
- if (iwl_mvm_rt_status(mvm->trans,
- mvm->trans->dbg.lmac_error_event_table[1], NULL))
+ if (iwl_fwrt_read_err_table(mvm->trans,
+ mvm->trans->dbg.lmac_error_event_table[1],
+ NULL))
return true;
/* check for umac error */
- if (iwl_mvm_rt_status(mvm->trans,
- mvm->trans->dbg.umac_error_event_table, NULL))
+ if (iwl_fwrt_read_err_table(mvm->trans,
+ mvm->trans->dbg.umac_error_event_table,
+ NULL))
return true;
return false;
@@ -3090,7 +3158,7 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,
/* if FW uses status notification, status shouldn't be NULL here */
if (!d3_data->status) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA :
+ u8 sta_id = mvm->net_detect ? IWL_INVALID_STA :
mvmvif->deflink.ap_sta_id;
/* bug - FW with MLO has status notification */
@@ -3262,13 +3330,19 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2,
d3_data->status,
len);
+ } else if (wowlan_info_ver < 5) {
+ struct iwl_wowlan_info_notif_v4 *notif =
+ (void *)pkt->data;
+
+ iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif,
+ d3_data->status, len,
+ wowlan_info_ver > 3);
} else {
struct iwl_wowlan_info_notif *notif =
(void *)pkt->data;
iwl_mvm_parse_wowlan_info_notif(mvm, notif,
- d3_data->status, len,
- wowlan_info_ver > 3);
+ d3_data->status, len);
}
d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;
@@ -3610,8 +3684,6 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm)
IWL_ERR(mvm,
"fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret);
- WARN_ON(iwl_mvm_power_update_mac(mvm));
-
ret = iwl_trans_d3_suspend(mvm->trans, false, false);
if (ret)
IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret);
@@ -3633,22 +3705,31 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt);
if (iwl_mvm_check_rt_status(mvm, NULL)) {
+ IWL_ERR(mvm,
+ "iwl_mvm_check_rt_status failed, device is gone during suspend\n");
set_bit(STATUS_FW_ERROR, &mvm->trans->status);
iwl_mvm_dump_nic_error_log(mvm);
iwl_dbg_tlv_time_point(&mvm->fwrt,
IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
false, 0);
- return -ENODEV;
+ mvm->trans->state = IWL_TRANS_NO_FW;
+ ret = -ENODEV;
+
+ goto out;
}
ret = iwl_mvm_d3_notif_wait(mvm, &d3_data);
+
+ if (ret) {
+ IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret);
+ mvm->trans->state = IWL_TRANS_NO_FW;
+ }
+
+out:
clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
mvm->fast_resume = false;
- if (ret)
- IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret);
-
return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 25f07e00db42..fbe4e4a50852 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -221,7 +221,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
mvmvif->deflink.queue_params[i].uapsd);
if (vif->type == NL80211_IFTYPE_STATION &&
- ap_sta_id != IWL_MVM_INVALID_STA) {
+ ap_sta_id != IWL_INVALID_STA) {
struct iwl_mvm_sta *mvm_sta;
mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
@@ -463,11 +463,13 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
-static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+iwl_dbgfs_low_latency_write_handle(struct wiphy *wiphy, struct file *file,
+ char *buf, size_t count, void *data)
{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct ieee80211_vif *vif = data;
u8 value;
int ret;
@@ -484,12 +486,28 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
return count;
}
-static ssize_t
-iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,
- size_t count, loff_t *ppos)
+static ssize_t iwl_dbgfs_low_latency_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
+ struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
+ char buf[10] = {};
+
+ return wiphy_locked_debugfs_write(mvm->hw->wiphy, file,
+ buf, sizeof(buf), user_buf, count,
+ iwl_dbgfs_low_latency_write_handle,
+ vif);
+}
+
+static ssize_t
+iwl_dbgfs_low_latency_force_write_handle(struct wiphy *wiphy, struct file *file,
+ char *buf, size_t count, void *data)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct ieee80211_vif *vif = data;
u8 value;
int ret;
@@ -517,6 +535,22 @@ iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,
return count;
}
+static ssize_t
+iwl_dbgfs_low_latency_force_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ char buf[10] = {};
+
+ return wiphy_locked_debugfs_write(mvm->hw->wiphy, file,
+ buf, sizeof(buf), user_buf, count,
+ iwl_dbgfs_low_latency_force_write_handle,
+ vif);
+}
+
static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -831,8 +865,20 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
-MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10);
+
+static const struct file_operations iwl_dbgfs_low_latency_ops = {
+ .write = iwl_dbgfs_low_latency_write,
+ .read = iwl_dbgfs_low_latency_read,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+static const struct file_operations iwl_dbgfs_low_latency_force_ops = {
+ .write = iwl_dbgfs_low_latency_force_write,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index 55245f913286..b26141c30c61 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -559,12 +559,12 @@ static int iwl_mvm_ftm_set_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->ftm_unprotected) {
- *sta_id = IWL_MVM_INVALID_STA;
+ *sta_id = IWL_INVALID_STA;
*flags &= ~cpu_to_le32(IWL_INITIATOR_AP_FLAGS_PMF);
}
#endif
} else {
- *sta_id = IWL_MVM_INVALID_STA;
+ *sta_id = IWL_INVALID_STA;
}
return 0;
@@ -1063,6 +1063,8 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_FW_CMD_VER_UNKNOWN);
switch (cmd_ver) {
+ case 15:
+ /* Version 15 has the same struct as 14 */
case 14:
err = iwl_mvm_ftm_start_v14(mvm, vif, req);
break;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
index e4caa362f597..e6e468e81ab3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
@@ -131,7 +131,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- if (cmd_ver == 10) {
+ if (cmd_ver >= 10) {
cmd.band =
iwl_mvm_phy_band_from_nl80211(chandef->chan->band);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 08546e673cf5..5ea684802ad1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1307,8 +1307,8 @@ static void iwl_mvm_disconnect_iterator(void *data, u8 *mac,
void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
{
u32 error_log_size = mvm->fw->ucode_capa.error_log_size;
+ u32 status = 0;
int ret;
- u32 resp;
struct iwl_fw_error_recovery_cmd recovery_cmd = {
.flags = cpu_to_le32(flags),
@@ -1316,7 +1316,6 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
};
struct iwl_host_cmd host_cmd = {
.id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD),
- .flags = CMD_WANT_SKB,
.data = {&recovery_cmd, },
.len = {sizeof(recovery_cmd), },
};
@@ -1336,7 +1335,7 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
recovery_cmd.buf_size = cpu_to_le32(error_log_size);
}
- ret = iwl_mvm_send_cmd(mvm, &host_cmd);
+ ret = iwl_mvm_send_cmd_status(mvm, &host_cmd, &status);
kfree(mvm->error_recovery_buf);
mvm->error_recovery_buf = NULL;
@@ -1347,11 +1346,10 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
/* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */
if (flags & ERROR_RECOVERY_UPDATE_DB) {
- resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data);
- if (resp) {
+ if (status) {
IWL_ERR(mvm,
"Failed to send recovery cmd blob was invalid %d\n",
- resp);
+ status);
ieee80211_iterate_interfaces(mvm->hw, 0,
iwl_mvm_disconnect_iterator,
@@ -1403,6 +1401,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
int ret, i;
struct ieee80211_supported_band *sband = NULL;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
lockdep_assert_held(&mvm->mutex);
ret = iwl_trans_start_hw(mvm->trans);
@@ -1486,7 +1485,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
for (i = 0; i < IWL_FW_MAX_LINK_ID + 1; i++)
RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL);
- mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
+ mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;
/* reset quota debouncing buffer - 0xff will yield invalid data */
memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
@@ -1622,6 +1621,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
{
int ret, i;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
lockdep_assert_held(&mvm->mutex);
ret = iwl_trans_start_hw(mvm->trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 2b0652168002..272da41567ef 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -12,6 +12,7 @@
HOW(BLOCKED_FW) \
HOW(BLOCKED_NON_BSS) \
HOW(BLOCKED_ROC) \
+ HOW(BLOCKED_TMP_NON_BSS) \
HOW(EXIT_MISSED_BEACON) \
HOW(EXIT_LOW_RSSI) \
HOW(EXIT_COEX) \
@@ -360,7 +361,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
send_cmd:
cmd.modify_mask = cpu_to_le32(changes);
cmd.flags = cpu_to_le32(flags);
- cmd.flags_mask = cpu_to_le32(flags_mask);
+ if (cmd_ver < 6)
+ cmd.flags_mask = cpu_to_le32(flags_mask);
cmd.spec_link_id = link_conf->link_id;
if (cmd_ver < 2)
cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
@@ -1165,3 +1167,14 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (!mvmvif->esr_disable_reason)
iwl_mvm_esr_unblocked(mvm, vif);
}
+
+void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link)
+{
+ link->bcast_sta.sta_id = IWL_INVALID_STA;
+ link->mcast_sta.sta_id = IWL_INVALID_STA;
+ link->ap_sta_id = IWL_INVALID_STA;
+
+ for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++)
+ link->smps_requests[r] =
+ IEEE80211_SMPS_AUTOMATIC;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index a7a10e716e65..2a13d70da46c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -216,7 +216,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
.preferred_tsf = NUM_TSF_IDS,
.found_vif = false,
};
- int ret, i;
+ int ret;
lockdep_assert_held(&mvm->mutex);
@@ -298,9 +298,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->time_event_data.id = TE_MAX;
mvmvif->roc_activity = ROC_NUM_ACTIVITIES;
- mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA;
- mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA;
- mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
+ iwl_mvm_init_link(&mvmvif->deflink);
/* No need to allocate data queues to P2P Device MAC and NAN.*/
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
@@ -316,9 +314,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
}
- for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++)
- mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC;
-
return 0;
exit_fail:
@@ -1605,6 +1600,7 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm,
0);
u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
MISSED_BEACONS_NOTIF, 0);
+ struct ieee80211_bss_conf *bss_conf;
/* If the firmware uses the new notification (from MAC_CONF_GROUP),
* refer to that notification's version.
@@ -1617,9 +1613,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm,
/* before version four the ID in the notification refers to mac ID */
if (notif_ver < 4) {
vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false);
+ bss_conf = &vif->bss_conf;
} else {
- struct ieee80211_bss_conf *bss_conf =
- iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false);
+ bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false);
if (!bss_conf)
return;
@@ -1664,6 +1660,8 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm,
rx_missed_bcon, rx_missed_bcon_since_rx);
}
} else if (link_id >= 0 && hweight16(vif->active_links) > 1) {
+ u32 bss_param_ch_cnt_link_id =
+ bss_conf->bss_param_ch_cnt_link_id;
u32 scnd_lnk_bcn_lost = 0;
if (notif_ver >= 5 &&
@@ -1677,10 +1675,14 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm,
/* Exit EMLSR if we lost more than
* IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links
* OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link.
+ * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED
+ * and the link's bss_param_ch_count has changed.
*/
if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS &&
scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) ||
- rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH)
+ rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH ||
+ (bss_param_ch_cnt_link_id != link_id &&
+ rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED))
iwl_mvm_exit_esr(mvm, vif,
IWL_MVM_ESR_EXIT_MISSED_BEACON,
iwl_mvm_get_primary_link(vif));
@@ -1689,6 +1691,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm,
ieee80211_beacon_loss(vif);
else
ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC);
+
+ /* try to switch links, no-op if we don't have MLO */
+ iwl_mvm_int_mlo_scan(mvm, vif);
}
iwl_dbg_tlv_time_point(&mvm->fwrt,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index a327893c6dce..07778d55878b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1109,7 +1109,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;
for_each_mvm_vif_valid_link(mvmvif, link_id) {
- mvmvif->link[link_id]->ap_sta_id = IWL_MVM_INVALID_STA;
+ mvmvif->link[link_id]->ap_sta_id = IWL_INVALID_STA;
mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
mvmvif->link[link_id]->phy_ctxt = NULL;
mvmvif->link[link_id]->active = 0;
@@ -1237,6 +1237,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
fast_resume = mvm->fast_resume;
if (fast_resume) {
+ iwl_mvm_mei_device_state(mvm, true);
ret = iwl_mvm_fast_resume(mvm);
if (ret) {
iwl_mvm_stop_device(mvm);
@@ -1293,12 +1294,14 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
+ int retry, max_retry = 0;
mutex_lock(&mvm->mutex);
/* we are starting the mac not in error flow, and restart is enabled */
if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) &&
iwlwifi_mod_params.fw_restart) {
+ max_retry = IWL_MAX_INIT_RETRY;
/*
* This will prevent mac80211 recovery flows to trigger during
* init failures
@@ -1306,7 +1309,13 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw)
set_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
}
- ret = __iwl_mvm_mac_start(mvm);
+ for (retry = 0; retry <= max_retry; retry++) {
+ ret = __iwl_mvm_mac_start(mvm);
+ if (!ret)
+ break;
+
+ IWL_ERR(mvm, "mac start retry %d\n", retry);
+ }
clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
mutex_unlock(&mvm->mutex);
@@ -1336,6 +1345,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
* of packets the FW sent out, so we must reconnect.
*/
iwl_mvm_teardown_tdls_peers(mvm);
+
+ IWL_INFO(mvm, "restart completed\n");
}
void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
@@ -1369,10 +1380,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend)
iwl_mvm_rm_aux_sta(mvm);
if (suspend &&
- mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
+ mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
iwl_mvm_fast_suspend(mvm);
- else
+ /* From this point on, we won't touch the device */
+ iwl_mvm_mei_device_state(mvm, false);
+ } else {
iwl_mvm_stop_device(mvm);
+ }
iwl_mvm_async_handlers_purge(mvm);
/* async_handlers_list is empty and will stay empty: HW is stopped */
@@ -1466,15 +1480,16 @@ struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
return NULL;
}
-int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+int iwl_mvm_set_tx_power(struct iwl_mvm *mvm,
+ struct ieee80211_bss_conf *link_conf,
s16 tx_power)
{
u32 cmd_id = REDUCE_TX_POWER_CMD;
+ u32 mac_id = iwl_mvm_vif_from_mac80211(link_conf->vif)->id;
int len;
struct iwl_dev_tx_power_cmd_v3_v8 cmd = {
.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
- .common.mac_context_id =
- cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
+ .common.mac_context_id = cpu_to_le32(mac_id),
};
struct iwl_dev_tx_power_cmd cmd_v9_v10;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3);
@@ -1487,8 +1502,7 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (cmd_ver > 8) {
/* Those fields sit on the same place for v9 and v10 */
cmd_v9_v10.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC);
- cmd_v9_v10.common.mac_context_id =
- cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id);
+ cmd_v9_v10.common.mac_context_id = cpu_to_le32(mac_id);
cmd_v9_v10.common.pwr_restriction = cpu_to_le16(u_tx_power);
cmd_data = &cmd_v9_v10;
}
@@ -1731,6 +1745,21 @@ static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk)
iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT);
}
+static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy,
+ struct wiphy_work *wk)
+{
+ struct iwl_mvm_vif *mvmvif =
+ container_of(wk, struct iwl_mvm_vif,
+ unblock_esr_tmp_non_bss_wk.work);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ struct ieee80211_vif *vif =
+ container_of((void *)mvmvif, struct ieee80211_vif, drv_priv);
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS);
+ mutex_unlock(&mvm->mutex);
+}
+
void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
{
lockdep_assert_held(&mvm->mutex);
@@ -1749,6 +1778,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif)
wiphy_work_init(&mvmvif->unblock_esr_tpt_wk,
iwl_mvm_unblock_esr_tpt);
+
+ wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk,
+ iwl_mvm_unblock_esr_tmp_non_bss);
}
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
@@ -1899,6 +1931,8 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
&mvmvif->mlo_int_scan_wk);
wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk);
+ wiphy_delayed_work_cancel(mvm->hw->wiphy,
+ &mvmvif->unblock_esr_tmp_non_bss_wk);
cancel_delayed_work_sync(&mvmvif->csa_work);
}
@@ -1970,7 +2004,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvm->p2p_device_vif = NULL;
}
- iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);
iwl_mvm_mac_ctxt_remove(mvm, vif);
RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);
@@ -1979,6 +2012,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvm->monitor_on = false;
out:
+ iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->deflink.mcast_sta);
@@ -2921,7 +2955,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_MVM_SMPS_REQ_PROT,
IEEE80211_SMPS_DYNAMIC, 0);
}
- } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
+ } else if (mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {
iwl_mvm_mei_host_disassociated(mvm);
/*
* If update fails - SF might be running in associated
@@ -2957,7 +2991,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm,
"failed to remove AP station\n");
- mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
+ mvmvif->deflink.ap_sta_id = IWL_INVALID_STA;
}
/* remove quota for this interface */
@@ -3303,7 +3337,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_TXPOWER) {
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",
bss_conf->txpower);
- iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
+ iwl_mvm_set_tx_power(mvm, bss_conf, bss_conf->txpower);
}
}
@@ -3414,7 +3448,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
*/
break;
case STA_NOTIFY_AWAKE:
- if (WARN_ON(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON(mvmsta->deflink.sta_id == IWL_INVALID_STA))
break;
if (txqs)
@@ -3494,6 +3528,8 @@ void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
unsigned int link_id;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
+
/*
* This is called before mac80211 does RCU synchronisation,
* so here we already invalidate our internal RCU-protected
@@ -4075,6 +4111,8 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
&mvmvif->mlo_int_scan_wk);
wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk);
+ wiphy_delayed_work_cancel(mvm->hw->wiphy,
+ &mvmvif->unblock_esr_tmp_non_bss_wk);
/* No need for the periodic statistics anymore */
if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active)
@@ -4236,8 +4274,9 @@ int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
}
void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, u32 changed)
+ struct ieee80211_link_sta *link_sta, u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (changed & (IEEE80211_RC_BW_CHANGED |
@@ -5067,7 +5106,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
(changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
IEEE80211_CHANCTX_CHANGE_RADAR |
- IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)),
+ IEEE80211_CHANCTX_CHANGE_MIN_DEF)),
"Cannot change PHY. Ref=%d, changed=0x%X\n",
phy_ctxt->ref, changed))
return;
@@ -5075,7 +5114,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
guard(mvm)(mvm);
/* we are only changing the min_width, may be a noop */
- if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) {
+ if (changed == IEEE80211_CHANCTX_CHANGE_MIN_DEF) {
if (phy_ctxt->width == def->width)
return;
@@ -6562,7 +6601,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
- .sta_rc_update = iwl_mvm_sta_rc_update,
+ .link_sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mac_conf_tx,
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 455f5f417506..ef0be44207e1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -396,7 +396,7 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
- link->ap_sta_id == IWL_MVM_INVALID_STA))
+ link->ap_sta_id == IWL_INVALID_STA))
return;
if (!sec_key_ver)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index f2378e0fb2fb..b807046144c0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -41,8 +41,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
/* reset deflink MLO parameters */
mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
mvmvif->deflink.active = 0;
- /* the first link always points to the default one */
- mvmvif->link[0] = &mvmvif->deflink;
ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
if (ret)
@@ -60,9 +58,19 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
}
- ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
- if (ret)
- goto out_free_bf;
+ /* We want link[0] to point to the default link, unless we have MLO and
+ * in this case this will be modified later by .change_vif_links()
+ * If we are in the restart flow with an MLD connection, we will wait
+ * to .change_vif_links() to setup the links.
+ */
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+ !ieee80211_vif_is_mld(vif)) {
+ mvmvif->link[0] = &mvmvif->deflink;
+
+ ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
+ if (ret)
+ goto out_free_bf;
+ }
/* Save a pointer to p2p device vif, so it can later be used to
* update the p2p device MAC when a GO is started/stopped
@@ -331,23 +339,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
if (ret)
goto out;
- /* Initialize rate control for the AP station, since we might be
- * doing a link switch here - we cannot initialize it before since
- * this needs the phy context assigned (and in FW?), and we cannot
- * do it later because it needs to be initialized as soon as we're
- * able to TX on the link, i.e. when active.
+ /*
+ * if link switching (link not active yet) we'll activate it in
+ * firmware later on link-info change, which mac80211 guarantees
+ * for link switch after the stations are set up
*/
- if (mvmvif->ap_sta) {
- struct ieee80211_link_sta *link_sta;
-
- rcu_read_lock();
- link_sta = rcu_dereference(mvmvif->ap_sta->link[link_id]);
-
- if (!WARN_ON_ONCE(!link_sta))
- iwl_mvm_rs_rate_init(mvm, vif, mvmvif->ap_sta,
- link_conf, link_sta,
- phy_ctxt->channel->band);
- rcu_read_unlock();
+ if (ieee80211_vif_link_active(vif, link_conf->link_id)) {
+ ret = iwl_mvm_link_changed(mvm, vif, link_conf,
+ LINK_CONTEXT_MODIFY_ACTIVE |
+ LINK_CONTEXT_MODIFY_RATES_INFO,
+ true);
+ if (ret)
+ goto out;
}
if (vif->type == NL80211_IFTYPE_STATION)
@@ -355,14 +358,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
link_conf,
false);
- /* then activate */
- ret = iwl_mvm_link_changed(mvm, vif, link_conf,
- LINK_CONTEXT_MODIFY_ACTIVE |
- LINK_CONTEXT_MODIFY_RATES_INFO,
- true);
- if (ret)
- goto out;
-
/*
* Power state must be updated before quotas,
* otherwise fw will complain.
@@ -775,6 +770,11 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id]))
return;
+ /* not yet marked active in vif means during link switch */
+ if (!ieee80211_vif_link_active(vif, link_conf->link_id) &&
+ vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt)
+ link_changes |= LINK_CONTEXT_MODIFY_ACTIVE;
+
has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;
has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be;
@@ -824,7 +824,7 @@ static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif)
int i;
for_each_mvm_vif_valid_link(mvmvif, i) {
- if (mvmvif->link[i]->ap_sta_id != IWL_MVM_INVALID_STA)
+ if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA)
return true;
}
@@ -851,7 +851,7 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm,
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");
- link->ap_sta_id = IWL_MVM_INVALID_STA;
+ link->ap_sta_id = IWL_INVALID_STA;
}
}
@@ -1038,7 +1038,7 @@ static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_TXPOWER) {
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n",
link_conf->txpower);
- iwl_mvm_set_tx_power(mvm, vif, link_conf->txpower);
+ iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower);
}
}
@@ -1169,8 +1169,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
int err, i;
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- int r;
-
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
break;
@@ -1182,19 +1180,17 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
goto free;
}
- new_link[i]->bcast_sta.sta_id = IWL_MVM_INVALID_STA;
- new_link[i]->mcast_sta.sta_id = IWL_MVM_INVALID_STA;
- new_link[i]->ap_sta_id = IWL_MVM_INVALID_STA;
new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
-
- for (r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++)
- new_link[i]->smps_requests[r] =
- IEEE80211_SMPS_AUTOMATIC;
+ iwl_mvm_init_link(new_link[i]);
}
mutex_lock(&mvm->mutex);
- if (old_links == 0) {
+ /* If we're in RESTART flow, the default link wasn't added in
+ * drv_add_interface(), and link[0] doesn't point to it.
+ */
+ if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status)) {
err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
if (err)
goto out_err;
@@ -1376,6 +1372,36 @@ iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw,
return ret;
}
+#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ)
+
+static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
+ struct iwl_mvm_vif *mvmvif;
+ int ret;
+
+ IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n",
+ type);
+
+ if (IS_ERR_OR_NULL(bss_vif) ||
+ !(type == NL80211_IFTYPE_AP ||
+ type == NL80211_IFTYPE_P2P_GO ||
+ type == NL80211_IFTYPE_P2P_CLIENT))
+ return;
+
+ mvmvif = iwl_mvm_vif_from_mac80211(bss_vif);
+ ret = iwl_mvm_block_esr_sync(mvm, bss_vif,
+ IWL_MVM_ESR_BLOCKED_TMP_NON_BSS);
+ if (ret)
+ return;
+
+ wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy,
+ &mvmvif->unblock_esr_tmp_non_bss_wk,
+ IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT);
+}
+
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.tx = iwl_mvm_mac_tx,
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
@@ -1401,7 +1427,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
.release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
- .sta_rc_update = iwl_mvm_sta_rc_update,
+ .link_sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mld_mac_conf_tx,
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
@@ -1472,4 +1498,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.change_sta_links = iwl_mvm_mld_change_sta_links,
.can_activate_links = iwl_mvm_mld_can_activate_links,
.can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm,
+ .prep_add_interface = iwl_mvm_mld_prep_add_interface,
};
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 28a9d90ad1cd..019839604011 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -146,7 +146,7 @@ int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout :
mvm->trans->trans_cfg->base_params->wd_timeout;
- if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA))
return -ENOSPC;
if (sta->type == STATION_TYPE_AUX)
@@ -346,7 +346,7 @@ static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON_ONCE(int_sta->sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(int_sta->sta_id == IWL_INVALID_STA))
return -EINVAL;
if (flush)
@@ -521,6 +521,9 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
unsigned int link_id,
bool is_in_fw)
{
+ lockdep_assert_wiphy(mvm->hw->wiphy);
+ lockdep_assert_held(&mvm->mutex);
+
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id],
is_in_fw ? ERR_PTR(-EINVAL) : NULL);
RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);
@@ -559,7 +562,10 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
u32 sta_id = iwl_mvm_find_free_sta_id(mvm,
ieee80211_vif_type_p2p(vif));
- if (sta_id == IWL_MVM_INVALID_STA)
+ lockdep_assert_wiphy(mvm->hw->wiphy);
+ lockdep_assert_held(&mvm->mutex);
+
+ if (sta_id == IWL_INVALID_STA)
return -ENOSPC;
if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) {
@@ -612,10 +618,10 @@ static void iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta *sta,
struct iwl_mvm_link_sta *sta_link)
{
if (!sta->tdls) {
- WARN_ON(vif_link->ap_sta_id != IWL_MVM_INVALID_STA);
+ WARN_ON(vif_link->ap_sta_id != IWL_INVALID_STA);
vif_link->ap_sta_id = sta_link->sta_id;
} else {
- WARN_ON(vif_link->ap_sta_id == IWL_MVM_INVALID_STA);
+ WARN_ON(vif_link->ap_sta_id == IWL_INVALID_STA);
}
}
@@ -631,6 +637,9 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,
int ret = -EINVAL;
int sta_id;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
+ lockdep_assert_held(&mvm->mutex);
+
/* First add an empty station since allocating a queue requires
* a valid station. Since we need a link_id to allocate a station,
* pick up the first valid one.
@@ -686,7 +695,7 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
spin_lock_init(&mvm_sta->lock);
- ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA,
+ ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_INVALID_STA,
STATION_TYPE_PEER);
} else {
ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta);
@@ -858,9 +867,10 @@ int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id)
{
int ret;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON(sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON(sta_id == IWL_INVALID_STA))
return 0;
ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id);
@@ -1064,6 +1074,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
unsigned int link_id;
int ret;
+ lockdep_assert_wiphy(mvm->hw->wiphy);
lockdep_assert_held(&mvm->mutex);
for_each_set_bit(link_id, &old_links_long,
@@ -1109,7 +1120,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
goto err;
if (vif->type == NL80211_IFTYPE_STATION)
- mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA;
+ mvm_vif_link->ap_sta_id = IWL_INVALID_STA;
iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id,
false);
@@ -1182,6 +1193,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
link_sta_added_to_fw |= BIT(link_id);
iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link);
+
+ iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta,
+ link_conf->chanreq.oper.chan->band);
}
if (sta_mask_added) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index ef07cff203b0..2ad615293c75 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -361,6 +361,9 @@ struct iwl_mvm_vif_link_info {
* @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is
* preventing EMLSR
* @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR
+ * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link
+ * is preventing EMLSR. This is a temporary blocking that is set when there
+ * is an indication that a non-BSS interface is to be added.
* @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons
* @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR
* due to low RSSI.
@@ -379,6 +382,7 @@ enum iwl_mvm_esr_state {
IWL_MVM_ESR_BLOCKED_FW = 0x8,
IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10,
IWL_MVM_ESR_BLOCKED_ROC = 0x20,
+ IWL_MVM_ESR_BLOCKED_TMP_NON_BSS = 0x40,
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
IWL_MVM_ESR_EXIT_COEX = 0x40000,
@@ -452,6 +456,8 @@ struct iwl_mvm_esr_exit {
* @prevent_esr_done_wk: work that should be done when esr prevention ends.
* @mlo_int_scan_wk: work for the internal MLO scan.
* @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough.
+ * @unblock_esr_tmp_non_bss_wk: work for removing the
+ * IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR.
* @roc_activity: currently running ROC activity for this vif (or
* ROC_NUM_ACTIVITIES if no activity is running).
* @session_prot_connection_loss: the connection was lost due to session
@@ -588,6 +594,7 @@ struct iwl_mvm_vif {
struct wiphy_delayed_work prevent_esr_done_wk;
struct wiphy_delayed_work mlo_int_scan_wk;
struct wiphy_work unblock_esr_tpt_wk;
+ struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk;
struct iwl_mvm_vif_link_info deflink;
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -773,7 +780,6 @@ struct iwl_mvm_tcm {
* @head_sn: reorder window head sn
* @num_stored: number of mpdus stored in the buffer
* @queue: queue of this reorder buffer
- * @last_amsdu: track last ASMDU SN for duplication detection
* @valid: reordering is valid for this queue
* @lock: protect reorder buffer internal state
*/
@@ -781,7 +787,6 @@ struct iwl_mvm_reorder_buffer {
u16 head_sn;
u16 num_stored;
int queue;
- u16 last_amsdu;
bool valid;
spinlock_t lock;
} ____cacheline_aligned_in_smp;
@@ -1077,6 +1082,7 @@ struct iwl_mvm {
/* data related to data path */
struct iwl_rx_phy_info last_phy_info;
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_STATION_COUNT_MAX];
+ /* note: fw_id_to_link_sta must be protected by wiphy and mvm mutexes */
struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];
u8 rx_ba_sessions;
@@ -1584,8 +1590,7 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm)
static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm)
{
return fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) &&
- !IWL_MVM_HW_CSUM_DISABLE;
+ IWL_UCODE_TLV_CAPA_CSUM_SUPPORT);
}
static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
@@ -2100,6 +2105,7 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band);
/* Links */
+void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link);
int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -2327,7 +2333,7 @@ static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm)
}
#endif
void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
- struct iwl_wowlan_config_cmd *cmd);
+ struct iwl_wowlan_config_cmd_v6 *cmd);
int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
bool disable_offloading,
@@ -2914,7 +2920,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
bool more_data);
int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, u32 changed);
+ struct ieee80211_link_sta *link_sta, u32 changed);
void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_prep_tx_info *info);
@@ -2982,7 +2988,8 @@ void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1,
struct iwl_mvm_vif *vif2);
bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif);
-int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+int iwl_mvm_set_tx_power(struct iwl_mvm *mvm,
+ struct ieee80211_bss_conf *bss_conf,
s16 tx_power);
int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
index 1eb21fe861e5..15d4369678a2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
@@ -10,7 +10,7 @@
#include "mvm.h"
void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
- struct iwl_wowlan_config_cmd *cmd)
+ struct iwl_wowlan_config_cmd_v6 *cmd)
{
int i;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 4dd4a9d5c71f..e25d7570ffab 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1505,8 +1505,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->scan_cmd_size = scan_size;
/* invalidate ids to prevent accidental removal of sta_id 0 */
- mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA;
- mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA;
+ mvm->aux_sta.sta_id = IWL_INVALID_STA;
+ mvm->snif_sta.sta_id = IWL_INVALID_STA;
/* Set EBS as successful as long as not stated otherwise by the FW. */
mvm->last_ebs_successful = true;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 05715e5af6ab..de5ac000272e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -440,12 +440,6 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (!mvmsta) {
- IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
- notif->sta_id);
- goto out;
- }
-
flags = le32_to_cpu(notif->flags);
mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]);
@@ -615,11 +609,8 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,
int cmd_ver;
int ret;
- /* Enable external EHT LTF only for GL device and if there's
- * mutual support by AP and client
- */
- if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL &&
- sband_eht_cap &&
+ /* Enable extra EHT LTF if there's mutual support by AP and client */
+ if (sband_eht_cap &&
sband_eht_cap->eht_cap_elem.phy_cap_info[5] &
IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF &&
link_sta->eht_cap.has_eht &&
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 1a0b5f8d4339..9e72db9bab40 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -560,7 +560,8 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,
struct iwl_mvm_vif_link_info *link_info,
struct ieee80211_bss_conf *bss_conf)
{
- struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
int thold = bss_conf->cqm_rssi_thold;
int hyst = bss_conf->cqm_rssi_hyst;
int last_event;
@@ -625,6 +626,13 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig,
if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
return;
+ /* We're not in EMLSR and our signal is bad, try to switch link maybe */
+ if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) {
+ iwl_mvm_int_mlo_scan(mvm, vif);
+ return;
+ }
+
+ /* We are in EMLSR, check if we need to exit */
exit_esr_thresh =
iwl_mvm_get_esr_rssi_thresh(mvm,
&bss_conf->chanreq.oper,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 65f8933c34b4..a2f16bfaec44 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -773,9 +773,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
return false;
}
- rcu_read_lock();
sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1);
- rcu_read_unlock();
if (IWL_FW_CHECK(mvm,
tid != baid_data->tid ||
@@ -814,7 +812,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
if (!amsdu || last_subframe)
buffer->head_sn = nssn;
- /* No need to update AMSDU last SN - we are moving the head */
+
spin_unlock_bh(&buffer->lock);
return false;
}
@@ -831,7 +829,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
if (!amsdu || last_subframe)
buffer->head_sn = ieee80211_sn_inc(buffer->head_sn);
- /* No need to update AMSDU last SN - we are moving the head */
spin_unlock_bh(&buffer->lock);
return false;
}
@@ -841,9 +838,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
__skb_queue_tail(&entries[index].frames, skb);
buffer->num_stored++;
- if (amsdu)
- buffer->last_amsdu = sn;
-
/*
* We cannot trust NSSN for AMSDU sub-frames that are not the last.
* The reason is that NSSN advances on the first sub-frame, and may
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 3ce9150213a7..376b9b12fa62 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1774,7 +1774,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,
&cp->channel_config[ch_cnt];
u32 s_ssid_bitmap = 0, bssid_bitmap = 0, flags = 0;
- u8 j, k, n_s_ssids = 0, n_bssids = 0;
+ u8 k, n_s_ssids = 0, n_bssids = 0;
u8 max_s_ssids, max_bssids;
bool force_passive = false, found = false, allow_passive = true,
unsolicited_probe_on_chan = false, psc_no_listen = false;
@@ -1799,7 +1799,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,
cfg->v5.iter_count = 1;
cfg->v5.iter_interval = 0;
- for (j = 0; j < params->n_6ghz_params; j++) {
+ for (u32 j = 0; j < params->n_6ghz_params; j++) {
s8 tmp_psd_20;
if (!(scan_6ghz_params[j].channel_idx == i))
@@ -1873,7 +1873,7 @@ iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,
* SSID.
* TODO: improve this logic
*/
- for (j = 0; j < params->n_6ghz_params; j++) {
+ for (u32 j = 0; j < params->n_6ghz_params; j++) {
if (!(scan_6ghz_params[j].channel_idx == i))
continue;
@@ -3597,7 +3597,8 @@ static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm,
IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n",
n_channels);
- if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
+ if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) ||
+ hweight16(vif->valid_links) == 1)
return -EINVAL;
size = struct_size(req, channels, n_channels);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index b6c99cd6d9e5..cd74c181c260 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -47,7 +47,7 @@ int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype)
lockdep_is_held(&mvm->mutex)))
return sta_id;
}
- return IWL_MVM_INVALID_STA;
+ return IWL_INVALID_STA;
}
/* Calculate the ampdu density and max size */
@@ -1216,7 +1216,7 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
* can be unshared and finding one (and only one) that can be
* reused.
* This function is also invoked as a sort of clean-up task,
- * in which case @alloc_for_sta is IWL_MVM_INVALID_STA.
+ * in which case @alloc_for_sta is IWL_INVALID_STA.
*
* Returns the queue number, or -ENOSPC.
*/
@@ -1309,7 +1309,7 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)
rcu_read_unlock();
- if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) {
+ if (free_queue >= 0 && alloc_for_sta != IWL_INVALID_STA) {
ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner,
alloc_for_sta);
if (ret)
@@ -1522,7 +1522,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
mutex_lock(&mvm->mutex);
- iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA);
+ iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA);
while (!list_empty(&mvm->add_stream_txqs)) {
struct iwl_mvm_txq *mvmtxq;
@@ -1580,7 +1580,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
return 0;
/* run the general cleanup/unsharing of queues */
- iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA);
+ iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA);
/* Make sure we have free resources for this STA */
if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls &&
@@ -1756,7 +1756,7 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* this function
*/
if (!mvm->mld_api_is_used) {
- if (WARN_ON(sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON(sta_id == IWL_INVALID_STA))
return -EINVAL;
mvm_sta->deflink.sta_id = sta_id;
@@ -1865,7 +1865,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
else
sta_id = mvm_sta->deflink.sta_id;
- if (sta_id == IWL_MVM_INVALID_STA)
+ if (sta_id == IWL_INVALID_STA)
return -ENOSPC;
spin_lock_init(&mvm_sta->lock);
@@ -1903,10 +1903,10 @@ update_fw:
if (vif->type == NL80211_IFTYPE_STATION) {
if (!sta->tdls) {
- WARN_ON(mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA);
+ WARN_ON(mvmvif->deflink.ap_sta_id != IWL_INVALID_STA);
mvmvif->deflink.ap_sta_id = sta_id;
} else {
- WARN_ON(mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA);
+ WARN_ON(mvmvif->deflink.ap_sta_id == IWL_INVALID_STA);
}
}
@@ -2095,7 +2095,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, 0);
/* unassoc - go ahead - remove the AP STA now */
- mvm_link->ap_sta_id = IWL_MVM_INVALID_STA;
+ mvm_link->ap_sta_id = IWL_INVALID_STA;
}
/*
@@ -2103,7 +2103,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* before the STA is removed.
*/
if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) {
- mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
+ mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;
cancel_delayed_work(&mvm->tdls_cs.dwork);
}
@@ -2170,9 +2170,9 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
u8 type)
{
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
- sta->sta_id == IWL_MVM_INVALID_STA) {
+ sta->sta_id == IWL_INVALID_STA) {
sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
- if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA))
return -ENOSPC;
}
@@ -2188,7 +2188,7 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
{
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
- sta->sta_id = IWL_MVM_INVALID_STA;
+ sta->sta_id = IWL_INVALID_STA;
}
static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue,
@@ -2306,7 +2306,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_INVALID_STA))
return -EINVAL;
iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id,
@@ -2324,7 +2324,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_INVALID_STA))
return -EINVAL;
iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id,
@@ -2389,7 +2389,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (vif->type == NL80211_IFTYPE_ADHOC)
baddr = vif->bss_conf.bssid;
- if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(bsta->sta_id == IWL_INVALID_STA))
return -ENOSPC;
ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
@@ -2644,7 +2644,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
u32 status;
/* This is a valid situation for GTK removal */
- if (sta_id == IWL_MVM_INVALID_STA)
+ if (sta_id == IWL_INVALID_STA)
return 0;
key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
@@ -3514,7 +3514,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm,
* station ID, then use AP's station ID.
*/
if (vif->type == NL80211_IFTYPE_STATION &&
- mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
+ mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {
u8 sta_id = mvmvif->deflink.ap_sta_id;
sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
@@ -3569,7 +3569,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA_KEY,
new_api ? 2 : 1);
- if (sta_id == IWL_MVM_INVALID_STA)
+ if (sta_id == IWL_INVALID_STA)
return -EINVAL;
keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) &
@@ -3728,7 +3728,7 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm,
if (remove_key) {
/* This is a valid situation for IGTK */
- if (sta_id == IWL_MVM_INVALID_STA)
+ if (sta_id == IWL_INVALID_STA)
return 0;
igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID);
@@ -3795,7 +3795,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
return sta->addr;
if (vif->type == NL80211_IFTYPE_STATION &&
- mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
+ mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) {
u8 sta_id = mvmvif->deflink.ap_sta_id;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
lockdep_is_held(&mvm->mutex));
@@ -3865,7 +3865,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
{
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
struct iwl_mvm_sta *mvm_sta;
- u8 sta_id = IWL_MVM_INVALID_STA;
+ u8 sta_id = IWL_INVALID_STA;
int ret;
static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
@@ -3966,7 +3966,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
{
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
struct iwl_mvm_sta *mvm_sta;
- u8 sta_id = IWL_MVM_INVALID_STA;
+ u8 sta_id = IWL_INVALID_STA;
int ret, i;
lockdep_assert_held(&mvm->mutex);
@@ -4273,7 +4273,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
return;
/* Need to block/unblock also multicast station */
- if (mvmvif->deflink.mcast_sta.sta_id != IWL_MVM_INVALID_STA)
+ if (mvmvif->deflink.mcast_sta.sta_id != IWL_INVALID_STA)
iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif,
&mvmvif->deflink.mcast_sta,
disable);
@@ -4282,7 +4282,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
* Only unblock the broadcast station (FW blocks it for immediate
* quiet, not the driver)
*/
- if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_MVM_INVALID_STA)
+ if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_INVALID_STA)
iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif,
&mvmvif->deflink.bcast_sta,
disable);
@@ -4328,7 +4328,10 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
unsigned int wdg_timeout =
iwl_mvm_get_wd_timeout(mvm, vif);
bool mld = iwl_mvm_has_mld_api(mvm->fw);
- u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK;
+ u32 type = IWL_STA_LINK;
+
+ if (mld)
+ type = STATION_TYPE_PEER;
ret = iwl_mvm_allocate_int_sta(mvm, sta, 0,
NL80211_IFTYPE_UNSPECIFIED, type);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
index 3d25ff5cd7e8..65927ebbabb7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
@@ -196,7 +196,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,
mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm);
if (state == IWL_MVM_TDLS_SW_IDLE)
- mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA;
+ mvm->tdls_cs.cur_sta_id = IWL_INVALID_STA;
}
void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
@@ -250,7 +250,7 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
/* get the existing peer if it's there */
if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE &&
- mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) {
+ mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {
struct ieee80211_sta *sta = rcu_dereference_protected(
mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],
lockdep_is_held(&mvm->mutex));
@@ -465,7 +465,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work)
iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);
/* station might be gone, in that case do nothing */
- if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA)
+ if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA)
return;
sta = rcu_dereference_protected(
@@ -512,7 +512,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,
sta->addr, chandef->chan->center_freq, chandef->width);
/* we only support a single peer for channel switching */
- if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) {
+ if (mvm->tdls_cs.peer.sta_id != IWL_INVALID_STA) {
IWL_DEBUG_TDLS(mvm,
"Existing peer. Can't start switch with %pM\n",
sta->addr);
@@ -566,7 +566,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,
IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr);
/* we only support a single peer for channel switching */
- if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) {
+ if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) {
IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr);
goto out;
}
@@ -587,7 +587,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,
mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE)
wait_for_phy = true;
- mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
+ mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;
dev_kfree_skb(mvm->tdls_cs.peer.skb);
mvm->tdls_cs.peer.skb = NULL;
@@ -630,7 +630,7 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,
if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE &&
params->status != 0 &&
mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&
- mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) {
+ mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {
struct ieee80211_sta *cur_sta;
/* make sure it's the same peer */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index ca026b5256ce..c9867d26361b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1213,7 +1213,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
return -1;
- if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA))
return -1;
if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he)
@@ -1357,7 +1357,7 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA))
return -1;
memcpy(&info, skb->cb, sizeof(info));
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 1d1364d03f02..dd890dcd1505 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -261,7 +261,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq)
.data = { lq, },
};
- if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA ||
+ if (WARN_ON(lq->sta_id == IWL_INVALID_STA ||
iwl_mvm_has_tlc_offload(mvm)))
return -EINVAL;
@@ -679,10 +679,8 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bss_iface_iterator, &bss_iter_data);
- if (bss_iter_data.error) {
- IWL_ERR(mvm, "More than one managed interface active!\n");
+ if (bss_iter_data.error)
return ERR_PTR(-EINVAL);
- }
return bss_iter_data.vif;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 3b9943eb6934..d19b3bd0866b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1643,6 +1643,8 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
out:
if (*status == IWL_D3_STATUS_ALIVE)
ret = iwl_pcie_d3_handshake(trans, false);
+ else
+ trans->state = IWL_TRANS_NO_FW;
return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 9fe050f0ddc1..1ef14340953c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -2351,6 +2351,10 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
txq_write_ptr = txq->write_ptr;
spin_unlock(&txq->lock);
+ /* There is nothing to do if we are flushing an empty queue */
+ if (is_flush && txq_write_ptr == txq_read_ptr)
+ goto out;
+
read_ptr = iwl_txq_get_cmd_index(txq, txq_read_ptr);
if (!test_bit(txq_id, trans_pcie->txqs.queue_used)) {
diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c
index d33a994906a7..27f44a9f0bc1 100644
--- a/drivers/net/wireless/intersil/p54/p54spi.c
+++ b/drivers/net/wireless/intersil/p54/p54spi.c
@@ -624,7 +624,7 @@ static int p54spi_probe(struct spi_device *spi)
gpio_direction_input(p54spi_gpio_irq);
ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
- p54spi_interrupt, 0, "p54spi",
+ p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi",
priv->spi);
if (ret < 0) {
dev_err(&priv->spi->dev, "request_irq() failed");
@@ -633,8 +633,6 @@ static int p54spi_probe(struct spi_device *spi)
irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING);
- disable_irq(gpio_to_irq(p54spi_gpio_irq));
-
INIT_WORK(&priv->work, p54spi_work);
init_completion(&priv->fw_comp);
INIT_LIST_HEAD(&priv->tx_pending);
diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig
index 36b234bc5be8..caf8bc231b2e 100644
--- a/drivers/net/wireless/marvell/libertas/Kconfig
+++ b/drivers/net/wireless/marvell/libertas/Kconfig
@@ -3,7 +3,6 @@ config LIBERTAS
tristate "Marvell 8xxx Libertas WLAN driver support"
depends on USB || MMC || SPI
depends on CFG80211
- select LIB80211
select FW_LOADER
help
A library for Marvell Libertas 8xxx devices.
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c
index afe9bcd3ad46..2e2c193716d9 100644
--- a/drivers/net/wireless/marvell/libertas/cfg.c
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
@@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *tlv, const u8 *ie, size_t ie_len)
*/
static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct lbs_private *priv = wiphy_priv(wiphy);
diff --git a/drivers/net/wireless/marvell/libertas/mesh.h b/drivers/net/wireless/marvell/libertas/mesh.h
index 44c4cd0230a8..e37db10e82a9 100644
--- a/drivers/net/wireless/marvell/libertas/mesh.h
+++ b/drivers/net/wireless/marvell/libertas/mesh.h
@@ -7,7 +7,6 @@
#include <net/iw_handler.h>
-#include <net/lib80211.h>
#include "host.h"
#include "dev.h"
diff --git a/drivers/net/wireless/marvell/libertas/radiotap.h b/drivers/net/wireless/marvell/libertas/radiotap.h
index 1ed5608d353f..d543bfe739dc 100644
--- a/drivers/net/wireless/marvell/libertas/radiotap.h
+++ b/drivers/net/wireless/marvell/libertas/radiotap.h
@@ -2,7 +2,7 @@
#include <net/ieee80211_radiotap.h>
struct tx_radiotap_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rate;
u8 txpower;
u8 rts_retries;
@@ -31,7 +31,7 @@ struct tx_radiotap_hdr {
#define IEEE80211_FC_DSTODS 0x0300
struct rx_radiotap_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 flags;
u8 rate;
u8 antsignal;
diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 1cff001bdc51..b30ed321c625 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -938,8 +938,10 @@ void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter)
assoc_resp.links[0].bss = priv->req_bss;
assoc_resp.buf = priv->assoc_rsp_buf;
assoc_resp.len = priv->assoc_rsp_size;
+ wiphy_lock(priv->wdev.wiphy);
cfg80211_rx_assoc_resp(priv->netdev,
&assoc_resp);
+ wiphy_unlock(priv->wdev.wiphy);
priv->assoc_rsp_size = 0;
}
}
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index d03129d5d24e..4a96281792cc 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -875,7 +875,7 @@ struct mwifiex_ietypes_chanstats {
struct mwifiex_ie_types_wildcard_ssid_params {
struct mwifiex_ie_types_header header;
u8 max_ssid_length;
- u8 ssid[1];
+ u8 ssid[];
} __packed;
#define TSF_DATA_SIZE 8
diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h
index 516159b721d3..74747d3a379a 100644
--- a/drivers/net/wireless/marvell/mwifiex/ioctl.h
+++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h
@@ -8,7 +8,7 @@
#ifndef _MWIFIEX_IOCTL_H_
#define _MWIFIEX_IOCTL_H_
-#include <net/lib80211.h>
+#define NUM_WEP_KEYS 4
enum {
MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c
index 6d8f1d1d7ca4..5a1a0287c1d5 100644
--- a/drivers/net/wireless/marvell/mwifiex/join.c
+++ b/drivers/net/wireless/marvell/mwifiex/join.c
@@ -663,7 +663,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
bool enable_data = true;
u16 cap_info, status_code, aid;
const u8 *ie_ptr;
- struct ieee80211_ht_operation *assoc_resp_ht_oper;
if (!priv->attempted_bss_desc) {
mwifiex_dbg(priv->adapter, ERROR,
@@ -779,14 +778,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer,
priv->assoc_rsp_size
- sizeof(struct ieee_types_assoc_rsp));
- if (ie_ptr) {
- assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr
- + sizeof(struct ieee_types_header));
- priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param;
- priv->ht_param_present = true;
- } else {
- priv->ht_param_present = false;
- }
+
+ priv->ht_param_present = ie_ptr ? true : false;
mwifiex_dbg(priv->adapter, INFO,
"info: ASSOC_RESP: curr_pkt_filter is %#x\n",
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 96d1f6039fbc..855019fe5485 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -1679,7 +1679,8 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter)
}
ret = devm_request_irq(dev, adapter->irq_wakeup,
- mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW,
+ mwifiex_irq_wakeup_handler,
+ IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN,
"wifi_wake", adapter);
if (ret) {
dev_err(dev, "Failed to request irq_wakeup %d (%d)\n",
@@ -1687,7 +1688,6 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter)
goto err_exit;
}
- disable_irq(adapter->irq_wakeup);
if (device_init_wakeup(dev, true)) {
dev_err(dev, "fail to init wakeup for mwifiex\n");
goto err_exit;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 566adce3413c..0674dcf7a537 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -19,7 +19,6 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <net/sock.h>
-#include <net/lib80211.h>
#include <linux/vmalloc.h>
#include <linux/firmware.h>
#include <linux/ctype.h>
@@ -574,7 +573,6 @@ struct mwifiex_private {
u16 listen_interval;
u16 atim_window;
u8 adhoc_channel;
- u8 adhoc_is_link_sensed;
u8 adhoc_state;
struct mwifiex_802_11_security sec_info;
struct mwifiex_wep_key wep_key[NUM_WEP_KEYS];
@@ -683,7 +681,6 @@ struct mwifiex_private {
struct mwifiex_ds_mem_rw mem_rw;
struct sk_buff_head bypass_txq;
struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];
- u8 assoc_resp_ht_param;
bool ht_param_present;
};
@@ -802,7 +799,6 @@ struct mwifiex_auto_tdls_peer {
unsigned long rssi_jiffies;
u8 failure_count;
u8 do_discover;
- u8 do_setup;
};
#define MWIFIEX_TYPE_AGGR_DATA_V2 11
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c
index b5f3821a6a8f..400348abeee5 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c
@@ -177,17 +177,14 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code,
priv->is_data_rate_auto = true;
priv->data_rate = 0;
- priv->assoc_resp_ht_param = 0;
priv->ht_param_present = false;
if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data)
mwifiex_hist_data_reset(priv);
- if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
priv->adhoc_state = ADHOC_IDLE;
- priv->adhoc_is_link_sensed = false;
- }
/*
* Memorize the previous SSID and BSSID so
@@ -843,7 +840,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_ADHOC_BCN_LOST:
mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n");
- priv->adhoc_is_link_sensed = false;
mwifiex_clean_txrx(priv);
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
if (netif_carrier_ok(priv->netdev))
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index d3cba6895f8c..e06a0622973e 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -351,8 +351,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
goto done;
}
- priv->adhoc_is_link_sensed = false;
-
ret = mwifiex_check_network_compatibility(priv, bss_desc);
mwifiex_stop_net_dev_queue(priv->netdev, adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
index 7823e67694e8..0a5f340876c3 100644
--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
+++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
@@ -1306,7 +1306,6 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
peer->mac_addr,
NL80211_TDLS_SETUP,
0, GFP_ATOMIC);
- peer->do_setup = false;
priv->check_tdls_tx = false;
} else if (peer->failure_count <
MWIFIEX_TDLS_MAX_FAIL_COUNT &&
@@ -1465,7 +1464,6 @@ void mwifiex_check_auto_tdls(struct timer_list *t)
tdls_peer->failure_count <
MWIFIEX_TDLS_MAX_FAIL_COUNT) {
priv->check_tdls_tx = true;
- tdls_peer->do_setup = true;
mwifiex_dbg(priv->adapter, INFO,
"check TDLS with peer=%pM\t"
"rssi=%d\n", tdls_peer->mac_addr,
diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c
index 42c04bf858da..1f1f6280a0f2 100644
--- a/drivers/net/wireless/marvell/mwifiex/util.c
+++ b/drivers/net/wireless/marvell/mwifiex/util.c
@@ -494,7 +494,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
}
}
+ wiphy_lock(priv->wdev.wiphy);
cfg80211_rx_mlme_mgmt(priv->netdev, skb->data, pkt_len);
+ wiphy_unlock(priv->wdev.wiphy);
}
if (priv->adapter->host_mlme_enabled &&
diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index 98da82b74094..3353012e8542 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -84,13 +84,16 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
mutex_lock(&dev->mcu.mutex);
if (dev->mcu_ops->mcu_skb_prepare_msg) {
+ orig_skb = skb;
ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);
if (ret < 0)
goto out;
}
retry:
- orig_skb = skb_get(skb);
+ /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */
+ if (orig_skb)
+ skb_get(orig_skb);
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
if (ret < 0)
goto out;
@@ -105,7 +108,7 @@ retry:
do {
skb = mt76_mcu_get_response(dev, expires);
if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) &&
- retry++ < dev->mcu_ops->max_retry) {
+ orig_skb && retry++ < dev->mcu_ops->max_retry) {
dev_err(dev->dev, "Retry message %08x (seq %d)\n",
cmd, seq);
skb = orig_skb;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
index ec02148a7f1f..08590aa68356 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
@@ -71,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2);
struct platform_driver mt76_wmac_driver = {
.probe = mt76_wmac_probe,
- .remove_new = mt76_wmac_remove,
+ .remove = mt76_wmac_remove,
.driver = {
.name = "mt76_wmac",
.of_match_table = of_wmac_match,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
index 12e3e4a91d27..06a0f2a141e8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
@@ -63,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = {
.of_match_table = mt7622_wmac_of_match,
},
.probe = mt7622_wmac_probe,
- .remove_new = mt7622_wmac_remove,
+ .remove = mt7622_wmac_remove,
};
MODULE_FIRMWARE(MT7622_FIRMWARE_N9);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index d75e8dea1fbd..c6f498fc81ff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -1163,9 +1163,10 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_dev *dev = phy->dev;
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
@@ -1709,7 +1710,7 @@ const struct ieee80211_ops mt7915_ops = {
.stop_ap = mt7915_stop_ap,
.sta_state = mt76_sta_state,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
- .sta_rc_update = mt7915_sta_rc_update,
+ .link_sta_rc_update = mt7915_sta_rc_update,
.set_key = mt7915_set_key,
.ampdu_action = mt7915_ampdu_action,
.set_rts_threshold = mt7915_set_rts_threshold,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
index 90a6f61d1089..c823a7554a3a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
@@ -1303,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = {
.of_match_table = mt798x_wmac_of_match,
},
.probe = mt798x_wmac_probe,
- .remove_new = mt798x_wmac_remove,
+ .remove = mt798x_wmac_remove,
};
MODULE_FIRMWARE(MT7986_FIRMWARE_WA);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 39f071ece35e..2b34ae5e0cb5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -1060,9 +1060,10 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_dev *dev = phy->dev;
@@ -1472,7 +1473,7 @@ const struct ieee80211_ops mt7996_ops = {
.sta_add = mt7996_sta_add,
.sta_remove = mt7996_sta_remove,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
- .sta_rc_update = mt7996_sta_rc_update,
+ .link_sta_rc_update = mt7996_sta_rc_update,
.set_key = mt7996_set_key,
.ampdu_action = mt7996_ampdu_action,
.set_rts_threshold = mt7996_set_rts_threshold,
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index eb37b228d54e..e96736cc7259 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl)
}
static int set_channel(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct wilc *wl = wiphy_priv(wiphy);
@@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev,
struct wilc_vif *vif = netdev_priv(dev);
int ret;
- ret = set_channel(wiphy, &settings->chandef);
+ ret = set_channel(wiphy, dev, &settings->chandef);
if (ret != 0)
netdev_err(dev, "Error in setting channel\n");
@@ -1757,57 +1758,10 @@ void wlan_deinit_locks(struct wilc *wilc)
cleanup_srcu_struct(&wilc->srcu);
}
-int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
- const struct wilc_hif_func *ops)
-{
- struct wilc *wl;
- int ret, i;
-
- wl = wilc_create_wiphy(dev);
- if (!wl)
- return -EINVAL;
-
- wlan_init_locks(wl);
-
- ret = wilc_wlan_cfg_init(wl);
- if (ret)
- goto free_wl;
-
- *wilc = wl;
- wl->io_type = io_type;
- wl->hif_func = ops;
-
- for (i = 0; i < NQUEUES; i++)
- INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
-
- INIT_LIST_HEAD(&wl->rxq_head.list);
- INIT_LIST_HEAD(&wl->vif_list);
-
- wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
- wiphy_name(wl->wiphy));
- if (!wl->hif_workqueue) {
- ret = -ENOMEM;
- goto free_cfg;
- }
-
- return 0;
-
-free_cfg:
- wilc_wlan_cfg_deinit(wl);
-
-free_wl:
- wlan_deinit_locks(wl);
- wiphy_unregister(wl->wiphy);
- wiphy_free(wl->wiphy);
- return ret;
-}
-EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
-
-struct wilc *wilc_create_wiphy(struct device *dev)
+static struct wilc *wilc_create_wiphy(struct device *dev)
{
struct wiphy *wiphy;
struct wilc *wl;
- int ret;
wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl));
if (!wiphy)
@@ -1850,17 +1804,66 @@ struct wilc *wilc_create_wiphy(struct device *dev)
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT);
wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- wiphy->features |= NL80211_FEATURE_SAE;
set_wiphy_dev(wiphy, dev);
wl->wiphy = wiphy;
- ret = wiphy_register(wiphy);
- if (ret) {
- wiphy_free(wiphy);
- return NULL;
- }
return wl;
}
+int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
+ const struct wilc_hif_func *ops)
+{
+ struct wilc *wl;
+ int ret, i;
+
+ wl = wilc_create_wiphy(dev);
+ if (!wl)
+ return -EINVAL;
+
+ wlan_init_locks(wl);
+
+ ret = wilc_wlan_cfg_init(wl);
+ if (ret)
+ goto free_wl;
+
+ *wilc = wl;
+ wl->io_type = io_type;
+ wl->hif_func = ops;
+
+ for (i = 0; i < NQUEUES; i++)
+ INIT_LIST_HEAD(&wl->txq[i].txq_head.list);
+
+ INIT_LIST_HEAD(&wl->rxq_head.list);
+ INIT_LIST_HEAD(&wl->vif_list);
+
+ wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
+ wiphy_name(wl->wiphy));
+ if (!wl->hif_workqueue) {
+ ret = -ENOMEM;
+ goto free_cfg;
+ }
+
+ return 0;
+
+free_cfg:
+ wilc_wlan_cfg_deinit(wl);
+
+free_wl:
+ wlan_deinit_locks(wl);
+ wiphy_free(wl->wiphy);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_init);
+
+int wilc_cfg80211_register(struct wilc *wilc)
+{
+ /* WPA3/SAE supported only on WILC1000 */
+ if (is_wilc1000(wilc->chipid))
+ wilc->wiphy->features |= NL80211_FEATURE_SAE;
+
+ return wiphy_register(wilc->wiphy);
+}
+EXPORT_SYMBOL_GPL(wilc_cfg80211_register);
+
int wilc_init_host_int(struct net_device *net)
{
int ret;
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
index 8c65951cfaf9..2dc9c1c42d60 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h
@@ -10,7 +10,7 @@
int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type,
const struct wilc_hif_func *ops);
-struct wilc *wilc_create_wiphy(struct device *dev);
+int wilc_cfg80211_register(struct wilc *wilc);
void wilc_deinit_host_int(struct net_device *net);
int wilc_init_host_int(struct net_device *net);
void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size);
diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c
index 03b7229a0ff5..c3d27aaec297 100644
--- a/drivers/net/wireless/microchip/wilc1000/mon.c
+++ b/drivers/net/wireless/microchip/wilc1000/mon.c
@@ -7,12 +7,12 @@
#include "cfg80211.h"
struct wilc_wfi_radiotap_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rate;
} __packed;
struct wilc_wfi_radiotap_cb_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rate;
u8 dump;
u16 tx_flags;
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 9ecf3fb29b55..7e84fc0fd911 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -23,6 +23,12 @@
#define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin"
#define WILC1000_FW(api) __WILC1000_FW(api)
+#define WILC3000_API_VER 1
+
+#define WILC3000_FW_PREFIX "atmel/wilc3000_wifi_firmware-"
+#define __WILC3000_FW(api) WILC3000_FW_PREFIX #api ".bin"
+#define WILC3000_FW(api) __WILC3000_FW(api)
+
static irqreturn_t isr_uh_routine(int irq, void *user_data)
{
struct wilc *wilc = user_data;
@@ -195,20 +201,24 @@ static int wilc_wlan_get_firmware(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- int chip_id;
const struct firmware *wilc_fw;
+ char *firmware;
int ret;
- chip_id = wilc_get_chipid(wilc, false);
+ if (is_wilc1000(wilc->chipid))
+ firmware = WILC1000_FW(WILC1000_API_VER);
+ else if (is_wilc3000(wilc->chipid))
+ firmware = WILC3000_FW(WILC3000_API_VER);
+ else
+ return -EINVAL;
- netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id,
- WILC1000_FW(WILC1000_API_VER));
+ netdev_info(dev, "WILC%d loading firmware [%s]\n",
+ is_wilc1000(wilc->chipid) ? 1000 : 3000,
+ firmware);
- ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER),
- wilc->dev);
+ ret = request_firmware(&wilc_fw, firmware, wilc->dev);
if (ret != 0) {
- netdev_err(dev, "%s - firmware not available\n",
- WILC1000_FW(WILC1000_API_VER));
+ netdev_err(dev, "%s - firmware not available\n", firmware);
return -EINVAL;
}
wilc->firmware = wilc_fw;
@@ -233,7 +243,7 @@ static int wilc_start_firmware(struct net_device *dev)
return 0;
}
-static int wilc1000_firmware_download(struct net_device *dev)
+static int wilc_firmware_download(struct net_device *dev)
{
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
@@ -528,7 +538,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
if (ret)
goto fail_irq_enable;
- ret = wilc1000_firmware_download(dev);
+ ret = wilc_firmware_download(dev);
if (ret)
goto fail_irq_enable;
@@ -608,6 +618,9 @@ static int wilc_mac_open(struct net_device *ndev)
return ret;
}
+ wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
+ vif->idx);
+
netdev_dbg(ndev, "Mac address: %pM\n", ndev->dev_addr);
ret = wilc_set_mac_address(vif, ndev->dev_addr);
if (ret) {
@@ -618,9 +631,6 @@ static int wilc_mac_open(struct net_device *ndev)
return ret;
}
- wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype,
- vif->idx);
-
mgmt_regs.interface_stypes = vif->mgmt_reg_stypes;
/* so we detect a change */
vif->mgmt_reg_stypes = 0;
@@ -1014,3 +1024,4 @@ EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init);
MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER));
+MODULE_FIRMWARE(WILC3000_FW(WILC3000_API_VER));
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index b4da05d5a498..5262c8846c13 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -182,6 +182,14 @@ static int wilc_sdio_probe(struct sdio_func *func,
wilc_sdio_init(wilc, false);
+ ret = wilc_get_chipid(wilc);
+ if (ret)
+ goto dispose_irq;
+
+ ret = wilc_cfg80211_register(wilc);
+ if (ret)
+ goto dispose_irq;
+
ret = wilc_load_mac_from_nv(wilc);
if (ret) {
pr_err("Can not retrieve MAC address from chip\n");
@@ -667,7 +675,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
struct wilc_sdio *sdio_priv = wilc->bus_data;
struct sdio_cmd52 cmd;
int loop, ret;
- u32 chipid;
/**
* function 0 csa enable
@@ -756,18 +763,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
return ret;
}
- /**
- * make sure can read back chip id correctly
- **/
- if (!resume) {
- ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid);
- if (ret) {
- dev_err(&func->dev, "Fail cmd read chip id...\n");
- return ret;
- }
- dev_err(&func->dev, "chipid (%08x)\n", chipid);
- }
-
sdio_priv->isinit = true;
return 0;
}
@@ -815,13 +810,19 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status)
cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG;
} else {
cmd.function = 0;
- cmd.address = WILC_SDIO_IRQ_FLAG_REG;
+ cmd.address = is_wilc1000(wilc->chipid) ?
+ WILC1000_SDIO_IRQ_FLAG_REG :
+ WILC3000_SDIO_IRQ_FLAG_REG;
}
cmd.raw = 0;
cmd.read_write = 0;
cmd.data = 0;
wilc_sdio_cmd52(wilc, &cmd);
irq_flags = cmd.data;
+
+ if (sdio_priv->irq_gpio)
+ irq_flags &= is_wilc1000(wilc->chipid) ? 0x1f : 0x0f;
+
tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data);
if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags))
@@ -843,22 +844,56 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
if (sdio_priv->irq_gpio)
reg = val & (BIT(MAX_NUM_INT) - 1);
- /* select VMM table 0 */
- if (val & SEL_VMM_TBL0)
- reg |= BIT(5);
- /* select VMM table 1 */
- if (val & SEL_VMM_TBL1)
- reg |= BIT(6);
- /* enable VMM */
- if (val & EN_VMM)
- reg |= BIT(7);
+ if (is_wilc1000(wilc->chipid)) {
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ reg |= BIT(5);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ reg |= BIT(6);
+ /* enable VMM */
+ if (val & EN_VMM)
+ reg |= BIT(7);
+ } else {
+ if (sdio_priv->irq_gpio && reg) {
+ struct sdio_cmd52 cmd;
+
+ cmd.read_write = 1;
+ cmd.function = 0;
+ cmd.raw = 0;
+ cmd.address = WILC3000_SDIO_IRQ_FLAG_REG;
+ cmd.data = reg;
+
+ ret = wilc_sdio_cmd52(wilc, &cmd);
+ if (ret) {
+ dev_err(&func->dev,
+ "Failed cmd52, set 0xfe data (%d) ...\n",
+ __LINE__);
+ return ret;
+ }
+ }
+
+ reg = 0;
+ /* select VMM table 0 */
+ if (val & SEL_VMM_TBL0)
+ reg |= BIT(0);
+ /* select VMM table 1 */
+ if (val & SEL_VMM_TBL1)
+ reg |= BIT(1);
+ /* enable VMM */
+ if (val & EN_VMM)
+ reg |= BIT(2);
+ }
+
if (reg) {
struct sdio_cmd52 cmd;
cmd.read_write = 1;
cmd.function = 0;
cmd.raw = 0;
- cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
+ cmd.address = is_wilc1000(wilc->chipid) ?
+ WILC1000_SDIO_IRQ_CLEAR_FLAG_REG :
+ WILC3000_SDIO_VMM_TBL_CTRL_REG;
cmd.data = reg;
ret = wilc_sdio_cmd52(wilc, &cmd);
@@ -979,17 +1014,15 @@ static int wilc_sdio_suspend(struct device *dev)
if (!IS_ERR(wilc->rtc_clk))
clk_disable_unprepare(wilc->rtc_clk);
- host_sleep_notify(wilc);
-
- wilc_sdio_disable_interrupt(wilc);
-
- ret = wilc_sdio_reset(wilc);
+ ret = host_sleep_notify(wilc);
if (ret) {
- dev_err(&func->dev, "Fail reset sdio\n");
+ clk_prepare_enable(wilc->rtc_clk);
return ret;
}
- return 0;
+ wilc_sdio_disable_interrupt(wilc);
+
+ return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
}
static int wilc_sdio_resume(struct device *dev)
@@ -1008,9 +1041,7 @@ static int wilc_sdio_resume(struct device *dev)
wilc_sdio_init(wilc, true);
wilc_sdio_enable_interrupt(wilc);
- host_wakeup_notify(wilc);
-
- return 0;
+ return host_wakeup_notify(wilc);
}
static const struct of_device_id wilc_of_match[] = {
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 05b577b1068e..ce2a9cdd6aa7 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -245,7 +245,11 @@ static int wilc_bus_probe(struct spi_device *spi)
if (ret)
goto power_down;
- ret = wilc_validate_chipid(wilc);
+ ret = wilc_get_chipid(wilc);
+ if (ret)
+ goto power_down;
+
+ ret = wilc_cfg80211_register(wilc);
if (ret)
goto power_down;
@@ -1229,7 +1233,7 @@ static int wilc_validate_chipid(struct wilc *wilc)
dev_err(&spi->dev, "Fail cmd read chip id...\n");
return ret;
}
- if (!is_wilc1000(chipid)) {
+ if (!is_wilc1000(chipid) && !is_wilc3000(chipid)) {
dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid);
return -ENODEV;
}
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c
index 533939e71534..9d80adc45d6b 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.c
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.c
@@ -12,20 +12,6 @@
#define WAKE_UP_TRIAL_RETRY 10000
-static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
-{
- mutex_lock(&wilc->hif_cs);
- if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode)
- chip_wakeup(wilc);
-}
-
-static inline void release_bus(struct wilc *wilc, enum bus_release release)
-{
- if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
- chip_allow_sleep(wilc);
- mutex_unlock(&wilc->hif_cs);
-}
-
static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num,
struct txq_entry_t *tqe)
{
@@ -555,7 +541,7 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc)
return rqe;
}
-void chip_allow_sleep(struct wilc *wilc)
+static int chip_allow_sleep_wilc1000(struct wilc *wilc)
{
u32 reg = 0;
const struct wilc_hif_func *hif_func = wilc->hif_func;
@@ -584,7 +570,7 @@ void chip_allow_sleep(struct wilc *wilc)
while (--trials) {
ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, &reg);
if (ret)
- return;
+ return ret;
if ((reg & to_host_from_fw_bit) == 0)
break;
}
@@ -594,28 +580,62 @@ void chip_allow_sleep(struct wilc *wilc)
/* Clear bit 1 */
ret = hif_func->hif_read_reg(wilc, wakeup_reg, &reg);
if (ret)
- return;
+ return ret;
if (reg & wakeup_bit) {
reg &= ~wakeup_bit;
ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg);
if (ret)
- return;
+ return ret;
}
ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, &reg);
if (ret)
- return;
+ return ret;
if (reg & from_host_to_fw_bit) {
reg &= ~from_host_to_fw_bit;
ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg);
if (ret)
- return;
+ return ret;
+ }
+ return 0;
+}
+
+static int chip_allow_sleep_wilc3000(struct wilc *wilc)
+{
+ u32 reg = 0;
+ int ret;
+ const struct wilc_hif_func *hif_func = wilc->hif_func;
+
+ if (wilc->io_type == WILC_HIF_SDIO) {
+ ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, &reg);
+ if (ret)
+ return ret;
+ ret = hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
+ reg & ~WILC_SDIO_WAKEUP_BIT);
+ if (ret)
+ return ret;
+ } else {
+ ret = hif_func->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, &reg);
+ if (ret)
+ return ret;
+ ret = hif_func->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG,
+ reg & ~WILC_SPI_WAKEUP_BIT);
+ if (ret)
+ return ret;
}
+ return 0;
+}
+
+static int chip_allow_sleep(struct wilc *wilc)
+{
+ if (is_wilc1000(wilc->chipid))
+ return chip_allow_sleep_wilc1000(wilc);
+ else
+ return chip_allow_sleep_wilc3000(wilc);
}
-EXPORT_SYMBOL_GPL(chip_allow_sleep);
-void chip_wakeup(struct wilc *wilc)
+static int chip_wakeup_wilc1000(struct wilc *wilc)
{
u32 ret = 0;
u32 clk_status_val = 0, trials = 0;
@@ -627,15 +647,15 @@ void chip_wakeup(struct wilc *wilc)
if (wilc->io_type == WILC_HIF_SDIO) {
wakeup_reg = WILC_SDIO_WAKEUP_REG;
wakeup_bit = WILC_SDIO_WAKEUP_BIT;
- clk_status_reg = WILC_SDIO_CLK_STATUS_REG;
- clk_status_bit = WILC_SDIO_CLK_STATUS_BIT;
+ clk_status_reg = WILC1000_SDIO_CLK_STATUS_REG;
+ clk_status_bit = WILC1000_SDIO_CLK_STATUS_BIT;
from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG;
from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT;
} else {
wakeup_reg = WILC_SPI_WAKEUP_REG;
wakeup_bit = WILC_SPI_WAKEUP_BIT;
- clk_status_reg = WILC_SPI_CLK_STATUS_REG;
- clk_status_bit = WILC_SPI_CLK_STATUS_BIT;
+ clk_status_reg = WILC1000_SPI_CLK_STATUS_REG;
+ clk_status_bit = WILC1000_SPI_CLK_STATUS_BIT;
from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG;
from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT;
}
@@ -644,20 +664,20 @@ void chip_wakeup(struct wilc *wilc)
ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg,
from_host_to_fw_bit);
if (ret)
- return;
+ return ret;
/* Set wake-up bit */
ret = hif_func->hif_write_reg(wilc, wakeup_reg,
wakeup_bit);
if (ret)
- return;
+ return ret;
while (trials < WAKE_UP_TRIAL_RETRY) {
ret = hif_func->hif_read_reg(wilc, clk_status_reg,
&clk_status_val);
if (ret) {
pr_err("Bus error %d %x\n", ret, clk_status_val);
- return;
+ return ret;
}
if (clk_status_val & clk_status_bit)
break;
@@ -666,29 +686,135 @@ void chip_wakeup(struct wilc *wilc)
}
if (trials >= WAKE_UP_TRIAL_RETRY) {
pr_err("Failed to wake-up the chip\n");
- return;
+ return -ETIMEDOUT;
}
/* Sometimes spi fail to read clock regs after reading
* writing clockless registers
*/
if (wilc->io_type == WILC_HIF_SPI)
wilc->hif_func->hif_reset(wilc);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(chip_wakeup);
-void host_wakeup_notify(struct wilc *wilc)
+static int chip_wakeup_wilc3000(struct wilc *wilc)
{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
- wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ u32 wakeup_reg_val, clk_status_reg_val, trials = 0;
+ u32 wakeup_reg, wakeup_bit;
+ u32 clk_status_reg, clk_status_bit;
+ int wake_seq_trials = 5;
+ const struct wilc_hif_func *hif_func = wilc->hif_func;
+
+ if (wilc->io_type == WILC_HIF_SDIO) {
+ wakeup_reg = WILC_SDIO_WAKEUP_REG;
+ wakeup_bit = WILC_SDIO_WAKEUP_BIT;
+ clk_status_reg = WILC3000_SDIO_CLK_STATUS_REG;
+ clk_status_bit = WILC3000_SDIO_CLK_STATUS_BIT;
+ } else {
+ wakeup_reg = WILC_SPI_WAKEUP_REG;
+ wakeup_bit = WILC_SPI_WAKEUP_BIT;
+ clk_status_reg = WILC3000_SPI_CLK_STATUS_REG;
+ clk_status_bit = WILC3000_SPI_CLK_STATUS_BIT;
+ }
+
+ hif_func->hif_read_reg(wilc, wakeup_reg, &wakeup_reg_val);
+ do {
+ hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_reg_val |
+ wakeup_bit);
+ /* Check the clock status */
+ hif_func->hif_read_reg(wilc, clk_status_reg,
+ &clk_status_reg_val);
+
+ /* In case of clocks off, wait 1ms, and check it again.
+ * if still off, wait for another 1ms, for a total wait of 3ms.
+ * If still off, redo the wake up sequence
+ */
+ while ((clk_status_reg_val & clk_status_bit) == 0 &&
+ (++trials % 4) != 0) {
+ /* Wait for the chip to stabilize*/
+ usleep_range(1000, 1100);
+
+ /* Make sure chip is awake. This is an extra step that
+ * can be removed later to avoid the bus access
+ * overhead
+ */
+ hif_func->hif_read_reg(wilc, clk_status_reg,
+ &clk_status_reg_val);
+ }
+ /* in case of failure, Reset the wakeup bit to introduce a new
+ * edge on the next loop
+ */
+ if ((clk_status_reg_val & clk_status_bit) == 0) {
+ hif_func->hif_write_reg(wilc, wakeup_reg,
+ wakeup_reg_val & (~wakeup_bit));
+ /* added wait before wakeup sequence retry */
+ usleep_range(200, 300);
+ }
+ } while ((clk_status_reg_val & clk_status_bit) == 0 && wake_seq_trials-- > 0);
+ if (!wake_seq_trials)
+ dev_err(wilc->dev, "clocks still OFF. Wake up failed\n");
+
+ return 0;
+}
+
+static int chip_wakeup(struct wilc *wilc)
+{
+ if (is_wilc1000(wilc->chipid))
+ return chip_wakeup_wilc1000(wilc);
+ else
+ return chip_wakeup_wilc3000(wilc);
+}
+
+static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
+{
+ int ret = 0;
+
+ mutex_lock(&wilc->hif_cs);
+ if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) {
+ ret = chip_wakeup(wilc);
+ if (ret)
+ mutex_unlock(&wilc->hif_cs);
+ }
+
+ return ret;
+}
+
+static inline int release_bus(struct wilc *wilc, enum bus_release release)
+{
+ int ret = 0;
+
+ if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode)
+ ret = chip_allow_sleep(wilc);
+ mutex_unlock(&wilc->hif_cs);
+
+ return ret;
+}
+
+int host_wakeup_notify(struct wilc *wilc)
+{
+ int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ if (ret)
+ return ret;
+
+ wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ?
+ WILC1000_CORTUS_INTERRUPT_2 :
+ WILC3000_CORTUS_INTERRUPT_2, 1);
+ return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
}
EXPORT_SYMBOL_GPL(host_wakeup_notify);
-void host_sleep_notify(struct wilc *wilc)
+int host_sleep_notify(struct wilc *wilc)
{
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
- wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1);
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+
+ if (ret)
+ return ret;
+
+ wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ?
+ WILC1000_CORTUS_INTERRUPT_1 :
+ WILC3000_CORTUS_INTERRUPT_1, 1);
+ return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
}
EXPORT_SYMBOL_GPL(host_sleep_notify);
@@ -715,6 +841,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
int srcu_idx;
u8 *txb = wilc->tx_buffer;
struct wilc_vif *vif;
+ int rv;
if (wilc->quit)
goto out_update_cnt;
@@ -785,7 +912,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
goto out_unlock;
vmm_table[i] = 0x0;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto out_unlock;
+
counter = 0;
func = wilc->hif_func;
do {
@@ -818,19 +948,45 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
if (ret)
break;
- ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
- if (ret)
- break;
+ if (is_wilc1000(wilc->chipid)) {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2);
+ if (ret)
+ break;
- do {
- ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ do {
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ if (ret)
+ break;
+ if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
+ entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+ break;
+ }
+ } while (--timeout);
+ } else {
+ ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0);
if (ret)
break;
- if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
- entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+
+ /* interrupt firmware */
+ ret = func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, 1);
+ if (ret)
break;
- }
- } while (--timeout);
+
+ do {
+ ret = func->hif_read_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, &reg);
+ if (ret)
+ break;
+ if (reg == 0) {
+ /* Get the entries */
+ ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
+ if (ret)
+ break;
+
+ entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
+ break;
+ }
+ } while (--timeout);
+ }
if (timeout <= 0) {
ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
break;
@@ -860,7 +1016,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
goto out_release_bus;
}
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (ret)
+ goto out_unlock;
offset = 0;
i = 0;
@@ -922,7 +1080,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
for (i = 0; i < NQUEUES; i++)
wilc->txq[i].fw.count += ac_pkt_num_to_chip[i];
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto out_unlock;
ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM);
if (ret)
@@ -931,7 +1091,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
ret = func->hif_block_tx_ext(wilc, 0, txb, offset);
out_release_bus:
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (!ret && rv)
+ ret = rv;
out_unlock:
mutex_unlock(&wilc->txq_add_to_head_cs);
@@ -1060,8 +1222,14 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
void wilc_handle_isr(struct wilc *wilc)
{
u32 int_status;
+ int ret;
+
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret) {
+ dev_err_ratelimited(wilc->dev, "Cannot acquire bus\n");
+ return;
+ }
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
wilc->hif_func->hif_read_int(wilc, &int_status);
if (int_status & DATA_INT_EXT)
@@ -1070,7 +1238,9 @@ void wilc_handle_isr(struct wilc *wilc)
if (!(int_status & (ALL_INT_EXT)))
wilc_unknown_isr_ext(wilc);
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (ret)
+ dev_err_ratelimited(wilc->dev, "Cannot release bus\n");
}
EXPORT_SYMBOL_GPL(wilc_handle_isr);
@@ -1082,6 +1252,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u8 *dma_buffer;
int ret = 0;
u32 reg = 0;
+ int rv;
blksz = BIT(12);
@@ -1092,7 +1263,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
offset = 0;
pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size);
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
reg &= ~BIT(10);
@@ -1101,11 +1274,17 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
if (reg & BIT(10))
pr_err("%s: Failed to reset\n", __func__);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ ret = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (ret)
+ goto fail;
+
do {
addr = get_unaligned_le32(&buffer[offset]);
size = get_unaligned_le32(&buffer[offset + 4]);
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ goto fail;
+
offset += 8;
while (((int)size) && (offset < buffer_size)) {
if (size <= blksz)
@@ -1123,7 +1302,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
offset += size2;
size -= size2;
}
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ if (!ret && rv)
+ ret = rv;
if (ret) {
pr_err("%s Bus error\n", __func__);
@@ -1142,7 +1323,7 @@ fail:
int wilc_wlan_start(struct wilc *wilc)
{
u32 reg = 0;
- int ret;
+ int ret, rv;
u32 chipid;
if (wilc->io_type == WILC_HIF_SDIO) {
@@ -1151,7 +1332,10 @@ int wilc_wlan_start(struct wilc *wilc)
} else if (wilc->io_type == WILC_HIF_SPI) {
reg = 1;
}
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ if (ret)
+ return ret;
+
ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg);
if (ret)
goto release;
@@ -1160,6 +1344,9 @@ int wilc_wlan_start(struct wilc *wilc)
if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num)
reg |= WILC_HAVE_SDIO_IRQ_GPIO;
+ if (is_wilc3000(wilc->chipid))
+ reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC;
+
ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg);
if (ret)
goto release;
@@ -1182,16 +1369,18 @@ int wilc_wlan_start(struct wilc *wilc)
wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, &reg);
release:
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- return ret;
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ return ret ? ret : rv;
}
int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
{
u32 reg = 0;
- int ret;
+ int ret, rv;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, &reg);
if (ret)
@@ -1227,9 +1416,9 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif)
ret = 0;
release:
/* host comm is disabled - we can't issue sleep command anymore: */
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
- return ret;
+ return ret ? ret : rv;
}
void wilc_wlan_cleanup(struct net_device *dev)
@@ -1402,19 +1591,56 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
return ret;
}
+int wilc_get_chipid(struct wilc *wilc)
+{
+ u32 chipid = 0;
+ u32 rfrevid = 0;
+
+ if (wilc->chipid == 0) {
+ wilc->hif_func->hif_read_reg(wilc, WILC3000_CHIP_ID, &chipid);
+ if (!is_wilc3000(chipid)) {
+ wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
+ wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
+ &rfrevid);
+
+ if (!is_wilc1000(chipid)) {
+ wilc->chipid = 0;
+ return -EINVAL;
+ }
+ if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
+ if (rfrevid != 0x1)
+ chipid = WILC_1000_BASE_ID_2A_REV1;
+ } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
+ if (rfrevid == 0x4)
+ chipid = WILC_1000_BASE_ID_2B_REV1;
+ else if (rfrevid != 0x3)
+ chipid = WILC_1000_BASE_ID_2B_REV2;
+ }
+ }
+
+ wilc->chipid = chipid;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wilc_get_chipid);
+
static int init_chip(struct net_device *dev)
{
- u32 chipid;
u32 reg;
- int ret = 0;
+ int ret, rv;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc = vif->wilc;
- acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
- chipid = wilc_get_chipid(wilc, true);
+ ret = wilc_get_chipid(wilc);
+ if (ret)
+ goto release;
- if ((chipid & 0xfff) != 0xa0) {
+ if ((wilc->chipid & 0xfff) != 0xa0) {
ret = wilc->hif_func->hif_read_reg(wilc,
WILC_CORTUS_RESET_MUX_SEL,
&reg);
@@ -1439,46 +1665,35 @@ static int init_chip(struct net_device *dev)
}
}
-release:
- release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
-
- return ret;
-}
-
-u32 wilc_get_chipid(struct wilc *wilc, bool update)
-{
- u32 chipid = 0;
- u32 rfrevid = 0;
-
- if (wilc->chipid == 0 || update) {
- wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
- wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
- &rfrevid);
- if (!is_wilc1000(chipid)) {
- wilc->chipid = 0;
- return wilc->chipid;
- }
- if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
- if (rfrevid != 0x1)
- chipid = WILC_1000_BASE_ID_2A_REV1;
- } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
- if (rfrevid == 0x4)
- chipid = WILC_1000_BASE_ID_2B_REV1;
- else if (rfrevid != 0x3)
- chipid = WILC_1000_BASE_ID_2B_REV2;
+ if (is_wilc3000(wilc->chipid)) {
+ ret = wilc->hif_func->hif_read_reg(wilc, WILC3000_BOOTROM_STATUS, &reg);
+ if (ret) {
+ netdev_err(dev, "failed to read WILC3000 BootROM status register\n");
+ goto release;
}
- wilc->chipid = chipid;
+ ret = wilc->hif_func->hif_write_reg(wilc, WILC3000_CORTUS_BOOT_REGISTER_2,
+ WILC_CORTUS_BOOT_FROM_IRAM);
+ if (ret) {
+ netdev_err(dev, "failed to write WILC3000 Boot register\n");
+ goto release;
+ }
}
- return wilc->chipid;
+
+release:
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
+
+ return ret ? ret : rv;
}
int wilc_load_mac_from_nv(struct wilc *wl)
{
- int ret = -EINVAL;
+ int ret, rv;
unsigned int i;
- acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ ret = acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP);
+ if (ret)
+ return ret;
for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) {
int bank_offset = get_bank_offset_from_bank_index(i);
@@ -1517,14 +1732,14 @@ int wilc_load_mac_from_nv(struct wilc *wl)
break;
}
- release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP);
- return ret;
+ rv = release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP);
+ return ret ? ret : rv;
}
EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv);
int wilc_wlan_init(struct net_device *dev)
{
- int ret = 0;
+ int ret = 0, rv;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wilc;
@@ -1533,11 +1748,26 @@ int wilc_wlan_init(struct net_device *dev)
wilc->quit = 0;
if (!wilc->hif_func->hif_is_init(wilc)) {
- acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
+ if (ret)
+ return ret;
+
ret = wilc->hif_func->hif_init(wilc, false);
- release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (!ret)
+ ret = wilc_get_chipid(wilc);
+ rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY);
+ if (!ret && rv)
+ ret = rv;
if (ret)
goto fail;
+
+ if (!is_wilc1000(wilc->chipid) && !is_wilc3000(wilc->chipid)) {
+ netdev_err(dev, "Unsupported chipid: %x\n", wilc->chipid);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ netdev_dbg(dev, "chipid (%08x)\n", wilc->chipid);
}
if (!wilc->vmm_table)
diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h
index dd2fb3c2f06a..b9e7f9222ead 100644
--- a/drivers/net/wireless/microchip/wilc1000/wlan.h
+++ b/drivers/net/wireless/microchip/wilc1000/wlan.h
@@ -96,8 +96,14 @@
#define WILC_SPI_WAKEUP_REG 0x1
#define WILC_SPI_WAKEUP_BIT BIT(1)
-#define WILC_SPI_CLK_STATUS_REG 0x0f
-#define WILC_SPI_CLK_STATUS_BIT BIT(2)
+/* WILC1000 specific */
+#define WILC1000_SPI_CLK_STATUS_REG 0x0f
+#define WILC1000_SPI_CLK_STATUS_BIT BIT(2)
+
+/* WILC3000 specific */
+#define WILC3000_SPI_CLK_STATUS_REG 0x13
+#define WILC3000_SPI_CLK_STATUS_BIT BIT(2)
+
#define WILC_SPI_HOST_TO_FW_REG 0x0b
#define WILC_SPI_HOST_TO_FW_BIT BIT(0)
@@ -123,14 +129,24 @@
#define WILC_SDIO_WAKEUP_REG 0xf0
#define WILC_SDIO_WAKEUP_BIT BIT(0)
-#define WILC_SDIO_CLK_STATUS_REG 0xf1
-#define WILC_SDIO_CLK_STATUS_BIT BIT(0)
+/* WILC1000 */
+#define WILC1000_SDIO_CLK_STATUS_REG 0xf1
+#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0)
+
+#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7
+#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8
+
+/* WILC3000 specific */
+#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg */
+#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4)
+
+#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1
+#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe
+/* Common vendor specific CCCR register */
#define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */
#define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6
-#define WILC_SDIO_IRQ_FLAG_REG 0xf7
-#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8
#define WILC_SDIO_HOST_TO_FW_REG 0xfa
#define WILC_SDIO_HOST_TO_FW_BIT BIT(0)
@@ -172,8 +188,11 @@
#define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8)
#define WILC_CORTUS_INTERRUPT_BASE 0x10A8
-#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4)
-#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8)
+#define WILC1000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4)
+#define WILC3000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x14)
+
+#define WILC1000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8)
+#define WILC3000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x18)
/* tx control register 1 to 4 for RX */
#define WILC_REG_4_TO_1_RX 0x1e1c
@@ -183,6 +202,9 @@
#define WILC_CORTUS_RESET_MUX_SEL 0x1118
#define WILC_CORTUS_BOOT_REGISTER 0xc0000
+#define WILC3000_BOOTROM_STATUS 0x207ac
+#define WILC3000_CORTUS_BOOT_REGISTER_2 0x4f0000
+#define WILC3000_CHIP_ID 0x3b0000
#define WILC_CORTUS_BOOT_FROM_IRAM 0x71
@@ -195,6 +217,8 @@
#define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1)
#define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2)
+#define WILC_3000_BASE_ID 0x300000
+
#define WILC_CHIP_REV_FIELD GENMASK(11, 0)
/********************************************
@@ -413,6 +437,11 @@ static inline bool is_wilc1000(u32 id)
return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID;
}
+static inline bool is_wilc3000(u32 id)
+{
+ return (id & (~WILC_CHIP_REV_FIELD)) == WILC_3000_BASE_ID;
+}
+
int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer,
u32 buffer_size);
int wilc_wlan_start(struct wilc *wilc);
@@ -436,13 +465,11 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size);
bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size);
-void host_wakeup_notify(struct wilc *wilc);
-void host_sleep_notify(struct wilc *wilc);
-void chip_allow_sleep(struct wilc *wilc);
-void chip_wakeup(struct wilc *wilc);
+int host_wakeup_notify(struct wilc *wilc);
+int host_sleep_notify(struct wilc *wilc);
int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids,
u32 count);
int wilc_wlan_init(struct net_device *dev);
-u32 wilc_get_chipid(struct wilc *wilc, bool update);
+int wilc_get_chipid(struct wilc *wilc);
int wilc_load_mac_from_nv(struct wilc *wilc);
#endif
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index 9540ad6196d7..956c5763662f 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -257,7 +257,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
cmd->beacon_interval = cpu_to_le16(s->beacon_interval);
cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid);
cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout);
- cmd->smps_mode = s->smps_mode;
+ cmd->smps_mode = NL80211_SMPS_OFF;
cmd->p2p_ctwindow = s->p2p_ctwindow;
cmd->p2p_opp_ps = s->p2p_opp_ps;
cmd->pbss = s->pbss;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h
index b204a24074ab..b375a4751580 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.h
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.h
@@ -13,7 +13,6 @@
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <net/sock.h>
-#include <net/lib80211.h>
#include <net/cfg80211.h>
#include <linux/vmalloc.h>
#include <linux/firmware.h>
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index 3bb81bcff0ac..60c2a12e9d5e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3607,7 +3607,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev,
rt2800_rfcsr_write(rt2x00dev, 52, 0x0C);
rt2800_rfcsr_write(rt2x00dev, 54, 0xF8);
if (rf->channel <= 50) {
- rt2800_rfcsr_write(rt2x00dev, 55, 0x06),
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x06);
rt2800_rfcsr_write(rt2x00dev, 56, 0xD3);
} else if (rf->channel >= 52) {
rt2800_rfcsr_write(rt2x00dev, 55, 0x04);
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c
index 7891c988dd5f..f95898f68d68 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
@@ -5058,10 +5058,12 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (bss_conf->enable_beacon)
+ if (bss_conf->enable_beacon) {
rtl8xxxu_start_tx_beacon(priv);
- else
+ schedule_delayed_work(&priv->update_beacon_work, 0);
+ } else {
rtl8xxxu_stop_tx_beacon(priv);
+ }
}
if (changed & BSS_CHANGED_BEACON)
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
index 039bbedb41c2..379193b24428 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -3409,17 +3409,6 @@ void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
}
}
-void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist)
-{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
-
- rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
- "[BTCoex], *****************Coex DM Reset****************\n");
-
- halbtc8723b1ant_init_hw_config(btcoexist, false, false);
- halbtc8723b1ant_init_coex_dm(btcoexist);
-}
-
void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist)
{
struct rtl_priv *rtlpriv = btcoexist->adapter;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h
index 9d41e11388ad..a4506d838dc7 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h
@@ -197,7 +197,6 @@ void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist,
u8 type);
void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist);
void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
-void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist);
void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist);
void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist,
struct seq_file *m);
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index be4c0e60d44d..478cca33e5e3 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -1708,19 +1708,6 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist,
halbtc_normal_low_power(btcoexist);
}
-void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type)
-{
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
-
- if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) {
- } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) {
- if (btcoexist->board_info.btdm_ant_num == 1)
- ex_btc8723b1ant_rf_status_notify(btcoexist, type);
- } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) {
- }
-}
-
void exhalbtc_halt_notify(struct btc_coexist *btcoexist)
{
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -1768,31 +1755,6 @@ void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
}
}
-void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist)
-{
- struct rtl_priv *rtlpriv = btcoexist->adapter;
-
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
- btcoexist->statistics.cnt_coex_dm_switch++;
-
- halbtc_leave_low_power(btcoexist);
-
- if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) {
- if (btcoexist->board_info.btdm_ant_num == 1) {
- btcoexist->stop_coex_dm = true;
- ex_btc8723b1ant_coex_dm_reset(btcoexist);
- exhalbtc_set_ant_num(rtlpriv,
- BT_COEX_ANT_TYPE_DETECTED, 2);
- ex_btc8723b2ant_init_hwconfig(btcoexist);
- ex_btc8723b2ant_init_coex_dm(btcoexist);
- btcoexist->stop_coex_dm = false;
- }
- }
-
- halbtc_normal_low_power(btcoexist);
-}
-
void exhalbtc_periodical(struct btc_coexist *btcoexist)
{
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -1820,29 +1782,6 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist)
halbtc_normal_low_power(btcoexist);
}
-void exhalbtc_dbg_control(struct btc_coexist *btcoexist,
- u8 code, u8 len, u8 *data)
-{
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
- btcoexist->statistics.cnt_dbg_ctrl++;
-
- halbtc_leave_low_power(btcoexist);
-
- halbtc_normal_low_power(btcoexist);
-}
-
-void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq,
- u32 offset, u32 span, u32 seconds)
-{
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
-}
-
-void exhalbtc_stack_update_profile_info(void)
-{
-}
-
void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi)
{
if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -1851,24 +1790,6 @@ void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi)
btcoexist->stack_info.min_bt_rssi = bt_rssi;
}
-void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version)
-{
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
-
- btcoexist->stack_info.hci_version = hci_version;
-}
-
-void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist,
- u16 bt_hci_version, u16 bt_patch_version)
-{
- if (!halbtc_is_bt_coexist_available(btcoexist))
- return;
-
- btcoexist->bt_info.bt_real_fw_ver = bt_patch_version;
- btcoexist->bt_info.bt_hci_ver = bt_hci_version;
-}
-
void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type)
{
switch (chip_type) {
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
index a96a995dd850..d8d88a989806 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -763,19 +763,9 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
u8 length);
-void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type);
void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
-void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
void exhalbtc_periodical(struct btc_coexist *btcoexist);
-void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
- u8 *data);
-void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq,
- u32 offset, u32 span, u32 seconds);
-void exhalbtc_stack_update_profile_info(void);
-void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version);
-void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist,
- u16 bt_hci_version, u16 bt_patch_version);
void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi);
void exhalbtc_set_bt_exist(struct btc_coexist *btcoexist, bool bt_exist);
void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type);
diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c
index 82cf5fb5175f..6518e77b89f5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/efuse.c
+++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c
@@ -162,10 +162,19 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 max_attempts = 10000;
u32 value32;
u8 readbyte;
u16 retry;
+ /*
+ * In case of USB devices, transfer speeds are limited, hence
+ * efuse I/O reads could be (way) slower. So, decrease (a lot)
+ * the read attempts in case of failures.
+ */
+ if (rtlpriv->rtlhal.interface == INTF_USB)
+ max_attempts = 10;
+
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
(_offset & 0xff));
readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2);
@@ -178,7 +187,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
retry = 0;
value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
- while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {
+ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < max_attempts)) {
value32 = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[EFUSE_CTRL]);
retry++;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192du/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192du/sw.c
index d069a81ac617..cc699efa9c79 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192du/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192du/sw.c
@@ -352,7 +352,6 @@ static const struct usb_device_id rtl8192d_usb_ids[] = {
{RTL_USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8194, rtl92du_hal_cfg)},
{RTL_USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8111, rtl92du_hal_cfg)},
{RTL_USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x0193, rtl92du_hal_cfg)},
- {RTL_USB_DEVICE(USB_VENDOR_ID_REALTEK, 0x8171, rtl92du_hal_cfg)},
{RTL_USB_DEVICE(USB_VENDOR_ID_REALTEK, 0xe194, rtl92du_hal_cfg)},
{RTL_USB_DEVICE(0x2019, 0xab2c, rtl92du_hal_cfg)},
{RTL_USB_DEVICE(0x2019, 0xab2d, rtl92du_hal_cfg)},
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
index 1b144fbd4d26..048744166a92 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
@@ -350,7 +350,8 @@ MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless");
-MODULE_FIRMWARE("rtlwifi/rtl8723efw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723fw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723fw_B.bin");
module_param_named(swenc, rtl8723e_mod_params.sw_crypto, bool, 0444);
module_param_named(debug_level, rtl8723e_mod_params.debug_level, int, 0644);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
index 0e77de1baaf8..bcfc53af4c1a 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
@@ -2040,31 +2040,33 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- int params[] = {RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID,
- EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR,
- EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID,
- COUNTRY_CODE_WORLD_WIDE_13};
+ static const int params[] = {
+ RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID,
+ EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR,
+ EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID,
+ COUNTRY_CODE_WORLD_WIDE_13
+ };
u8 *hwinfo;
int i;
bool is_toshiba_smid1 = false;
bool is_toshiba_smid2 = false;
bool is_samsung_smid = false;
bool is_lenovo_smid = false;
- u16 toshiba_smid1[] = {
+ static const u16 toshiba_smid1[] = {
0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180,
0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180,
0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185,
0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185
};
- u16 toshiba_smid2[] = {
+ static const u16 toshiba_smid2[] = {
0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181,
0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185
};
- u16 samsung_smid[] = {
+ static const u16 samsung_smid[] = {
0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192,
0x8193, 0x9191, 0x9192, 0x9193
};
- u16 lenovo_smid[] = {
+ static const u16 lenovo_smid[] = {
0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200
};
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
index a65503c5ae5a..b5266e560416 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
@@ -407,6 +407,9 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 8821ae 802.11ac PCI wireless");
MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin");
MODULE_FIRMWARE("rtlwifi/rtl8821aefw_29.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8821aefw_wowlan.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8812aefw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8812aefw_wowlan.bin");
module_param_named(swenc, rtl8821ae_mod_params.sw_crypto, bool, 0444);
module_param_named(debug_level, rtl8821ae_mod_params.debug_level, int, 0644);
diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig
index 02b0d698413b..733b3e58da51 100644
--- a/drivers/net/wireless/realtek/rtw88/Kconfig
+++ b/drivers/net/wireless/realtek/rtw88/Kconfig
@@ -43,6 +43,17 @@ config RTW88_8723D
config RTW88_8821C
tristate
+config RTW88_88XXA
+ tristate
+
+config RTW88_8821A
+ tristate
+ select RTW88_88XXA
+
+config RTW88_8812A
+ tristate
+ select RTW88_88XXA
+
config RTW88_8822BE
tristate "Realtek 8822BE PCI wireless network adapter"
depends on PCI
@@ -189,6 +200,28 @@ config RTW88_8821CU
802.11ac USB wireless network adapter
+config RTW88_8821AU
+ tristate "Realtek 8821AU/8811AU USB wireless network adapter"
+ depends on USB
+ select RTW88_CORE
+ select RTW88_USB
+ select RTW88_8821A
+ help
+ Select this option will enable support for 8821AU and 8811AU chipset
+
+ 802.11ac USB wireless network adapter
+
+config RTW88_8812AU
+ tristate "Realtek 8812AU USB wireless network adapter"
+ depends on USB
+ select RTW88_CORE
+ select RTW88_USB
+ select RTW88_8812A
+ help
+ Select this option will enable support for 8812AU chipset
+
+ 802.11ac USB wireless network adapter
+
config RTW88_DEBUG
bool "Realtek rtw88 debug support"
depends on RTW88_CORE
diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile
index 8f47359b4380..f0b49f5a8a5a 100644
--- a/drivers/net/wireless/realtek/rtw88/Makefile
+++ b/drivers/net/wireless/realtek/rtw88/Makefile
@@ -77,6 +77,21 @@ rtw88_8821cs-objs := rtw8821cs.o
obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o
rtw88_8821cu-objs := rtw8821cu.o
+obj-$(CONFIG_RTW88_88XXA) += rtw88_88xxa.o
+rtw88_88xxa-objs := rtw88xxa.o
+
+obj-$(CONFIG_RTW88_8821A) += rtw88_8821a.o
+rtw88_8821a-objs := rtw8821a.o rtw8821a_table.o
+
+obj-$(CONFIG_RTW88_8812A) += rtw88_8812a.o
+rtw88_8812a-objs := rtw8812a.o rtw8812a_table.o
+
+obj-$(CONFIG_RTW88_8821AU) += rtw88_8821au.o
+rtw88_8821au-objs := rtw8821au.o
+
+obj-$(CONFIG_RTW88_8812AU) += rtw88_8812au.o
+rtw88_8812au-objs := rtw8812au.o
+
obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o
rtw88_pci-objs := pci.o
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index a99776af56c2..c929db1e53ca 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.c
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -446,7 +446,7 @@ static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
}
}
-static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
+void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
@@ -494,11 +494,29 @@ static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm;
bool bt_disabled = false;
+ bool bt_active = true;
u16 score_board;
if (chip->scbd_support) {
score_board = rtw_coex_read_scbd(rtwdev);
bt_disabled = !(score_board & COEX_SCBD_ONOFF);
+ } else {
+ if (coex_stat->hi_pri_tx == 0 && coex_stat->hi_pri_rx == 0 &&
+ coex_stat->lo_pri_tx == 0 && coex_stat->lo_pri_rx == 0)
+ bt_active = false;
+
+ if (coex_stat->hi_pri_tx == 0xffff && coex_stat->hi_pri_rx == 0xffff &&
+ coex_stat->lo_pri_tx == 0xffff && coex_stat->lo_pri_rx == 0xffff)
+ bt_active = false;
+
+ if (bt_active) {
+ coex_stat->bt_disable_cnt = 0;
+ bt_disabled = false;
+ } else {
+ coex_stat->bt_disable_cnt++;
+ if (coex_stat->bt_disable_cnt >= 10)
+ bt_disabled = true;
+ }
}
if (coex_stat->bt_disabled != bt_disabled) {
@@ -950,12 +968,18 @@ static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)
{
+ if (!rtwdev->chip->ltecoex_addr)
+ return;
+
rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state);
rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state);
}
static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
{
+ if (!rtwdev->chip->ltecoex_addr)
+ return;
+
rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state);
rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);
}
@@ -2747,16 +2771,19 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)
rtw_write8(rtwdev, 0xff1a, 0x0);
rtw_coex_set_gnt_debug(rtwdev);
}
+EXPORT_SYMBOL(rtw_coex_power_on_setting);
void rtw_coex_power_off_setting(struct rtw_dev *rtwdev)
{
rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN);
}
+EXPORT_SYMBOL(rtw_coex_power_off_setting);
void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)
{
__rtw_coex_init_hw_config(rtwdev, wifi_only);
}
+EXPORT_SYMBOL(rtw_coex_init_hw_config);
void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)
{
@@ -3904,7 +3931,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
u8 sys_lte;
u16 score_board_WB, score_board_BW;
u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc;
- u32 lte_coex, bt_coex;
+ u32 lte_coex = 0, bt_coex = 0;
int i;
score_board_BW = rtw_coex_read_scbd(rtwdev);
@@ -3916,8 +3943,10 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL);
sys_lte = rtw_read8(rtwdev, 0x73);
- lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
- bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
+ if (rtwdev->chip->ltecoex_addr) {
+ lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
+ bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
+ }
if (!coex_stat->wl_under_ips &&
(!coex_stat->wl_under_lps || coex_stat->wl_force_lps_ctrl) &&
diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h
index 57cf29da9ea4..c398be8391f7 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.h
+++ b/drivers/net/wireless/realtek/rtw88/coex.h
@@ -384,6 +384,7 @@ u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr);
void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,
u32 mask, u32 val);
void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set);
+void rtw_coex_query_bt_info(struct rtw_dev *rtwdev);
void rtw_coex_bt_relink_work(struct work_struct *work);
void rtw_coex_bt_reenable_work(struct work_struct *work);
@@ -419,4 +420,14 @@ static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev)
return coex_stat->bt_disabled;
}
+static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev)
+{
+ /* The RTL8821AU firmware doesn't send C2H_BT_INFO by itself
+ * when bluetooth headphones are disconnected, so we have to
+ * ask for it regularly.
+ */
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A && rtwdev->efuse.btcoex)
+ rtw_coex_query_bt_info(rtwdev);
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index c26a6905fd15..364ec0436d0f 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -308,7 +308,7 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v)
{
struct rtw_debugfs_priv *debugfs_priv = m->private;
struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
- u8 page_size = rtwdev->chip->page_size;
+ u16 page_size = rtwdev->chip->page_size;
u32 buf_size = debugfs_priv->rsvd_page.page_num * page_size;
u32 offset = debugfs_priv->rsvd_page.page_offset * page_size;
u8 *buf;
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index b9b0114e253b..e6e9946fbf44 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -139,25 +139,30 @@ static u16 get_max_amsdu_len(u32 bit_rate)
struct rtw_fw_iter_ra_data {
struct rtw_dev *rtwdev;
u8 *payload;
+ u8 length;
};
static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw_fw_iter_ra_data *ra_data = data;
+ struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)ra_data->payload;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
u8 mac_id, rate, sgi, bw;
u8 mcs, nss;
u32 bit_rate;
- mac_id = GET_RA_REPORT_MACID(ra_data->payload);
+ mac_id = ra_rpt->mac_id;
if (si->mac_id != mac_id)
return;
si->ra_report.txrate.flags = 0;
- rate = GET_RA_REPORT_RATE(ra_data->payload);
- sgi = GET_RA_REPORT_SGI(ra_data->payload);
- bw = GET_RA_REPORT_BW(ra_data->payload);
+ rate = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_RATE);
+ sgi = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_SGI);
+ if (ra_data->length >= offsetofend(typeof(*ra_rpt), bw))
+ bw = ra_rpt->bw;
+ else
+ bw = si->bw_mode;
if (rate < DESC_RATEMCS0) {
si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate);
@@ -197,14 +202,18 @@ legacy:
static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload,
u8 length)
{
+ struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)payload;
struct rtw_fw_iter_ra_data ra_data;
- if (WARN(length < 7, "invalid ra report c2h length\n"))
+ if (WARN(length < rtwdev->chip->c2h_ra_report_size,
+ "invalid ra report c2h length %d\n", length))
return;
- rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload);
+ rtwdev->dm_info.tx_rate = u8_get_bits(ra_rpt->rate_sgi,
+ RTW_C2H_RA_RPT_RATE);
ra_data.rtwdev = rtwdev;
ra_data.payload = payload;
+ ra_data.length = length;
rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data);
}
@@ -267,7 +276,7 @@ static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload,
static void rtw_fw_adaptivity_result(struct rtw_dev *rtwdev, u8 *payload,
u8 length)
{
- struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th;
+ const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th;
struct rtw_c2h_adaptivity *result = (struct rtw_c2h_adaptivity *)payload;
rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY,
@@ -1281,16 +1290,16 @@ static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb,
rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type);
pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
- rtw_tx_fill_tx_desc(&pkt_info, skb);
+ rtw_tx_fill_tx_desc(rtwdev, &pkt_info, skb);
}
-static inline u8 rtw_len_to_page(unsigned int len, u8 page_size)
+static inline u8 rtw_len_to_page(unsigned int len, u16 page_size)
{
return DIV_ROUND_UP(len, page_size);
}
-static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size,
- u8 page_margin, u32 page, u8 *buf,
+static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u16 page_size,
+ u16 page_margin, u32 page, u8 *buf,
struct rtw_rsvd_page *rsvd_pkt)
{
struct sk_buff *skb = rsvd_pkt->skb;
@@ -1592,13 +1601,13 @@ static int __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev)
static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size)
{
- struct ieee80211_hw *hw = rtwdev->hw;
const struct rtw_chip_info *chip = rtwdev->chip;
- struct sk_buff *iter;
+ struct ieee80211_hw *hw = rtwdev->hw;
struct rtw_rsvd_page *rsvd_pkt;
- u32 page = 0;
+ struct sk_buff *iter;
+ u16 page_size, page_margin, tx_desc_sz;
u8 total_page = 0;
- u8 page_size, page_margin, tx_desc_sz;
+ u32 page = 0;
u8 *buf;
int ret;
@@ -2004,12 +2013,13 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_probes,
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb, *tmp;
- u8 page_offset = 1, *buf, page_size = chip->page_size;
u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc;
- u16 buf_offset = page_size * page_offset;
u8 tx_desc_sz = chip->tx_pkt_desc_sz;
- u8 page_cnt, pages;
+ u16 page_size = chip->page_size;
+ u8 page_offset = 1, *buf;
+ u16 buf_offset = page_size * page_offset;
unsigned int pkt_len;
+ u8 page_cnt, pages;
int ret;
if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM))
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
index e999c24e4634..404de1b0c407 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.h
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
@@ -85,6 +85,19 @@ struct rtw_c2h_adaptivity {
u8 option;
} __packed;
+struct rtw_c2h_ra_rpt {
+ u8 rate_sgi;
+ u8 mac_id;
+ u8 byte2;
+ u8 status;
+ u8 byte4;
+ u8 ra_ratio;
+ u8 bw;
+} __packed;
+
+#define RTW_C2H_RA_RPT_RATE GENMASK(6, 0)
+#define RTW_C2H_RA_RPT_SGI BIT(7)
+
struct rtw_h2c_register {
u32 w0;
u32 w1;
@@ -364,10 +377,6 @@ struct rtw_fw_hdr_legacy {
#define GET_CHAN_SWITCH_CENTRAL_CH(c2h_payload) (c2h_payload[2])
#define GET_CHAN_SWITCH_ID(c2h_payload) (c2h_payload[3])
#define GET_CHAN_SWITCH_STATUS(c2h_payload) (c2h_payload[4])
-#define GET_RA_REPORT_RATE(c2h_payload) (c2h_payload[0] & 0x7f)
-#define GET_RA_REPORT_SGI(c2h_payload) ((c2h_payload[0] & 0x80) >> 7)
-#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6])
-#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1])
#define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf)
#define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10)
diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c
index 564f5988ee82..cae9cca6dca3 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.c
+++ b/drivers/net/wireless/realtek/rtw88/mac.c
@@ -227,8 +227,8 @@ static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask,
return 0;
}
-static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
- const struct rtw_pwr_seq_cmd **cmd_seq)
+int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
+ const struct rtw_pwr_seq_cmd * const *cmd_seq)
{
u8 cut_mask;
u8 intf_mask;
@@ -267,11 +267,12 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
return 0;
}
+EXPORT_SYMBOL(rtw_pwr_seq_parser);
static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
{
const struct rtw_chip_info *chip = rtwdev->chip;
- const struct rtw_pwr_seq_cmd **pwr_seq;
+ const struct rtw_pwr_seq_cmd * const *pwr_seq;
u32 imr = 0;
u8 rpwm;
bool cur_pwr;
@@ -994,6 +995,7 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
return 0;
}
+EXPORT_SYMBOL(rtw_download_firmware);
static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues)
{
@@ -1127,7 +1129,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
return 0;
}
-static int set_trx_fifo_info(struct rtw_dev *rtwdev)
+int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo;
@@ -1136,7 +1138,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev)
/* config rsvd page num */
fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num;
- fifo->txff_pg_num = chip->txff_size >> 7;
+ fifo->txff_pg_num = chip->txff_size / chip->page_size;
if (rtw_chip_wcpu_11n(rtwdev))
fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num;
else
@@ -1179,6 +1181,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev)
return 0;
}
+EXPORT_SYMBOL(rtw_set_trx_fifo_info);
static int __priority_queue_cfg(struct rtw_dev *rtwdev,
const struct rtw_page_table *pg_tbl,
@@ -1256,7 +1259,7 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev)
u16 pubq_num;
int ret;
- ret = set_trx_fifo_info(rtwdev);
+ ret = rtw_set_trx_fifo_info(rtwdev);
if (ret)
return ret;
diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h
index 58c3dccc14bb..6905e2747372 100644
--- a/drivers/net/wireless/realtek/rtw88/mac.h
+++ b/drivers/net/wireless/realtek/rtw88/mac.h
@@ -30,11 +30,14 @@
void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_ch_idx);
+int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
+ const struct rtw_pwr_seq_cmd * const *cmd_seq);
int rtw_mac_power_on(struct rtw_dev *rtwdev);
void rtw_mac_power_off(struct rtw_dev *rtwdev);
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
int rtw_mac_init(struct rtw_dev *rtwdev);
void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);
+int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev);
int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size);
static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop)
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index b39e90fb66b4..026fbf4ad9cc 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -928,8 +928,10 @@ static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw,
static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, u32 changed)
+ struct ieee80211_link_sta *link_sta,
+ u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct rtw_dev *rtwdev = hw->priv;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
@@ -973,7 +975,7 @@ const struct ieee80211_ops rtw_ops = {
.reconfig_complete = rtw_reconfig_complete,
.hw_scan = rtw_ops_hw_scan,
.cancel_hw_scan = rtw_ops_cancel_hw_scan,
- .sta_rc_update = rtw_ops_sta_rc_update,
+ .link_sta_rc_update = rtw_ops_sta_rc_update,
.set_sar_specs = rtw_ops_set_sar_specs,
#ifdef CONFIG_PM
.suspend = rtw_ops_suspend,
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index bbdef38c7e34..e91530ed05a0 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -202,6 +202,21 @@ static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif)
rtwvif->stats.rx_cnt = 0;
}
+static void rtw_sw_beacon_loss_check(struct rtw_dev *rtwdev,
+ struct rtw_vif *rtwvif, int received_beacons)
+{
+ int watchdog_delay = 2000000 / 1024; /* TU */
+ int beacon_int, expected_beacons;
+
+ if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !rtwvif)
+ return;
+
+ beacon_int = rtwvif_to_vif(rtwvif)->bss_conf.beacon_int;
+ expected_beacons = DIV_ROUND_UP(watchdog_delay, beacon_int);
+
+ rtwdev->beacon_loss = received_beacons < expected_beacons / 2;
+}
+
/* process TX/RX statistics periodically for hardware,
* the information helps hardware to enhance performance
*/
@@ -212,6 +227,7 @@ static void rtw_watch_dog_work(struct work_struct *work)
struct rtw_traffic_stats *stats = &rtwdev->stats;
struct rtw_watch_dog_iter_data data = {};
bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);
+ int received_beacons = rtwdev->dm_info.cur_pkt_count.num_bcn_pkt;
u32 tx_unicast_mbps, rx_unicast_mbps;
bool ps_active;
@@ -258,6 +274,7 @@ static void rtw_watch_dog_work(struct work_struct *work)
rtw_leave_lps(rtwdev);
rtw_coex_wl_status_check(rtwdev);
rtw_coex_query_bt_hid_list(rtwdev);
+ rtw_coex_active_query_bt_info(rtwdev);
rtw_phy_dynamic_mechanism(rtwdev);
@@ -270,6 +287,8 @@ static void rtw_watch_dog_work(struct work_struct *work)
*/
rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data);
+ rtw_sw_beacon_loss_check(rtwdev, data.rtwvif, received_beacons);
+
/* fw supports only one station associated to enter lps, if there are
* more than two stations associated to the AP, then we can not enter
* lps, because fw does not handle the overlapped beacon interval
@@ -1309,7 +1328,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask);
}
-static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev)
+int rtw_wait_firmware_completion(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fw_state *fw;
@@ -1329,6 +1348,7 @@ static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev)
return ret;
}
+EXPORT_SYMBOL(rtw_wait_firmware_completion);
static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev,
struct rtw_fw_state *fw)
@@ -1350,7 +1370,7 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev,
return LPS_DEEP_MODE_NONE;
}
-static int rtw_power_on(struct rtw_dev *rtwdev)
+int rtw_power_on(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fw_state *fw = &rtwdev->fw;
@@ -1413,6 +1433,7 @@ err_off:
err:
return ret;
}
+EXPORT_SYMBOL(rtw_power_on);
void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start)
{
@@ -1485,7 +1506,7 @@ int rtw_core_start(struct rtw_dev *rtwdev)
{
int ret;
- ret = rtw_power_on(rtwdev);
+ ret = rtwdev->chip->ops->power_on(rtwdev);
if (ret)
return ret;
@@ -1505,12 +1526,13 @@ int rtw_core_start(struct rtw_dev *rtwdev)
return 0;
}
-static void rtw_power_off(struct rtw_dev *rtwdev)
+void rtw_power_off(struct rtw_dev *rtwdev)
{
rtw_hci_stop(rtwdev);
rtw_coex_power_off_setting(rtwdev);
rtw_mac_power_off(rtwdev);
}
+EXPORT_SYMBOL(rtw_power_off);
void rtw_core_stop(struct rtw_dev *rtwdev)
{
@@ -1535,7 +1557,7 @@ void rtw_core_stop(struct rtw_dev *rtwdev)
mutex_lock(&rtwdev->mutex);
- rtw_power_off(rtwdev);
+ rtwdev->chip->ops->power_off(rtwdev);
}
static void rtw_init_ht_cap(struct rtw_dev *rtwdev,
@@ -1917,6 +1939,9 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev)
u8 bw;
int i;
+ if (!rtwdev->chip->hw_feature_report)
+ return 0;
+
id = rtw_read8(rtwdev, REG_C2HEVT);
if (id != C2H_HW_FEATURE_REPORT) {
rtw_err(rtwdev, "failed to read hw feature report\n");
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 945117afe143..cd09fb6f7b8b 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -189,6 +189,8 @@ enum rtw_chip_type {
RTW_CHIP_TYPE_8723D,
RTW_CHIP_TYPE_8821C,
RTW_CHIP_TYPE_8703B,
+ RTW_CHIP_TYPE_8821A,
+ RTW_CHIP_TYPE_8812A,
};
enum rtw_tx_queue_type {
@@ -841,6 +843,8 @@ struct rtw_regd {
};
struct rtw_chip_ops {
+ int (*power_on)(struct rtw_dev *rtwdev);
+ void (*power_off)(struct rtw_dev *rtwdev);
int (*mac_init)(struct rtw_dev *rtwdev);
int (*dump_fw_crash)(struct rtw_dev *rtwdev);
void (*shutdown)(struct rtw_dev *rtwdev);
@@ -848,9 +852,8 @@ struct rtw_chip_ops {
void (*phy_set_param)(struct rtw_dev *rtwdev);
void (*set_channel)(struct rtw_dev *rtwdev, u8 channel,
u8 bandwidth, u8 primary_chan_idx);
- void (*query_rx_desc)(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status);
+ void (*query_phy_status)(struct rtw_dev *rtwdev, u8 *phy_status,
+ struct rtw_rx_pkt_stat *pkt_stat);
u32 (*read_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask);
bool (*write_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
@@ -1096,17 +1099,20 @@ enum rtw_rfe_fem {
struct rtw_rfe_def {
const struct rtw_table *phy_pg_tbl;
const struct rtw_table *txpwr_lmt_tbl;
+ const struct rtw_pwr_track_tbl *pwr_track_tbl;
const struct rtw_table *agc_btg_tbl;
};
-#define RTW_DEF_RFE(chip, bb_pg, pwrlmt) { \
+#define RTW_DEF_RFE(chip, bb_pg, pwrlmt, track) { \
.phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \
.txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \
+ .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \
}
-#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, btg) { \
+#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, track, btg) { \
.phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \
.txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \
+ .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \
.agc_btg_tbl = &rtw ## chip ## _agc_btg_type ## btg ## _tbl, \
}
@@ -1167,7 +1173,7 @@ enum rtw_fwcd_item {
/* hardware configuration for each IC */
struct rtw_chip_info {
- struct rtw_chip_ops *ops;
+ const struct rtw_chip_ops *ops;
u8 id;
const char *fw_name;
@@ -1184,7 +1190,7 @@ struct rtw_chip_info {
u32 fw_rxff_size;
u16 rsvd_drv_pg_num;
u8 band;
- u8 page_size;
+ u16 page_size;
u8 csi_buf_pg_num;
u8 dig_max;
u8 dig_min;
@@ -1199,6 +1205,9 @@ struct rtw_chip_info {
const struct rtw_fwcd_segs *fwcd_segs;
u8 usb_tx_agg_desc_num;
+ bool hw_feature_report;
+ u8 c2h_ra_report_size;
+ bool old_datarate_fb_limit;
u8 default_1ss_tx_path;
@@ -1209,8 +1218,8 @@ struct rtw_chip_info {
/* init values */
u8 sys_func_en;
- const struct rtw_pwr_seq_cmd **pwr_on_seq;
- const struct rtw_pwr_seq_cmd **pwr_off_seq;
+ const struct rtw_pwr_seq_cmd * const *pwr_on_seq;
+ const struct rtw_pwr_seq_cmd * const *pwr_off_seq;
const struct rtw_rqpn *rqpn_table;
const struct rtw_prioq_addrs *prioq_addrs;
const struct rtw_page_table *page_table;
@@ -1237,12 +1246,11 @@ struct rtw_chip_info {
u16 dpd_ratemask;
u8 iqk_threshold;
u8 lck_threshold;
- const struct rtw_pwr_track_tbl *pwr_track_tbl;
u8 bfer_su_max_num;
u8 bfer_mu_max_num;
- struct rtw_hw_reg_offset *edcca_th;
+ const struct rtw_hw_reg_offset *edcca_th;
s8 l2h_th_ini_cs;
s8 l2h_th_ini_ad;
@@ -1486,6 +1494,7 @@ struct rtw_coex_stat {
u8 bt_hid_slot;
u8 bt_a2dp_bitpool;
u8 bt_iqk_state;
+ u8 bt_disable_cnt;
u16 wl_beacon_interval;
u8 wl_noisy_level;
@@ -1709,7 +1718,7 @@ struct rtw_dm_info {
bool pwr_trk_init_trigger;
struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX];
s8 txagc_remnant_cck;
- s8 txagc_remnant_ofdm;
+ s8 txagc_remnant_ofdm[RTW_RF_PATH_MAX];
u8 rx_cck_agc_report_type;
/* backup dack results for each path and I/Q */
@@ -1832,6 +1841,20 @@ struct rtw_phy_cond {
#define BRANCH_ENDIF 3
};
+struct rtw_phy_cond2 {
+#ifdef __LITTLE_ENDIAN
+ u8 type_glna;
+ u8 type_gpa;
+ u8 type_alna;
+ u8 type_apa;
+#else
+ u8 type_apa;
+ u8 type_alna;
+ u8 type_gpa;
+ u8 type_glna;
+#endif
+};
+
struct rtw_fifo_conf {
/* tx fifo information */
u16 rsvd_boundary;
@@ -1913,6 +1936,7 @@ struct rtw_hal {
u8 oem_id;
u8 pkg_type;
struct rtw_phy_cond phy_cond;
+ struct rtw_phy_cond2 phy_cond2;
bool rfe_btg;
u8 ps_mode;
@@ -1935,6 +1959,7 @@ struct rtw_hal {
u32 antenna_rx;
u8 bfee_sts_cap;
bool txrx_1ss;
+ bool cck_high_power;
/* protect tx power section */
struct mutex tx_power_mutex;
@@ -2190,6 +2215,7 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool hw_scan);
int rtw_core_start(struct rtw_dev *rtwdev);
+void rtw_power_off(struct rtw_dev *rtwdev);
void rtw_core_stop(struct rtw_dev *rtwdev);
int rtw_chip_info_setup(struct rtw_dev *rtwdev);
int rtw_core_init(struct rtw_dev *rtwdev);
@@ -2204,6 +2230,8 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
bool fw_exist);
void rtw_fw_recovery(struct rtw_dev *rtwdev);
+int rtw_wait_firmware_completion(struct rtw_dev *rtwdev);
+int rtw_power_on(struct rtw_dev *rtwdev);
void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
u32 fwcd_item);
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 0b9b8807af2c..0ecaefc4c83d 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -824,7 +824,7 @@ static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev,
pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
memset(pkt_desc, 0, tx_pkt_desc_sz);
pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue);
- rtw_tx_fill_tx_desc(pkt_info, skb);
+ rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb);
dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
if (dma_mapping_error(&rtwpci->pdev->dev, dma))
@@ -1065,7 +1065,7 @@ static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE,
DMA_FROM_DEVICE);
rx_desc = skb->data;
- chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
+ rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
/* offset from rx_desc to payload */
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c
index 37ef80c9091d..8ed20c89d216 100644
--- a/drivers/net/wireless/realtek/rtw88/phy.c
+++ b/drivers/net/wireless/realtek/rtw88/phy.c
@@ -18,7 +18,10 @@ struct phy_cfg_pair {
};
union phy_table_tile {
- struct rtw_phy_cond cond;
+ struct {
+ struct rtw_phy_cond cond;
+ struct rtw_phy_cond2 cond2;
+ } __packed;
struct phy_cfg_pair cfg;
};
@@ -123,7 +126,7 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev)
void rtw_phy_set_edcca_th(struct rtw_dev *rtwdev, u8 l2h, u8 h2l)
{
- struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th;
+ const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th;
rtw_write32_mask(rtwdev,
edcca_th[EDCCA_TH_L2H_IDX].hw_reg.addr,
@@ -527,6 +530,13 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev)
*/
rtw_phy_dig_recorder(dm_info, cur_igi, fa_cnt);
+ /* Mitigate beacon loss and connectivity issues, mainly (only?)
+ * in the 5 GHz band
+ */
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A && rtwdev->beacon_loss &&
+ linked && dm_info->total_fa_cnt < DIG_PERF_FA_TH_EXTRA_HIGH)
+ cur_igi = DIG_CVRG_MIN;
+
if (cur_igi != pre_igi)
rtw_phy_dig_write(rtwdev, cur_igi);
}
@@ -1041,7 +1051,8 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg)
{
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_efuse *efuse = &rtwdev->efuse;
- struct rtw_phy_cond cond = {0};
+ struct rtw_phy_cond cond = {};
+ struct rtw_phy_cond2 cond2 = {};
cond.cut = hal->cut_version ? hal->cut_version : 15;
cond.pkg = pkg ? pkg : 15;
@@ -1061,15 +1072,34 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg)
break;
}
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A ||
+ rtwdev->chip->id == RTW_CHIP_TYPE_8821A) {
+ cond.rfe = 0;
+ cond.rfe |= efuse->ext_lna_2g;
+ cond.rfe |= efuse->ext_pa_2g << 1;
+ cond.rfe |= efuse->ext_lna_5g << 2;
+ cond.rfe |= efuse->ext_pa_5g << 3;
+ cond.rfe |= efuse->btcoex << 4;
+
+ cond2.type_alna = efuse->alna_type;
+ cond2.type_glna = efuse->glna_type;
+ cond2.type_apa = efuse->apa_type;
+ cond2.type_gpa = efuse->gpa_type;
+ }
+
hal->phy_cond = cond;
+ hal->phy_cond2 = cond2;
- rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x\n", *((u32 *)&hal->phy_cond));
+ rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x cond2=0x%08x\n",
+ *((u32 *)&hal->phy_cond), *((u32 *)&hal->phy_cond2));
}
-static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond)
+static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond,
+ struct rtw_phy_cond2 cond2)
{
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_phy_cond drv_cond = hal->phy_cond;
+ struct rtw_phy_cond2 drv_cond2 = hal->phy_cond2;
if (cond.cut && cond.cut != drv_cond.cut)
return false;
@@ -1080,8 +1110,29 @@ static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond)
if (cond.intf && cond.intf != drv_cond.intf)
return false;
- if (cond.rfe != drv_cond.rfe)
- return false;
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A ||
+ rtwdev->chip->id == RTW_CHIP_TYPE_8821A) {
+ if (!(cond.rfe & 0x0f))
+ return true;
+
+ if ((cond.rfe & drv_cond.rfe) != cond.rfe)
+ return false;
+
+ if ((cond.rfe & BIT(0)) && cond2.type_glna != drv_cond2.type_glna)
+ return false;
+
+ if ((cond.rfe & BIT(1)) && cond2.type_gpa != drv_cond2.type_gpa)
+ return false;
+
+ if ((cond.rfe & BIT(2)) && cond2.type_alna != drv_cond2.type_alna)
+ return false;
+
+ if ((cond.rfe & BIT(3)) && cond2.type_apa != drv_cond2.type_apa)
+ return false;
+ } else {
+ if (cond.rfe != drv_cond.rfe)
+ return false;
+ }
return true;
}
@@ -1090,7 +1141,8 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
{
const union phy_table_tile *p = tbl->data;
const union phy_table_tile *end = p + tbl->size / 2;
- struct rtw_phy_cond pos_cond = {0};
+ struct rtw_phy_cond pos_cond = {};
+ struct rtw_phy_cond2 pos_cond2 = {};
bool is_matched = true, is_skipped = false;
BUILD_BUG_ON(sizeof(union phy_table_tile) != sizeof(struct phy_cfg_pair));
@@ -1109,11 +1161,12 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl)
case BRANCH_ELIF:
default:
pos_cond = p->cond;
+ pos_cond2 = p->cond2;
break;
}
} else if (p->cond.neg) {
if (!is_skipped) {
- if (check_positive(rtwdev, pos_cond)) {
+ if (check_positive(rtwdev, pos_cond, pos_cond2)) {
is_matched = true;
is_skipped = true;
} else {
@@ -1470,10 +1523,8 @@ static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev,
rate = rates[i];
if (band == PHY_BAND_2G)
hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset;
- else if (band == PHY_BAND_5G)
- hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
else
- continue;
+ hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset;
}
}
@@ -2125,8 +2176,8 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw,
*limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path,
rate, ch, regd);
- *remnant = (rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck :
- dm_info->txagc_remnant_ofdm);
+ *remnant = rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck :
+ dm_info->txagc_remnant_ofdm[path];
*sar = rtw_phy_get_tx_power_sar(rtwdev, hal->sar_band, path, rate);
}
@@ -2340,7 +2391,8 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev)
void rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
struct rtw_swing_table *swing_table)
{
- const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl;
+ const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
+ const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl;
u8 channel = rtwdev->hal.current_channel;
if (IS_CH_2G_BAND(channel)) {
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index 4d9b8668e8b0..e4d506cf9c33 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -9,6 +9,7 @@
#define BIT_FEN_EN_25_1 BIT(13)
#define BIT_FEN_ELDR BIT(12)
#define BIT_FEN_CPUEN BIT(2)
+#define BIT_FEN_USBA BIT(2)
#define BIT_FEN_BB_GLB_RST BIT(1)
#define BIT_FEN_BB_RSTB BIT(0)
#define BIT_R_DIS_PRST BIT(6)
@@ -16,6 +17,10 @@
#define REG_SYS_PW_CTRL 0x0004
#define BIT_PFM_WOWL BIT(3)
#define BIT_APFM_OFFMAC BIT(9)
+#define REG_APS_FSMCO 0x0004
+#define APS_FSMCO_MAC_ENABLE BIT(8)
+#define APS_FSMCO_MAC_OFF BIT(9)
+#define APS_FSMCO_HW_POWERDOWN BIT(15)
#define REG_SYS_CLK_CTRL 0x0008
#define BIT_CPU_CLK_EN BIT(14)
@@ -58,6 +63,8 @@
#define BIT_SHIFT_LDO25_VOLTAGE 4
#define BIT_LDO25_EN BIT(7)
+#define REG_ACLK_MON 0x3e
+
#define REG_GPIO_MUXCFG 0x0040
#define BIT_FSPI_EN BIT(19)
#define BIT_EN_SIC BIT(12)
@@ -90,6 +97,8 @@
#define BIT_USB_SUS_DIS BIT(8)
#define BIT_SDIO_PAD_E5 BIT(18)
+#define REG_RF_B_CTRL 0x76
+
#define REG_AFE_CTRL_4 0x0078
#define BIT_CK320M_AFE_EN BIT(4)
#define BIT_EN_SYN BIT(15)
@@ -134,6 +143,11 @@
#define REG_PMC_DBG_CTRL1 0xa8
#define BITS_PMC_BT_IQK_STS GENMASK(22, 21)
+#define REG_HIMR0 0xb0
+#define REG_HISR0 0xb4
+#define REG_HIMR1 0xb8
+#define REG_HISR1 0xbc
+
#define REG_PAD_CTRL2 0x00C4
#define BIT_RSM_EN_V1 BIT(16)
#define BIT_NO_PDN_CHIPOFF_V1 BIT(17)
@@ -185,6 +199,15 @@
#define MAC_TRX_ENABLE (BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \
BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \
BIT_MACTXEN | BIT_MACRXEN)
+#define REG_PBP 0x104
+#define PBP_RX_MASK 0x0f
+#define PBP_TX_MASK 0xf0
+#define PBP_64 0x0
+#define PBP_128 0x1
+#define PBP_256 0x2
+#define PBP_512 0x3
+#define PBP_1024 0x4
+
#define BIT_SHIFT_TXDMA_VOQ_MAP 4
#define BIT_MASK_TXDMA_VOQ_MAP 0x3
#define BIT_TXDMA_VOQ_MAP(x) \
@@ -256,6 +279,8 @@
#define REG_HMEBOX1 0x01D4
#define REG_HMEBOX2 0x01D8
#define REG_HMEBOX3 0x01DC
+#define REG_LLT_INIT 0x01E0
+#define BIT_LLT_WRITE_ACCESS BIT(30)
#define REG_HMEBOX0_EX 0x01F0
#define REG_HMEBOX1_EX 0x01F4
#define REG_HMEBOX2_EX 0x01F8
@@ -298,6 +323,7 @@
#define REG_AUTO_LLT 0x0224
#define BIT_AUTO_INIT_LLT BIT(16)
+#define REG_DWBCN1_CTRL 0x0228
#define REG_RQPN_CTRL_1 0x0228
#define REG_RQPN_CTRL_2 0x022C
#define BIT_LD_RQPN BIT(31)
@@ -329,6 +355,7 @@
#define BIT_DMA_BURST_SIZE_1024 0
#define REG_RXPKTNUM 0x02B0
+#define REG_EARLY_MODE_CONTROL 0x02BC
#define REG_INT_MIG 0x0304
#define REG_HCI_MIX_CFG 0x03FC
@@ -336,6 +363,7 @@
#define REG_BCNQ_INFO 0x0418
#define BIT_MGQ_CPU_EMPTY BIT(24)
+#define REG_TXPKT_EMPTY 0x041A
#define REG_FWHW_TXQ_CTRL 0x0420
#define BIT_EN_BCNQ_DL BIT(22)
#define BIT_EN_WR_FREE_TAIL BIT(20)
@@ -362,10 +390,12 @@
#define REG_AMPDU_MAX_TIME_V1 0x0455
#define REG_BCNQ1_BDNY_V1 0x0456
#define REG_AMPDU_MAX_TIME 0x0456
+#define REG_AMPDU_MAX_LENGTH 0x0458
#define REG_WMAC_LBK_BF_HD 0x045D
#define REG_TX_HANG_CTRL 0x045E
#define BIT_EN_GNT_BT_AWAKE BIT(3)
#define BIT_EN_EOF_V1 BIT(2)
+#define REG_FAST_EDCA_CTRL 0x0460
#define REG_DATA_SC 0x0483
#define REG_ARFR2_V1 0x048C
#define REG_ARFRH2_V1 0x0490
@@ -390,6 +420,8 @@
#define REG_PRECNT_CTRL 0x04E5
#define BIT_BTCCA_CTRL (BIT(0) | BIT(1))
#define BIT_EN_PRECNT BIT(11)
+#define REG_TX_RPT_CTRL 0x04EC
+#define REG_TX_RPT_TIME 0x04F0
#define REG_DUMMY_PAGE4_V1 0x04FC
#define REG_EDCA_VO_PARAM 0x0500
@@ -400,6 +432,7 @@
#define BIT_MASK_CWMAX GENMASK(15, 12)
#define BIT_MASK_CWMIN GENMASK(11, 8)
#define BIT_MASK_AIFS GENMASK(7, 0)
+#define REG_BCNTCFG 0x0510
#define REG_PIFS 0x0512
#define REG_SIFS 0x0514
#define BIT_SHIFT_SIFS_OFDM_CTX 8
@@ -526,6 +559,8 @@
#define REG_BT_COEX_V2 0x0762
#define BIT_GNT_BT_POLARITY BIT(12)
#define BIT_LTE_COEX_EN BIT(7)
+#define REG_GNT_BT 0x0765
+#define BIT_PTA_SW_CTL GENMASK(4, 3)
#define REG_BT_COEX_ENH_INTR_CTRL 0x76E
#define BIT_R_GRANTALL_WLMASK BIT(3)
#define BIT_STATIS_BT_EN BIT(2)
@@ -543,14 +578,43 @@
#define REG_FPGA0_RFMOD 0x0800
#define BIT_CCKEN BIT(24)
#define BIT_OFDMEN BIT(25)
+#define REG_CCK_RPT_FORMAT 0x0804
+#define BIT_CCK_RPT_FORMAT BIT(16)
+#define REG_RXPSEL 0x0808
+#define BIT_RX_PSEL_RST (BIT(28) | BIT(29))
+#define REG_TXPSEL 0x080C
#define REG_RX_GAIN_EN 0x081c
+#define REG_CCASEL 0x082C
+#define REG_PDMFTH 0x0830
+#define REG_BWINDICATION 0x0834
+#define REG_CCA2ND 0x0838
+#define REG_L1PKTH 0x0848
+#define REG_CLKTRK 0x0860
+#define REG_ADCCLK 0x08AC
+#define REG_HSSI_READ 0x08B0
+#define REG_FPGA0_XCD_RF_PARA 0x08B4
+#define REG_RX_MCS_LIMIT 0x08BC
+#define REG_ADC160 0x08C4
+#define REG_ANTSEL_SW 0x0900
+#define REG_DAC_RSTB 0x090c
+#define REG_SINGLE_TONE_CONT_TX 0x0914
#define REG_RFE_CTRL_E 0x0974
#define REG_2ND_CCA_CTRL 0x0976
+#define REG_IQK_COM00 0x0978
+#define REG_IQK_COM32 0x097c
+#define REG_IQK_COM64 0x0980
+#define REG_IQK_COM96 0x0984
+
+#define REG_FAS 0x09a4
+#define REG_RXSB 0x0a00
+#define REG_CCK_RX 0x0a04
+#define REG_CCK_PD_TH 0x0a0a
#define REG_CCK0_FAREPORT 0xa2c
#define BIT_CCK0_2RX BIT(18)
#define BIT_CCK0_MRC BIT(22)
+#define REG_FA_CCK 0x0a5c
#define REG_DIS_DPD 0x0a70
#define DIS_DPD_MASK GENMASK(9, 0)
@@ -566,13 +630,109 @@
#define DIS_DPD_RATEVHT2SS_MCS1 BIT(9)
#define DIS_DPD_RATEALL GENMASK(9, 0)
+#define REG_CNTRST 0x0b58
+
+#define REG_3WIRE_SWA 0x0c00
+#define REG_RX_IQC_AB_A 0x0c10
+#define REG_TXSCALE_A 0x0c1c
+#define BB_SWING_MASK GENMASK(31, 21)
+#define REG_TX_AGC_A_CCK_11_CCK_1 0xc20
+#define REG_TX_AGC_A_OFDM18_OFDM6 0xc24
+#define REG_TX_AGC_A_OFDM54_OFDM24 0xc28
+#define REG_TX_AGC_A_MCS3_MCS0 0xc2c
+#define REG_TX_AGC_A_MCS7_MCS4 0xc30
+#define REG_TX_AGC_A_MCS11_MCS8 0xc34
+#define REG_TX_AGC_A_MCS15_MCS12 0xc38
+#define REG_TX_AGC_A_NSS1_INDEX3_NSS1_INDEX0 0xc3c
+#define REG_TX_AGC_A_NSS1_INDEX7_NSS1_INDEX4 0xc40
+#define REG_TX_AGC_A_NSS2_INDEX1_NSS1_INDEX8 0xc44
+#define REG_TX_AGC_A_NSS2_INDEX5_NSS2_INDEX2 0xc48
+#define REG_TX_AGC_A_NSS2_INDEX9_NSS2_INDEX6 0xc4c
+#define REG_RXIGI_A 0x0c50
+#define REG_TX_PWR_TRAINING_A 0x0c54
+#define REG_CK_MONHA 0x0c5c
+#define REG_AFE_PWR1_A 0x0c60
+#define REG_AFE_PWR2_A 0x0c64
+#define REG_RX_WAIT_CCA_TX_CCK_RFON_A 0x0c68
+#define REG_OFDM0_XA_TX_IQ_IMBALANCE 0x0c80
+#define REG_OFDM0_A_TX_AFE 0x0c84
+#define REG_OFDM0_XB_TX_IQ_IMBALANCE 0x0c88
+#define REG_TSSI_TRK_SW 0x0c8c
+#define REG_LSSI_WRITE_A 0x0c90
+#define REG_PREDISTA 0x0c90
+#define REG_TXAGCIDX 0x0c94
+
+#define REG_RFE_PINMUX_A 0x0cb0
+#define REG_RFE_INV_A 0x0cb4
#define REG_RFE_CTRL8 0x0cb4
#define BIT_MASK_RFE_SEL89 GENMASK(7, 0)
+#define PTA_CTRL_PIN 0x66
+#define DPDT_CTRL_PIN 0x77
+#define RFE_INV_MASK 0x3ff00000
+#define REG_RFECTL_A 0x0cb8
#define REG_RFE_INV8 0x0cbd
#define BIT_MASK_RFE_INV89 GENMASK(1, 0)
#define REG_RFE_INV16 0x0cbe
#define BIT_RFE_BUF_EN BIT(3)
+#define REG_IQK_DPD_CFG 0x0cc4
+#define REG_CFG_PMPD 0x0cc8
+#define REG_IQC_Y 0x0ccc
+#define REG_IQC_X 0x0cd4
+#define REG_INTPO_SETA 0x0ce8
+
+#define REG_IQKA_END 0x0d00
+#define REG_PI_READ_A 0x0d04
+#define REG_SI_READ_A 0x0d08
+#define REG_IQKB_END 0x0d40
+#define REG_PI_READ_B 0x0d44
+#define REG_SI_READ_B 0x0d48
+
+#define REG_3WIRE_SWB 0x0e00
+#define REG_RX_IQC_AB_B 0x0e10
+#define REG_TXSCALE_B 0x0e1c
+#define REG_TX_AGC_B_CCK_11_CCK_1 0xe20
+#define REG_TX_AGC_B_OFDM18_OFDM6 0xe24
+#define REG_TX_AGC_B_OFDM54_OFDM24 0xe28
+#define REG_TX_AGC_B_MCS3_MCS0 0xe2c
+#define REG_TX_AGC_B_MCS7_MCS4 0xe30
+#define REG_TX_AGC_B_MCS11_MCS8 0xe34
+#define REG_TX_AGC_B_MCS15_MCS12 0xe38
+#define REG_TX_AGC_B_NSS1_INDEX3_NSS1_INDEX0 0xe3c
+#define REG_TX_AGC_B_NSS1_INDEX7_NSS1_INDEX4 0xe40
+#define REG_TX_AGC_B_NSS2_INDEX1_NSS1_INDEX8 0xe44
+#define REG_TX_AGC_B_NSS2_INDEX5_NSS2_INDEX2 0xe48
+#define REG_TX_AGC_B_NSS2_INDEX9_NSS2_INDEX6 0xe4c
+#define REG_RXIGI_B 0x0e50
+#define REG_TX_PWR_TRAINING_B 0x0e54
+#define REG_CK_MONHB 0x0e5c
+#define REG_AFE_PWR1_B 0x0e60
+#define REG_AFE_PWR2_B 0x0e64
+#define REG_RX_WAIT_CCA_TX_CCK_RFON_B 0x0e68
+#define REG_TXTONEB 0x0e80
+#define REG_RXTONEB 0x0e84
+#define REG_TXPITMB 0x0e88
+#define REG_RXPITMB 0x0e8c
+#define REG_LSSI_WRITE_B 0x0e90
+#define REG_PREDISTB 0x0e90
+#define REG_INIDLYB 0x0e94
+#define REG_RFE_PINMUX_B 0x0eb0
+#define REG_RFE_INV_B 0x0eb4
+#define REG_RFECTL_B 0x0eb8
+#define REG_BPBDB 0x0ec4
+#define REG_PHYTXONB 0x0ec8
+#define REG_IQKYB 0x0ecc
+#define REG_IQKXB 0x0ed4
+#define REG_INTPO_SETB 0x0ee8
+
+#define REG_CRC_CCK 0x0f04
+#define REG_CCA_OFDM 0x0f08
+#define REG_CRC_VHT 0x0f0c
+#define REG_CRC_HT 0x0f10
+#define REG_CRC_OFDM 0x0f14
+#define REG_FA_OFDM 0x0f48
+#define REG_CCA_CCK 0x0fcc
+
#define REG_ANAPARSW_MAC_0 0x1010
#define BIT_CF_L_V2 GENMASK(29, 28)
@@ -709,6 +869,10 @@
#define REG_IGN_GNTBT4 0x4160
+#define REG_USB_MOD 0xf008
+#define REG_USB3_RXITV 0xf050
+#define REG_USB_HRPWM 0xfe58
+
#define RF_MODE 0x00
#define RF_MODOPT 0x01
#define RF_WLINT 0x01
@@ -716,7 +880,13 @@
#define RF_DTXLOK 0x08
#define RF_CFGCH 0x18
#define BIT_BAND GENMASK(18, 16)
+#define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8))
+#define RF18_CHANNEL_MASK (MASKBYTE0)
+#define RF18_RFSI_MASK (BIT(18) | BIT(17))
#define RF_RCK 0x1d
+#define RF_MODE_TABLE_ADDR 0x30
+#define RF_MODE_TABLE_DATA0 0x31
+#define RF_MODE_TABLE_DATA1 0x32
#define RF_LUTWA 0x33
#define RF_LUTWD1 0x3e
#define RF_LUTWD0 0x3f
@@ -725,10 +895,14 @@
#define RF_T_METER 0x42
#define RF_BSPAD 0x54
#define RF_GAINTX 0x56
+#define RF_TXMOD 0x58
#define RF_TXATANK 0x64
+#define RF_TXA_PREPAD 0x65
#define RF_TRXIQ 0x66
#define RF_RXIQGEN 0x8d
+#define RF_RXBB2 0x8f
#define RF_SYN_PFD 0xb0
+#define RF_LCK 0xb4
#define RF_XTALX2 0xb8
#define RF_SYN_CTRL 0xbb
#define RF_MALSEL 0xbe
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
index 222608de33cd..a19b94d022ee 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
@@ -29,9 +29,6 @@
#define TBTT_PROHIBIT_HOLD_TIME 0x80
#define TBTT_PROHIBIT_HOLD_TIME_STOP_BCN 0x64
-/* raw pkt_stat->drv_info_sz is in unit of 8-bytes */
-#define RX_DRV_INFO_SZ_UNIT_8703B 8
-
#define TRANS_SEQ_END \
0xFFFF, \
RTW_PWR_CUT_ALL_MSK, \
@@ -481,14 +478,14 @@ static const struct rtw_pwr_seq_cmd trans_act_to_lps_8703b[] = {
{TRANS_SEQ_END},
};
-static const struct rtw_pwr_seq_cmd *card_enable_flow_8703b[] = {
+static const struct rtw_pwr_seq_cmd * const card_enable_flow_8703b[] = {
trans_pre_enable_8703b,
trans_carddis_to_cardemu_8703b,
trans_cardemu_to_act_8703b,
NULL
};
-static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = {
+static const struct rtw_pwr_seq_cmd * const card_disable_flow_8703b[] = {
trans_act_to_lps_8703b,
trans_act_to_reset_mcu_8703b,
trans_act_to_cardemu_8703b,
@@ -496,11 +493,6 @@ static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = {
NULL
};
-static const struct rtw_rfe_def rtw8703b_rfe_defs[] = {
- [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl,
- .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl,},
-};
-
static const struct rtw_page_table page_table_8703b[] = {
{12, 2, 2, 0, 1},
{12, 2, 2, 0, 1},
@@ -640,7 +632,7 @@ static void rtw8703b_pwrtrack_init(struct rtw_dev *rtwdev)
dm_info->pwr_trk_init_trigger = true;
dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
dm_info->txagc_remnant_cck = 0;
- dm_info->txagc_remnant_ofdm = 0;
+ dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0;
}
static void rtw8703b_phy_set_param(struct rtw_dev *rtwdev)
@@ -1032,57 +1024,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
query_phy_status_ofdm(rtwdev, phy_status, pkt_stat);
}
-static void rtw8703b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
- u8 *phy_status = NULL;
-
- memset(pkt_stat, 0, sizeof(*pkt_stat));
-
- pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
- pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
- pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
- GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
- pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
- pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
- pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
- pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
- pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
- pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
- pkt_stat->ppdu_cnt = 0;
- pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
-
- pkt_stat->drv_info_sz *= RX_DRV_INFO_SZ_UNIT_8703B;
-
- if (pkt_stat->is_c2h)
- return;
-
- hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
- pkt_stat->drv_info_sz);
-
- pkt_stat->bw = GET_RX_DESC_BW(rx_desc);
-
- if (pkt_stat->phy_status) {
- phy_status = rx_desc + desc_sz + pkt_stat->shift;
- query_phy_status(rtwdev, phy_status, pkt_stat);
- }
-
- rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
-
- /* Rtl8723cs driver checks for size < 14 or size > 8192 and
- * simply drops the packet. Maybe this should go into
- * rtw_rx_fill_rx_status()?
- */
- if (pkt_stat->pkt_len == 0) {
- rx_status->flag |= RX_FLAG_NO_PSDU;
- rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet");
- }
-}
-
#define ADDA_ON_VAL_8703B 0x03c00014
static
@@ -1643,7 +1584,7 @@ static void rtw8703b_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx,
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- dm_info->txagc_remnant_ofdm = txagc_idx;
+ dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx;
/* Only path A is calibrated for rtl8703b */
rtw8703b_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A);
@@ -1872,6 +1813,12 @@ static const struct rtw_pwr_track_tbl rtw8703b_rtw_pwr_track_tbl = {
.pwrtrk_xtal_p = rtw8703b_pwrtrk_xtal_p,
};
+static const struct rtw_rfe_def rtw8703b_rfe_defs[] = {
+ [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl,
+ .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl, },
+};
+
/* Shared-Antenna Coex Table */
static const struct coex_table_para table_sant_8703b[] = {
{0xffffffff, 0xffffffff}, /* case-0 */
@@ -1941,14 +1888,16 @@ static const struct coex_tdma_para tdma_sant_8703b[] = {
{ {0x61, 0x08, 0x03, 0x11, 0x11} },
};
-static struct rtw_chip_ops rtw8703b_ops = {
+static const struct rtw_chip_ops rtw8703b_ops = {
+ .power_on = rtw_power_on,
+ .power_off = rtw_power_off,
.mac_init = rtw8723x_mac_init,
.dump_fw_crash = NULL,
.shutdown = NULL,
.read_efuse = rtw8703b_read_efuse,
.phy_set_param = rtw8703b_phy_set_param,
.set_channel = rtw8703b_set_channel,
- .query_rx_desc = rtw8703b_query_rx_desc,
+ .query_phy_status = query_phy_status,
.read_rf = rtw_phy_read_rf_sipi,
.write_rf = rtw_phy_write_rf_reg_sipi,
.set_tx_power_index = rtw8723x_set_tx_power_index,
@@ -2014,6 +1963,9 @@ const struct rtw_chip_info rtw8703b_hw_spec = {
.max_power_index = 0x3f,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.usb_tx_agg_desc_num = 1, /* Not sure if this chip has USB interface */
+ .hw_feature_report = true,
+ .c2h_ra_report_size = 7,
+ .old_datarate_fb_limit = true,
.path_div_supported = false,
.ht_supported = true,
@@ -2046,7 +1998,6 @@ const struct rtw_chip_info rtw8703b_hw_spec = {
.rfe_defs_size = ARRAY_SIZE(rtw8703b_rfe_defs),
.iqk_threshold = 8,
- .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl,
/* WOWLAN firmware exists, but not implemented yet */
.wow_fw_name = "rtw88/rtw8703b_wow_fw.bin",
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
index 3fba4054d45f..eeca31bf71f1 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
@@ -79,7 +79,7 @@ static void rtw8723d_pwrtrack_init(struct rtw_dev *rtwdev)
dm_info->pwr_trk_init_trigger = true;
dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
dm_info->txagc_remnant_cck = 0;
- dm_info->txagc_remnant_ofdm = 0;
+ dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0;
}
static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev)
@@ -227,47 +227,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
}
}
-static void rtw8723d_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
- u8 *phy_status = NULL;
-
- memset(pkt_stat, 0, sizeof(*pkt_stat));
-
- pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
- pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
- pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
- GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
- pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
- pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
- pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
- pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
- pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
- pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
- pkt_stat->ppdu_cnt = 0;
- pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
-
- /* drv_info_sz is in unit of 8-bytes */
- pkt_stat->drv_info_sz *= 8;
-
- /* c2h cmd pkt's rx/phy status is not interested */
- if (pkt_stat->is_c2h)
- return;
-
- hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
- pkt_stat->drv_info_sz);
- if (pkt_stat->phy_status) {
- phy_status = rx_desc + desc_sz + pkt_stat->shift;
- query_phy_status(rtwdev, phy_status, pkt_stat);
- }
-
- rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
-}
-
static bool rtw8723d_check_spur_ov_thres(struct rtw_dev *rtwdev,
u8 channel, u32 thres)
{
@@ -1306,7 +1265,7 @@ static void rtw8723d_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx,
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- dm_info->txagc_remnant_ofdm = txagc_idx;
+ dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx;
rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A);
rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_B);
@@ -1430,10 +1389,12 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev)
dm_info->pwr_trk_triggered = false;
}
-static struct rtw_chip_ops rtw8723d_ops = {
+static const struct rtw_chip_ops rtw8723d_ops = {
+ .power_on = rtw_power_on,
+ .power_off = rtw_power_off,
.phy_set_param = rtw8723d_phy_set_param,
.read_efuse = rtw8723x_read_efuse,
- .query_rx_desc = rtw8723d_query_rx_desc,
+ .query_phy_status = query_phy_status,
.set_channel = rtw8723d_set_channel,
.mac_init = rtw8723x_mac_init,
.shutdown = rtw8723d_shutdown,
@@ -1788,7 +1749,7 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8723d[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static const struct rtw_pwr_seq_cmd *card_enable_flow_8723d[] = {
+static const struct rtw_pwr_seq_cmd * const card_enable_flow_8723d[] = {
trans_carddis_to_cardemu_8723d,
trans_cardemu_to_act_8723d,
NULL
@@ -2004,7 +1965,7 @@ static const struct rtw_pwr_seq_cmd trans_act_to_post_carddis_8723d[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static const struct rtw_pwr_seq_cmd *card_disable_flow_8723d[] = {
+static const struct rtw_pwr_seq_cmd * const card_disable_flow_8723d[] = {
trans_act_to_lps_8723d,
trans_act_to_pre_carddis_8723d,
trans_act_to_cardemu_8723d,
@@ -2059,11 +2020,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8723d = {
.n_gen1_para = ARRAY_SIZE(pcie_gen1_param_8723d),
};
-static const struct rtw_rfe_def rtw8723d_rfe_defs[] = {
- [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl,
- .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,},
-};
-
static const u8 rtw8723d_pwrtrk_2gb_n[] = {
0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5,
6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10
@@ -2127,6 +2083,12 @@ static const struct rtw_pwr_track_tbl rtw8723d_rtw_pwr_track_tbl = {
.pwrtrk_xtal_n = rtw8723d_pwrtrk_xtal_n,
};
+static const struct rtw_rfe_def rtw8723d_rfe_defs[] = {
+ [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl,
+ .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, },
+};
+
static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = {
{0x948, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0x67, BIT(7), RTW_REG_DOMAIN_MAC8},
@@ -2172,6 +2134,9 @@ const struct rtw_chip_info rtw8723d_hw_spec = {
.page_size = TX_PAGE_SIZE,
.dig_min = 0x20,
.usb_tx_agg_desc_num = 1,
+ .hw_feature_report = true,
+ .c2h_ra_report_size = 7,
+ .old_datarate_fb_limit = true,
.ht_supported = true,
.vht_supported = false,
.lps_deep_mode_supported = 0,
@@ -2195,7 +2160,6 @@ const struct rtw_chip_info rtw8723d_hw_spec = {
.rfe_defs = rtw8723d_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8723d_rfe_defs),
.rx_ldpc = false,
- .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl,
.iqk_threshold = 8,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c
index 0d0b6c2cb9aa..69f73cb5b4cd 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c
@@ -595,7 +595,8 @@ void __rtw8723x_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path,
u8 delta)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
- const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl;
+ const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev);
+ const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl;
const s8 *pwrtrk_xtal;
s8 xtal_cap;
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
new file mode 100644
index 000000000000..482edd31823d
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c
@@ -0,0 +1,1102 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include "main.h"
+#include "coex.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw88xxa.h"
+#include "rtw8812a.h"
+#include "rtw8812a_table.h"
+#include "tx.h"
+
+static void rtw8812a_power_off(struct rtw_dev *rtwdev)
+{
+ rtw88xxa_power_off(rtwdev, enter_lps_flow_8812a);
+}
+
+static s8 rtw8812a_cck_rx_pwr(u8 lna_idx, u8 vga_idx)
+{
+ s8 rx_pwr_all = 0;
+
+ switch (lna_idx) {
+ case 7:
+ if (vga_idx <= 27)
+ rx_pwr_all = -94 + 2 * (27 - vga_idx);
+ else
+ rx_pwr_all = -94;
+ break;
+ case 6:
+ rx_pwr_all = -42 + 2 * (2 - vga_idx);
+ break;
+ case 5:
+ rx_pwr_all = -36 + 2 * (7 - vga_idx);
+ break;
+ case 4:
+ rx_pwr_all = -30 + 2 * (7 - vga_idx);
+ break;
+ case 3:
+ rx_pwr_all = -18 + 2 * (7 - vga_idx);
+ break;
+ case 2:
+ rx_pwr_all = 2 * (5 - vga_idx);
+ break;
+ case 1:
+ rx_pwr_all = 14 - 2 * vga_idx;
+ break;
+ case 0:
+ rx_pwr_all = 20 - 2 * vga_idx;
+ break;
+ default:
+ break;
+ }
+
+ return rx_pwr_all;
+}
+
+static void rtw8812a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+ struct rtw_rx_pkt_stat *pkt_stat)
+{
+ rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat,
+ rtw8812a_cck_rx_pwr);
+
+ if (pkt_stat->rate >= DESC_RATE6M)
+ return;
+
+ if (rtwdev->hal.cck_high_power)
+ return;
+
+ if (pkt_stat->rssi >= 80)
+ pkt_stat->rssi = ((pkt_stat->rssi - 80) << 1) +
+ ((pkt_stat->rssi - 80) >> 1) + 80;
+ else if (pkt_stat->rssi <= 78 && pkt_stat->rssi >= 20)
+ pkt_stat->rssi += 3;
+}
+
+static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
+{
+}
+
+static void rtw8812a_do_lck(struct rtw_dev *rtwdev)
+{
+ u32 cont_tx, lc_cal, i;
+
+ cont_tx = rtw_read32_mask(rtwdev, REG_SINGLE_TONE_CONT_TX, 0x70000);
+
+ lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK);
+
+ if (!cont_tx)
+ rtw_write8(rtwdev, REG_TXPAUSE, 0xff);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 1);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000, 1);
+
+ mdelay(150);
+
+ for (i = 0; i < 5; i++) {
+ if (rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000) != 1)
+ break;
+
+ mdelay(10);
+ }
+
+ if (i == 5)
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "LCK timed out\n");
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 0);
+
+ if (!cont_tx)
+ rtw_write8(rtwdev, REG_TXPAUSE, 0);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal);
+}
+
+static void rtw8812a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup,
+ u32 *rfb_backup, const u32 *backup_rf_reg,
+ u32 rf_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Save RF Parameters */
+ for (i = 0; i < rf_num; i++) {
+ rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A,
+ backup_rf_reg[i], MASKDWORD);
+ rfb_backup[i] = rtw_read_rf(rtwdev, RF_PATH_B,
+ backup_rf_reg[i], MASKDWORD);
+ }
+}
+
+static void rtw8812a_iqk_restore_rf(struct rtw_dev *rtwdev,
+ enum rtw_rf_path path,
+ const u32 *backup_rf_reg,
+ u32 *RF_backup, u32 rf_reg_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ for (i = 0; i < rf_reg_num; i++)
+ rtw_write_rf(rtwdev, path, backup_rf_reg[i],
+ RFREG_MASK, RF_backup[i]);
+
+ rtw_write_rf(rtwdev, path, RF_LUTWE, RFREG_MASK, 0);
+}
+
+static void rtw8812a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
+ const u32 *backup_afe_reg, u32 afe_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Reload AFE Parameters */
+ for (i = 0; i < afe_num; i++)
+ rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0);
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0);
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0);
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000);
+ rtw_write32_mask(rtwdev, REG_LSSI_WRITE_A, BIT(7), 1);
+ rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 1);
+ rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 1);
+ rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 1);
+
+ rtw_write32(rtwdev, REG_TXTONEB, 0x0);
+ rtw_write32(rtwdev, REG_RXTONEB, 0x0);
+ rtw_write32(rtwdev, REG_TXPITMB, 0x0);
+ rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000);
+ rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, BIT(7), 1);
+ rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 1);
+ rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 1);
+ rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 1);
+}
+
+static void rtw8812a_iqk_rx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path,
+ unsigned int rx_x, unsigned int rx_y)
+{
+ switch (path) {
+ case RF_PATH_A:
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ if (rx_x >> 1 >= 0x112 ||
+ (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) {
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x000003ff, 0x100);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x03ff0000, 0);
+ } else {
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x000003ff, rx_x >> 1);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x03ff0000, rx_y >> 1);
+ }
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x = %x;;rx_y = %x ====>fill to IQC\n",
+ rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "0xc10 = %x ====>fill to IQC\n",
+ rtw_read32(rtwdev, REG_RX_IQC_AB_A));
+ break;
+ case RF_PATH_B:
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ if (rx_x >> 1 >= 0x112 ||
+ (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) {
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+ 0x000003ff, 0x100);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+ 0x03ff0000, 0);
+ } else {
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+ 0x000003ff, rx_x >> 1);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B,
+ 0x03ff0000, rx_y >> 1);
+ }
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x = %x;;rx_y = %x ====>fill to IQC\n",
+ rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "0xe10 = %x====>fill to IQC\n",
+ rtw_read32(rtwdev, REG_RX_IQC_AB_B));
+ break;
+ default:
+ break;
+ }
+}
+
+static void rtw8812a_iqk_tx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path,
+ unsigned int tx_x, unsigned int tx_y)
+{
+ switch (path) {
+ case RF_PATH_A:
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+ rtw_write32_mask(rtwdev, REG_PREDISTA, BIT(7), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 0x1);
+ rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y);
+ rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx_x = %x;;tx_y = %x =====> fill to IQC\n",
+ tx_x & 0x000007ff, tx_y & 0x000007ff);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "0xcd4 = %x;;0xccc = %x ====>fill to IQC\n",
+ rtw_read32_mask(rtwdev, REG_IQC_X, 0x000007ff),
+ rtw_read32_mask(rtwdev, REG_IQC_Y, 0x000007ff));
+ break;
+ case RF_PATH_B:
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+ rtw_write32_mask(rtwdev, REG_PREDISTB, BIT(7), 0x1);
+ rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 0x1);
+ rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 0x1);
+ rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQKYB, 0x000007ff, tx_y);
+ rtw_write32_mask(rtwdev, REG_IQKXB, 0x000007ff, tx_x);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx_x = %x;;tx_y = %x =====> fill to IQC\n",
+ tx_x & 0x000007ff, tx_y & 0x000007ff);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "0xed4 = %x;;0xecc = %x ====>fill to IQC\n",
+ rtw_read32_mask(rtwdev, REG_IQKXB, 0x000007ff),
+ rtw_read32_mask(rtwdev, REG_IQKYB, 0x000007ff));
+ break;
+ default:
+ break;
+ }
+}
+
+static void rtw8812a_iqk(struct rtw_dev *rtwdev)
+{
+ int tx_x0_temp[10], tx_y0_temp[10], tx_x1_temp[10], tx_y1_temp[10];
+ int rx_x0_temp[10], rx_y0_temp[10], rx_x1_temp[10], rx_y1_temp[10];
+ bool iqk0_ready = false, tx0_finish = false, rx0_finish = false;
+ bool iqk1_ready = false, tx1_finish = false, rx1_finish = false;
+ u8 tx0_avg = 0, tx1_avg = 0, rx0_avg = 0, rx1_avg = 0;
+ int tx_x0 = 0, tx_y0 = 0, tx_x1 = 0, tx_y1 = 0;
+ int rx_x0 = 0, rx_y0 = 0, rx_x1 = 0, rx_y1 = 0;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ bool tx0_fail = true, rx0_fail = true;
+ bool tx1_fail = true, rx1_fail = true;
+ u8 cal0_retry, cal1_retry;
+ u8 delay_count;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* ========path-A AFE all on======== */
+ /* Port 0 DAC/ADC on */
+ rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777);
+ rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777);
+
+ /* Port 1 DAC/ADC on */
+ rtw_write32(rtwdev, REG_AFE_PWR1_B, 0x77777777);
+ rtw_write32(rtwdev, REG_AFE_PWR2_B, 0x77777777);
+
+ rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979);
+ rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_B, 0x19791979);
+
+ /* hardware 3-wire off */
+ rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4);
+ rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4);
+
+ /* DAC/ADC sampling rate (160 MHz) */
+ rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7);
+ rtw_write32_mask(rtwdev, REG_CK_MONHB, GENMASK(26, 24), 0x7);
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ /* ====== path A TX IQK RF setting ====== */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001);
+
+ /* ====== path B TX IQK RF setting ====== */
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80002);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d5);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x8a001);
+
+ rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+ rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1);
+ rtw_write32_mask(rtwdev, REG_INIDLYB, BIT(0), 0x1);
+ rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); /* TX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); /* RX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); /* [0]:AGC_en, [15]:idac_K_Mask */
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ if (efuse->ext_pa_5g) {
+ if (efuse->rfe_option == 1) {
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403e3);
+ rtw_write32(rtwdev, REG_TXPITMB, 0x821403e3);
+ } else {
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f7);
+ rtw_write32(rtwdev, REG_TXPITMB, 0x821403f7);
+ }
+ } else {
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f1);
+ rtw_write32(rtwdev, REG_TXPITMB, 0x821403f1);
+ }
+
+ if (rtwdev->hal.current_band_type == RTW_BAND_5G) {
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96);
+ rtw_write32(rtwdev, REG_RXPITMB, 0x68163e96);
+ } else {
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96);
+ rtw_write32(rtwdev, REG_RXPITMB, 0x28163e96);
+
+ if (efuse->rfe_option == 3) {
+ if (efuse->ext_pa_2g)
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403e3);
+ else
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403f7);
+ }
+ }
+
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10);
+ rtw_write32(rtwdev, REG_INTPO_SETA, 0x00000000);
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_TXTONEB, 0x18008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_RXTONEB, 0x38008c10);
+ rtw_write32(rtwdev, REG_INTPO_SETB, 0x00000000);
+
+ cal0_retry = 0;
+ cal1_retry = 0;
+ while (1) {
+ /* one shot */
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+ mdelay(10);
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000);
+
+ for (delay_count = 0; delay_count < 20; delay_count++) {
+ if (!tx0_finish)
+ iqk0_ready = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ BIT(10));
+ if (!tx1_finish)
+ iqk1_ready = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ BIT(10));
+ if (iqk0_ready && iqk1_ready)
+ break;
+
+ mdelay(1);
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "TX delay_count = %d\n",
+ delay_count);
+
+ if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */
+ /* ============TXIQK Check============== */
+ tx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12));
+ tx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(12));
+
+ if (!(tx0_fail || tx0_finish)) {
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000);
+ tx_x0_temp[tx0_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000);
+ tx_y0_temp[tx0_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n",
+ tx0_avg, tx_x0_temp[tx0_avg],
+ tx0_avg, tx_y0_temp[tx0_avg]);
+
+ tx_x0_temp[tx0_avg] <<= 21;
+ tx_y0_temp[tx0_avg] <<= 21;
+
+ tx0_avg++;
+ } else {
+ cal0_retry++;
+ if (cal0_retry == 10)
+ break;
+ }
+
+ if (!(tx1_fail || tx1_finish)) {
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x02000000);
+ tx_x1_temp[tx1_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ 0x07ff0000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x04000000);
+ tx_y1_temp[tx1_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ 0x07ff0000);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx_x1[%d] = %x ;; tx_y1[%d] = %x\n",
+ tx1_avg, tx_x1_temp[tx1_avg],
+ tx1_avg, tx_y1_temp[tx1_avg]);
+
+ tx_x1_temp[tx1_avg] <<= 21;
+ tx_y1_temp[tx1_avg] <<= 21;
+
+ tx1_avg++;
+ } else {
+ cal1_retry++;
+ if (cal1_retry == 10)
+ break;
+ }
+ } else {
+ cal0_retry++;
+ cal1_retry++;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "delay 20ms TX IQK Not Ready!!!!!\n");
+
+ if (cal0_retry == 10)
+ break;
+ }
+
+ if (tx0_avg >= 2)
+ tx0_finish = rtw88xxa_iqk_finish(tx0_avg, 4,
+ tx_x0_temp, tx_y0_temp, &tx_x0, &tx_y0,
+ false, false);
+
+ if (tx1_avg >= 2)
+ tx1_finish = rtw88xxa_iqk_finish(tx1_avg, 4,
+ tx_x1_temp, tx_y1_temp, &tx_x1, &tx_y1,
+ false, false);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx0_average = %d, tx1_average = %d\n",
+ tx0_avg, tx1_avg);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx0_finish = %d, tx1_finish = %d\n",
+ tx0_finish, tx1_finish);
+
+ if (tx0_finish && tx1_finish)
+ break;
+
+ if ((cal0_retry + tx0_avg) >= 10 ||
+ (cal1_retry + tx1_avg) >= 10)
+ break;
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "TXA_cal_retry = %d\n", cal0_retry);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "TXB_cal_retry = %d\n", cal1_retry);
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ /* Load LOK */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00,
+ rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00));
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_TXMOD, 0x7fe00,
+ rtw_read_rf(rtwdev, RF_PATH_B, RF_DTXLOK, 0xffc00));
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ if (tx0_finish) {
+ /* ====== path A RX IQK RF setting====== */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x30000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ 0x3f7ff);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ 0xfe7bf);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d1);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000);
+ }
+ if (tx1_finish) {
+ /* ====== path B RX IQK RF setting====== */
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80000);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x30000);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ 0x3f7ff);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ 0xfe7bf);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x88001);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d1);
+ rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x00000);
+ }
+
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0);
+ rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+
+ if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911);
+ else
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a890);
+
+ if (efuse->rfe_option == 1) {
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717);
+ rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717);
+ rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077);
+ } else {
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717);
+ rtw_write32(rtwdev, REG_RFE_INV_A, 0x02000077);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717);
+ rtw_write32(rtwdev, REG_RFE_INV_B, 0x02000077);
+ }
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ if (tx0_finish) {
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10);
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x82140119);
+ }
+ if (tx1_finish) {
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_TXTONEB, 0x38008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_RXTONEB, 0x18008c10);
+ rtw_write32(rtwdev, REG_TXPITMB, 0x82140119);
+ }
+
+ cal0_retry = 0;
+ cal1_retry = 0;
+ while (1) {
+ /* one shot */
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ if (tx0_finish) {
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000,
+ tx_x0 & 0x000007ff);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF,
+ tx_y0 & 0x000007ff);
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+ if (efuse->rfe_option == 1)
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161500);
+ else
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160cc0);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00300000);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+ mdelay(5);
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+ }
+
+ if (tx1_finish) {
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000,
+ tx_x1 & 0x000007ff);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF,
+ tx_y1 & 0x000007ff);
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+ if (efuse->rfe_option == 1)
+ rtw_write32(rtwdev, REG_RXPITMB, 0x28161500);
+ else
+ rtw_write32(rtwdev, REG_RXPITMB, 0x28160ca0);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x00300000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000);
+ mdelay(5);
+ rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000);
+ }
+
+ for (delay_count = 0; delay_count < 20; delay_count++) {
+ if (!rx0_finish && tx0_finish)
+ iqk0_ready = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ BIT(10));
+ if (!rx1_finish && tx1_finish)
+ iqk1_ready = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ BIT(10));
+ if (iqk0_ready && iqk1_ready)
+ break;
+
+ mdelay(1);
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "RX delay_count = %d\n",
+ delay_count);
+
+ if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */
+ /* ============RXIQK Check============== */
+ rx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11));
+ rx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(11));
+
+ if (!(rx0_fail || rx0_finish) && tx0_finish) {
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000);
+ rx_x0_temp[rx0_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000);
+ rx_y0_temp[rx0_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x0[%d] = %x ;; rx_y0[%d] = %x\n",
+ rx0_avg, rx_x0_temp[rx0_avg],
+ rx0_avg, rx_y0_temp[rx0_avg]);
+
+ rx_x0_temp[rx0_avg] <<= 21;
+ rx_y0_temp[rx0_avg] <<= 21;
+
+ rx0_avg++;
+ } else {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "1. RXA_cal_retry = %d\n", cal0_retry);
+
+ cal0_retry++;
+ if (cal0_retry == 10)
+ break;
+ }
+
+ if (!(rx1_fail || rx1_finish) && tx1_finish) {
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x06000000);
+ rx_x1_temp[rx1_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ 0x07ff0000);
+ rtw_write32(rtwdev, REG_RFECTL_B, 0x08000000);
+ rx_y1_temp[rx1_avg] = rtw_read32_mask(rtwdev,
+ REG_IQKB_END,
+ 0x07ff0000);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x1[%d] = %x ;; rx_y1[%d] = %x\n",
+ rx1_avg, rx_x1_temp[rx1_avg],
+ rx1_avg, rx_y1_temp[rx1_avg]);
+
+ rx_x1_temp[rx1_avg] <<= 21;
+ rx_y1_temp[rx1_avg] <<= 21;
+
+ rx1_avg++;
+ } else {
+ cal1_retry++;
+ if (cal1_retry == 10)
+ break;
+ }
+ } else {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "2. RXA_cal_retry = %d\n", cal0_retry);
+
+ cal0_retry++;
+ cal1_retry++;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "delay 20ms RX IQK Not Ready!!!!!\n");
+
+ if (cal0_retry == 10)
+ break;
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "3. RXA_cal_retry = %d\n",
+ cal0_retry);
+
+ if (rx0_avg >= 2)
+ rx0_finish = rtw88xxa_iqk_finish(rx0_avg, 4,
+ rx_x0_temp, rx_y0_temp,
+ &rx_x0, &rx_y0,
+ true, false);
+
+ if (rx1_avg >= 2)
+ rx1_finish = rtw88xxa_iqk_finish(rx1_avg, 4,
+ rx_x1_temp, rx_y1_temp,
+ &rx_x1, &rx_y1,
+ true, false);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx0_average = %d, rx1_average = %d\n",
+ rx0_avg, rx1_avg);
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx0_finish = %d, rx1_finish = %d\n",
+ rx0_finish, rx1_finish);
+
+ if ((rx0_finish || !tx0_finish) && (rx1_finish || !tx1_finish))
+ break;
+
+ if ((cal0_retry + rx0_avg) >= 10 ||
+ (cal1_retry + rx1_avg) >= 10 ||
+ rx0_avg == 3 || rx1_avg == 3)
+ break;
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "RXA_cal_retry = %d\n", cal0_retry);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "RXB_cal_retry = %d\n", cal1_retry);
+
+ /* FillIQK Result */
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_A =======\n");
+
+ if (tx0_finish)
+ rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, tx_x0, tx_y0);
+ else
+ rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, 0x200, 0x0);
+
+ if (rx0_finish)
+ rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, rx_x0, rx_y0);
+ else
+ rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, 0x200, 0x0);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_B =======\n");
+
+ if (tx1_finish)
+ rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, tx_x1, tx_y1);
+ else
+ rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, 0x200, 0x0);
+
+ if (rx1_finish)
+ rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, rx_x1, rx_y1);
+ else
+ rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, 0x200, 0x0);
+}
+
+#define MACBB_REG_NUM_8812A 9
+#define AFE_REG_NUM_8812A 12
+#define RF_REG_NUM_8812A 3
+
+static void rtw8812a_do_iqk(struct rtw_dev *rtwdev)
+{
+ static const u32 backup_macbb_reg[MACBB_REG_NUM_8812A] = {
+ 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c
+ };
+ static const u32 backup_afe_reg[AFE_REG_NUM_8812A] = {
+ 0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4,
+ 0xe5c, 0xe60, 0xe64, 0xe68, 0xeb0, 0xeb4
+ };
+ static const u32 backup_rf_reg[RF_REG_NUM_8812A] = {
+ 0x65, 0x8f, 0x0
+ };
+ u32 macbb_backup[MACBB_REG_NUM_8812A] = {};
+ u32 afe_backup[AFE_REG_NUM_8812A] = {};
+ u32 rfa_backup[RF_REG_NUM_8812A] = {};
+ u32 rfb_backup[RF_REG_NUM_8812A] = {};
+ u32 reg_cb8, reg_eb8;
+
+ rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup,
+ backup_macbb_reg, MACBB_REG_NUM_8812A);
+
+ rtw_write32_set(rtwdev, REG_CCASEL, BIT(31));
+ reg_cb8 = rtw_read32(rtwdev, REG_RFECTL_A);
+ reg_eb8 = rtw_read32(rtwdev, REG_RFECTL_B);
+ rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31));
+
+ rtw88xxa_iqk_backup_afe(rtwdev, afe_backup,
+ backup_afe_reg, AFE_REG_NUM_8812A);
+ rtw8812a_iqk_backup_rf(rtwdev, rfa_backup, rfb_backup,
+ backup_rf_reg, RF_REG_NUM_8812A);
+
+ rtw88xxa_iqk_configure_mac(rtwdev);
+
+ rtw8812a_iqk(rtwdev);
+
+ rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_A, backup_rf_reg,
+ rfa_backup, RF_REG_NUM_8812A);
+ rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_B, backup_rf_reg,
+ rfb_backup, RF_REG_NUM_8812A);
+
+ rtw8812a_iqk_restore_afe(rtwdev, afe_backup,
+ backup_afe_reg, AFE_REG_NUM_8812A);
+
+ rtw_write32_set(rtwdev, REG_CCASEL, BIT(31));
+ rtw_write32(rtwdev, REG_RFECTL_A, reg_cb8);
+ rtw_write32(rtwdev, REG_RFECTL_B, reg_eb8);
+ rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31));
+
+ rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup,
+ backup_macbb_reg, MACBB_REG_NUM_8812A);
+}
+
+static void rtw8812a_phy_calibration(struct rtw_dev *rtwdev)
+{
+ u8 channel = rtwdev->hal.current_channel;
+
+ rtw8812a_do_iqk(rtwdev);
+
+ /* The official driver wants to do this after connecting
+ * but before first writing a new igi (phydm_get_new_igi).
+ * Here seems close enough.
+ */
+ if (channel >= 36 && channel <= 64)
+ rtw_load_table(rtwdev, &rtw8812a_agc_diff_lb_tbl);
+ else if (channel >= 100)
+ rtw_load_table(rtwdev, &rtw8812a_agc_diff_hb_tbl);
+}
+
+static void rtw8812a_pwr_track(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+
+ if (!dm_info->pwr_trk_triggered) {
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER,
+ GENMASK(17, 16), 0x03);
+ dm_info->pwr_trk_triggered = true;
+ return;
+ }
+
+ rtw88xxa_phy_pwrtrack(rtwdev, rtw8812a_do_lck, rtw8812a_do_iqk);
+ dm_info->pwr_trk_triggered = false;
+}
+
+static void rtw8812a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info,
+ u8 *txdesc)
+{
+ fill_txdesc_checksum_common(txdesc, 16);
+}
+
+static void rtw8812a_coex_cfg_init(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8812a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+}
+
+static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+}
+
+static const struct rtw_chip_ops rtw8812a_ops = {
+ .power_on = rtw88xxa_power_on,
+ .power_off = rtw8812a_power_off,
+ .phy_set_param = NULL,
+ .read_efuse = rtw88xxa_read_efuse,
+ .query_phy_status = rtw8812a_query_phy_status,
+ .set_channel = rtw88xxa_set_channel,
+ .mac_init = NULL,
+ .read_rf = rtw88xxa_phy_read_rf,
+ .write_rf = rtw_phy_write_rf_reg_sipi,
+ .set_antenna = NULL,
+ .set_tx_power_index = rtw88xxa_set_tx_power_index,
+ .cfg_ldo25 = rtw8812a_cfg_ldo25,
+ .efuse_grant = rtw88xxa_efuse_grant,
+ .false_alarm_statistics = rtw88xxa_false_alarm_statistics,
+ .phy_calibration = rtw8812a_phy_calibration,
+ .cck_pd_set = rtw88xxa_phy_cck_pd_set,
+ .pwr_track = rtw8812a_pwr_track,
+ .config_bfee = NULL,
+ .set_gid_table = NULL,
+ .cfg_csi_rate = NULL,
+ .fill_txdesc_checksum = rtw8812a_fill_txdesc_checksum,
+ .coex_set_init = rtw8812a_coex_cfg_init,
+ .coex_set_ant_switch = NULL,
+ .coex_set_gnt_fix = rtw8812a_coex_cfg_gnt_fix,
+ .coex_set_gnt_debug = NULL,
+ .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type,
+ .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power,
+ .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
+};
+
+static const struct rtw_page_table page_table_8812a[] = {
+ /* hq_num, nq_num, lq_num, exq_num, gapq_num */
+ {0, 0, 0, 0, 0}, /* SDIO */
+ {0, 0, 0, 0, 0}, /* PCI */
+ {16, 0, 0, 0, 1}, /* 2 bulk out endpoints */
+ {16, 0, 16, 0, 1}, /* 3 bulk out endpoints */
+ {16, 0, 16, 0, 1}, /* 4 bulk out endpoints */
+};
+
+static const struct rtw_rqpn rqpn_table_8812a[] = {
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH,
+ RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+};
+
+static const struct rtw_prioq_addrs prioq_addrs_8812a = {
+ .prio[RTW_DMA_MAPPING_EXTRA] = {
+ .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3,
+ },
+ .prio[RTW_DMA_MAPPING_LOW] = {
+ .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1,
+ },
+ .prio[RTW_DMA_MAPPING_NORMAL] = {
+ .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1,
+ },
+ .prio[RTW_DMA_MAPPING_HIGH] = {
+ .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2,
+ },
+ .wsize = false,
+};
+
+static const struct rtw_hw_reg rtw8812a_dig[] = {
+ [0] = { .addr = REG_RXIGI_A, .mask = 0x7f },
+ [1] = { .addr = REG_RXIGI_B, .mask = 0x7f },
+};
+
+static const struct rtw_rfe_def rtw8812a_rfe_defs[] = {
+ [0] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl,
+ .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, },
+ [1] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl,
+ .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, },
+ [3] = { .phy_pg_tbl = &rtw8812a_bb_pg_rfe3_tbl,
+ .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8812a_rtw_pwr_track_rfe3_tbl, },
+};
+
+static const u8 wl_rssi_step_8812a[] = {101, 45, 101, 40};
+static const u8 bt_rssi_step_8812a[] = {101, 101, 101, 101};
+
+static const struct coex_rf_para rf_para_tx_8812a[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 20, false, 7}, /* for WL-CPT */
+ {8, 17, true, 4},
+ {7, 18, true, 4},
+ {6, 19, true, 4},
+ {5, 20, true, 4}
+};
+
+static const struct coex_rf_para rf_para_rx_8812a[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 20, false, 7}, /* for WL-CPT */
+ {3, 24, true, 5},
+ {2, 26, true, 5},
+ {1, 27, true, 5},
+ {0, 28, true, 5}
+};
+
+static_assert(ARRAY_SIZE(rf_para_tx_8812a) == ARRAY_SIZE(rf_para_rx_8812a));
+
+const struct rtw_chip_info rtw8812a_hw_spec = {
+ .ops = &rtw8812a_ops,
+ .id = RTW_CHIP_TYPE_8812A,
+ .fw_name = "rtw88/rtw8812a_fw.bin",
+ .wlan_cpu = RTW_WCPU_11N,
+ .tx_pkt_desc_sz = 40,
+ .tx_buf_desc_sz = 16,
+ .rx_pkt_desc_sz = 24,
+ .rx_buf_desc_sz = 8,
+ .phy_efuse_size = 512,
+ .log_efuse_size = 512,
+ .ptct_efuse_size = 96 + 1, /* TODO or just 18? */
+ .txff_size = 131072,
+ .rxff_size = 16128,
+ .rsvd_drv_pg_num = 9,
+ .txgi_factor = 1,
+ .is_pwr_by_rate_dec = true,
+ .max_power_index = 0x3f,
+ .csi_buf_pg_num = 0,
+ .band = RTW_BAND_2G | RTW_BAND_5G,
+ .page_size = 512,
+ .dig_min = 0x20,
+ .ht_supported = true,
+ .vht_supported = true,
+ .lps_deep_mode_supported = 0,
+ .sys_func_en = 0xFD,
+ .pwr_on_seq = card_enable_flow_8812a,
+ .pwr_off_seq = card_disable_flow_8812a,
+ .page_table = page_table_8812a,
+ .rqpn_table = rqpn_table_8812a,
+ .prioq_addrs = &prioq_addrs_8812a,
+ .intf_table = NULL,
+ .dig = rtw8812a_dig,
+ .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B},
+ .ltecoex_addr = NULL,
+ .mac_tbl = &rtw8812a_mac_tbl,
+ .agc_tbl = &rtw8812a_agc_tbl,
+ .bb_tbl = &rtw8812a_bb_tbl,
+ .rf_tbl = {&rtw8812a_rf_a_tbl, &rtw8812a_rf_b_tbl},
+ .rfe_defs = rtw8812a_rfe_defs,
+ .rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs),
+ .rx_ldpc = false,
+ .hw_feature_report = false,
+ .c2h_ra_report_size = 4,
+ .old_datarate_fb_limit = true,
+ .usb_tx_agg_desc_num = 1,
+ .iqk_threshold = 8,
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+ .max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+
+ .coex_para_ver = 0, /* no coex code in 8812au driver */
+ .bt_desired_ver = 0,
+ .scbd_support = false,
+ .new_scbd10_def = false,
+ .ble_hid_profile_support = false,
+ .wl_mimo_ps_support = false,
+ .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
+ .bt_rssi_type = COEX_BTRSSI_RATIO,
+ .ant_isolation = 15,
+ .rssi_tolerance = 2,
+ .wl_rssi_step = wl_rssi_step_8812a,
+ .bt_rssi_step = bt_rssi_step_8812a,
+ .table_sant_num = 0,
+ .table_sant = NULL,
+ .table_nsant_num = 0,
+ .table_nsant = NULL,
+ .tdma_sant_num = 0,
+ .tdma_sant = NULL,
+ .tdma_nsant_num = 0,
+ .tdma_nsant = NULL,
+ .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8812a),
+ .wl_rf_para_tx = rf_para_tx_8812a,
+ .wl_rf_para_rx = rf_para_rx_8812a,
+ .bt_afh_span_bw20 = 0x20,
+ .bt_afh_span_bw40 = 0x30,
+ .afh_5g_num = 0,
+ .afh_5g = NULL,
+ .coex_info_hw_regs_num = 0,
+ .coex_info_hw_regs = NULL,
+};
+EXPORT_SYMBOL(rtw8812a_hw_spec);
+
+MODULE_FIRMWARE("rtw88/rtw8812a_fw.bin");
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812a driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.h b/drivers/net/wireless/realtek/rtw88/rtw8812a.h
new file mode 100644
index 000000000000..82dab59e341d
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#ifndef __RTW8812A_H__
+#define __RTW8812A_H__
+
+extern const struct rtw_chip_info rtw8812a_hw_spec;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c
new file mode 100644
index 000000000000..048efbbd49ed
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c
@@ -0,0 +1,2812 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include "main.h"
+#include "phy.h"
+#include "rtw8812a_table.h"
+
+static const u32 rtw8812a_mac[] = {
+ 0x010, 0x0000000C,
+ 0x80000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x011, 0x00000066,
+ 0xA0000000, 0x00000000,
+ 0x011, 0x0000005A,
+ 0xB0000000, 0x00000000,
+ 0x025, 0x0000000F,
+ 0x072, 0x00000000,
+ 0x420, 0x00000080,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000000,
+ 0x432, 0x00000000,
+ 0x433, 0x00000001,
+ 0x434, 0x00000002,
+ 0x435, 0x00000003,
+ 0x436, 0x00000005,
+ 0x437, 0x00000007,
+ 0x438, 0x00000000,
+ 0x439, 0x00000000,
+ 0x43A, 0x00000000,
+ 0x43B, 0x00000001,
+ 0x43C, 0x00000002,
+ 0x43D, 0x00000003,
+ 0x43E, 0x00000005,
+ 0x43F, 0x00000007,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000010,
+ 0x445, 0x00000000,
+ 0x446, 0x00000000,
+ 0x447, 0x00000000,
+ 0x448, 0x00000000,
+ 0x449, 0x000000F0,
+ 0x44A, 0x0000000F,
+ 0x44B, 0x0000003E,
+ 0x44C, 0x00000010,
+ 0x44D, 0x00000000,
+ 0x44E, 0x00000000,
+ 0x44F, 0x00000000,
+ 0x450, 0x00000000,
+ 0x451, 0x000000F0,
+ 0x452, 0x0000000F,
+ 0x453, 0x00000000,
+ 0x45B, 0x00000080,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x4C8, 0x000000FF,
+ 0x4C9, 0x00000008,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000A2,
+ 0x502, 0x0000002F,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000A3,
+ 0x506, 0x0000005E,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002B,
+ 0x509, 0x000000A4,
+ 0x50A, 0x0000005E,
+ 0x50B, 0x00000000,
+ 0x50C, 0x0000004F,
+ 0x50D, 0x000000A4,
+ 0x50E, 0x00000000,
+ 0x50F, 0x00000000,
+ 0x512, 0x0000001C,
+ 0x514, 0x0000000A,
+ 0x516, 0x0000000A,
+ 0x525, 0x0000004F,
+ 0x550, 0x00000010,
+ 0x551, 0x00000010,
+ 0x559, 0x00000002,
+ 0x55C, 0x00000050,
+ 0x55D, 0x000000FF,
+ 0x604, 0x00000009,
+ 0x605, 0x00000030,
+ 0x607, 0x00000003,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x638, 0x00000050,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000080,
+ 0x642, 0x00000040,
+ 0x643, 0x00000000,
+ 0x652, 0x000000C8,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+ 0x718, 0x00000040,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8812a_mac, rtw_phy_cfg_mac);
+
+static const u32 rtw8812a_agc[] = {
+ 0x80000001, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0xFC000001,
+ 0x81C, 0xFB020001,
+ 0x81C, 0xFA040001,
+ 0x81C, 0xF9060001,
+ 0x81C, 0xF8080001,
+ 0x81C, 0xF70A0001,
+ 0x81C, 0xF60C0001,
+ 0x81C, 0xF50E0001,
+ 0x81C, 0xF4100001,
+ 0x81C, 0xF3120001,
+ 0x81C, 0xF2140001,
+ 0x81C, 0xF1160001,
+ 0x81C, 0xF0180001,
+ 0x81C, 0xEF1A0001,
+ 0x81C, 0xEE1C0001,
+ 0x81C, 0xED1E0001,
+ 0x81C, 0xEC200001,
+ 0x81C, 0xEB220001,
+ 0x81C, 0xEA240001,
+ 0x81C, 0xCD260001,
+ 0x81C, 0xCC280001,
+ 0x81C, 0xCB2A0001,
+ 0x81C, 0xCA2C0001,
+ 0x81C, 0xC92E0001,
+ 0x81C, 0xC8300001,
+ 0x81C, 0xA6320001,
+ 0x81C, 0xA5340001,
+ 0x81C, 0xA4360001,
+ 0x81C, 0xA3380001,
+ 0x81C, 0xA23A0001,
+ 0x81C, 0x883C0001,
+ 0x81C, 0x873E0001,
+ 0x81C, 0x86400001,
+ 0x81C, 0x85420001,
+ 0x81C, 0x84440001,
+ 0x81C, 0x83460001,
+ 0x81C, 0x82480001,
+ 0x81C, 0x814A0001,
+ 0x81C, 0x484C0001,
+ 0x81C, 0x474E0001,
+ 0x81C, 0x46500001,
+ 0x81C, 0x45520001,
+ 0x81C, 0x44540001,
+ 0x81C, 0x43560001,
+ 0x81C, 0x42580001,
+ 0x81C, 0x415A0001,
+ 0x81C, 0x255C0001,
+ 0x81C, 0x245E0001,
+ 0x81C, 0x23600001,
+ 0x81C, 0x22620001,
+ 0x81C, 0x21640001,
+ 0x81C, 0x21660001,
+ 0x81C, 0x21680001,
+ 0x81C, 0x216A0001,
+ 0x81C, 0x216C0001,
+ 0x81C, 0x216E0001,
+ 0x81C, 0x21700001,
+ 0x81C, 0x21720001,
+ 0x81C, 0x21740001,
+ 0x81C, 0x21760001,
+ 0x81C, 0x21780001,
+ 0x81C, 0x217A0001,
+ 0x81C, 0x217C0001,
+ 0x81C, 0x217E0001,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0x81C, 0xF9000001,
+ 0x81C, 0xF8020001,
+ 0x81C, 0xF7040001,
+ 0x81C, 0xF6060001,
+ 0x81C, 0xF5080001,
+ 0x81C, 0xF40A0001,
+ 0x81C, 0xF30C0001,
+ 0x81C, 0xF20E0001,
+ 0x81C, 0xF1100001,
+ 0x81C, 0xF0120001,
+ 0x81C, 0xEF140001,
+ 0x81C, 0xEE160001,
+ 0x81C, 0xED180001,
+ 0x81C, 0xEC1A0001,
+ 0x81C, 0xEB1C0001,
+ 0x81C, 0xEA1E0001,
+ 0x81C, 0xCD200001,
+ 0x81C, 0xCC220001,
+ 0x81C, 0xCB240001,
+ 0x81C, 0xCA260001,
+ 0x81C, 0xC9280001,
+ 0x81C, 0xC82A0001,
+ 0x81C, 0xC72C0001,
+ 0x81C, 0xC62E0001,
+ 0x81C, 0xA5300001,
+ 0x81C, 0xA4320001,
+ 0x81C, 0xA3340001,
+ 0x81C, 0xA2360001,
+ 0x81C, 0x88380001,
+ 0x81C, 0x873A0001,
+ 0x81C, 0x863C0001,
+ 0x81C, 0x853E0001,
+ 0x81C, 0x84400001,
+ 0x81C, 0x83420001,
+ 0x81C, 0x82440001,
+ 0x81C, 0x81460001,
+ 0x81C, 0x48480001,
+ 0x81C, 0x474A0001,
+ 0x81C, 0x464C0001,
+ 0x81C, 0x454E0001,
+ 0x81C, 0x44500001,
+ 0x81C, 0x43520001,
+ 0x81C, 0x42540001,
+ 0x81C, 0x41560001,
+ 0x81C, 0x25580001,
+ 0x81C, 0x245A0001,
+ 0x81C, 0x235C0001,
+ 0x81C, 0x225E0001,
+ 0x81C, 0x21600001,
+ 0x81C, 0x21620001,
+ 0x81C, 0x21640001,
+ 0x81C, 0x21660001,
+ 0x81C, 0x21680001,
+ 0x81C, 0x216A0001,
+ 0x81C, 0x236C0001,
+ 0x81C, 0x226E0001,
+ 0x81C, 0x21700001,
+ 0x81C, 0x21720001,
+ 0x81C, 0x21740001,
+ 0x81C, 0x21760001,
+ 0x81C, 0x21780001,
+ 0x81C, 0x217A0001,
+ 0x81C, 0x217C0001,
+ 0x81C, 0x217E0001,
+ 0xA0000000, 0x00000000,
+ 0x81C, 0xFF000001,
+ 0x81C, 0xFF020001,
+ 0x81C, 0xFF040001,
+ 0x81C, 0xFF060001,
+ 0x81C, 0xFF080001,
+ 0x81C, 0xFE0A0001,
+ 0x81C, 0xFD0C0001,
+ 0x81C, 0xFC0E0001,
+ 0x81C, 0xFB100001,
+ 0x81C, 0xFA120001,
+ 0x81C, 0xF9140001,
+ 0x81C, 0xF8160001,
+ 0x81C, 0xF7180001,
+ 0x81C, 0xF61A0001,
+ 0x81C, 0xF51C0001,
+ 0x81C, 0xF41E0001,
+ 0x81C, 0xF3200001,
+ 0x81C, 0xF2220001,
+ 0x81C, 0xF1240001,
+ 0x81C, 0xF0260001,
+ 0x81C, 0xEF280001,
+ 0x81C, 0xEE2A0001,
+ 0x81C, 0xED2C0001,
+ 0x81C, 0xEC2E0001,
+ 0x81C, 0xEB300001,
+ 0x81C, 0xEA320001,
+ 0x81C, 0xE9340001,
+ 0x81C, 0xE8360001,
+ 0x81C, 0xE7380001,
+ 0x81C, 0xE63A0001,
+ 0x81C, 0xE53C0001,
+ 0x81C, 0xC73E0001,
+ 0x81C, 0xC6400001,
+ 0x81C, 0xC5420001,
+ 0x81C, 0xC4440001,
+ 0x81C, 0xC3460001,
+ 0x81C, 0xC2480001,
+ 0x81C, 0xC14A0001,
+ 0x81C, 0xA74C0001,
+ 0x81C, 0xA64E0001,
+ 0x81C, 0xA5500001,
+ 0x81C, 0xA4520001,
+ 0x81C, 0xA3540001,
+ 0x81C, 0xA2560001,
+ 0x81C, 0xA1580001,
+ 0x81C, 0x675A0001,
+ 0x81C, 0x665C0001,
+ 0x81C, 0x655E0001,
+ 0x81C, 0x64600001,
+ 0x81C, 0x63620001,
+ 0x81C, 0x48640001,
+ 0x81C, 0x47660001,
+ 0x81C, 0x46680001,
+ 0x81C, 0x456A0001,
+ 0x81C, 0x446C0001,
+ 0x81C, 0x436E0001,
+ 0x81C, 0x42700001,
+ 0x81C, 0x41720001,
+ 0x81C, 0x41740001,
+ 0x81C, 0x41760001,
+ 0x81C, 0x41780001,
+ 0x81C, 0x417A0001,
+ 0x81C, 0x417C0001,
+ 0x81C, 0x417E0001,
+ 0xB0000000, 0x00000000,
+ 0x80000004, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0xFC800001,
+ 0x81C, 0xFB820001,
+ 0x81C, 0xFA840001,
+ 0x81C, 0xF9860001,
+ 0x81C, 0xF8880001,
+ 0x81C, 0xF78A0001,
+ 0x81C, 0xF68C0001,
+ 0x81C, 0xF58E0001,
+ 0x81C, 0xF4900001,
+ 0x81C, 0xF3920001,
+ 0x81C, 0xF2940001,
+ 0x81C, 0xF1960001,
+ 0x81C, 0xF0980001,
+ 0x81C, 0xEF9A0001,
+ 0x81C, 0xEE9C0001,
+ 0x81C, 0xED9E0001,
+ 0x81C, 0xECA00001,
+ 0x81C, 0xEBA20001,
+ 0x81C, 0xEAA40001,
+ 0x81C, 0xE9A60001,
+ 0x81C, 0xE8A80001,
+ 0x81C, 0xE7AA0001,
+ 0x81C, 0xE6AC0001,
+ 0x81C, 0xE5AE0001,
+ 0x81C, 0xE4B00001,
+ 0x81C, 0xE3B20001,
+ 0x81C, 0xA8B40001,
+ 0x81C, 0xA7B60001,
+ 0x81C, 0xA6B80001,
+ 0x81C, 0xA5BA0001,
+ 0x81C, 0xA4BC0001,
+ 0x81C, 0xA3BE0001,
+ 0x81C, 0xA2C00001,
+ 0x81C, 0xA1C20001,
+ 0x81C, 0x68C40001,
+ 0x81C, 0x67C60001,
+ 0x81C, 0x66C80001,
+ 0x81C, 0x65CA0001,
+ 0x81C, 0x64CC0001,
+ 0x81C, 0x47CE0001,
+ 0x81C, 0x46D00001,
+ 0x81C, 0x45D20001,
+ 0x81C, 0x44D40001,
+ 0x81C, 0x43D60001,
+ 0x81C, 0x42D80001,
+ 0x81C, 0x08DA0001,
+ 0x81C, 0x07DC0001,
+ 0x81C, 0x06DE0001,
+ 0x81C, 0x05E00001,
+ 0x81C, 0x04E20001,
+ 0x81C, 0x03E40001,
+ 0x81C, 0x02E60001,
+ 0x81C, 0x01E80001,
+ 0x81C, 0x01EA0001,
+ 0x81C, 0x01EC0001,
+ 0x81C, 0x01EE0001,
+ 0x81C, 0x01F00001,
+ 0x81C, 0x01F20001,
+ 0x81C, 0x01F40001,
+ 0x81C, 0x01F60001,
+ 0x81C, 0x01F80001,
+ 0x81C, 0x01FA0001,
+ 0x81C, 0x01FC0001,
+ 0x81C, 0x01FE0001,
+ 0xA0000000, 0x00000000,
+ 0x81C, 0xFF800001,
+ 0x81C, 0xFF820001,
+ 0x81C, 0xFF840001,
+ 0x81C, 0xFE860001,
+ 0x81C, 0xFD880001,
+ 0x81C, 0xFC8A0001,
+ 0x81C, 0xFB8C0001,
+ 0x81C, 0xFA8E0001,
+ 0x81C, 0xF9900001,
+ 0x81C, 0xF8920001,
+ 0x81C, 0xF7940001,
+ 0x81C, 0xF6960001,
+ 0x81C, 0xF5980001,
+ 0x81C, 0xF49A0001,
+ 0x81C, 0xF39C0001,
+ 0x81C, 0xF29E0001,
+ 0x81C, 0xF1A00001,
+ 0x81C, 0xF0A20001,
+ 0x81C, 0xEFA40001,
+ 0x81C, 0xEEA60001,
+ 0x81C, 0xEDA80001,
+ 0x81C, 0xECAA0001,
+ 0x81C, 0xEBAC0001,
+ 0x81C, 0xEAAE0001,
+ 0x81C, 0xE9B00001,
+ 0x81C, 0xE8B20001,
+ 0x81C, 0xE7B40001,
+ 0x81C, 0xE6B60001,
+ 0x81C, 0xE5B80001,
+ 0x81C, 0xE4BA0001,
+ 0x81C, 0xE3BC0001,
+ 0x81C, 0xA8BE0001,
+ 0x81C, 0xA7C00001,
+ 0x81C, 0xA6C20001,
+ 0x81C, 0xA5C40001,
+ 0x81C, 0xA4C60001,
+ 0x81C, 0xA3C80001,
+ 0x81C, 0xA2CA0001,
+ 0x81C, 0xA1CC0001,
+ 0x81C, 0x68CE0001,
+ 0x81C, 0x67D00001,
+ 0x81C, 0x66D20001,
+ 0x81C, 0x65D40001,
+ 0x81C, 0x64D60001,
+ 0x81C, 0x47D80001,
+ 0x81C, 0x46DA0001,
+ 0x81C, 0x45DC0001,
+ 0x81C, 0x44DE0001,
+ 0x81C, 0x43E00001,
+ 0x81C, 0x42E20001,
+ 0x81C, 0x08E40001,
+ 0x81C, 0x07E60001,
+ 0x81C, 0x06E80001,
+ 0x81C, 0x05EA0001,
+ 0x81C, 0x04EC0001,
+ 0x81C, 0x03EE0001,
+ 0x81C, 0x02F00001,
+ 0x81C, 0x01F20001,
+ 0x81C, 0x01F40001,
+ 0x81C, 0x01F60001,
+ 0x81C, 0x01F80001,
+ 0x81C, 0x01FA0001,
+ 0x81C, 0x01FC0001,
+ 0x81C, 0x01FE0001,
+ 0xB0000000, 0x00000000,
+ 0xC50, 0x00000022,
+ 0xC50, 0x00000020,
+ 0xE50, 0x00000022,
+ 0xE50, 0x00000020,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8812a_agc, rtw_phy_cfg_agc);
+
+static const u32 rtw8812a_agc_diff_lb[] = {
+ 0x80000004, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0x47CE0001,
+ 0x81C, 0x46D00001,
+ 0x81C, 0x45D20001,
+ 0x81C, 0x44D40001,
+ 0x81C, 0x43D60001,
+ 0x81C, 0x42D80001,
+ 0x81C, 0x08DA0001,
+ 0x81C, 0x07DC0001,
+ 0x81C, 0x06DE0001,
+ 0x81C, 0x05E00001,
+ 0x81C, 0x04E20001,
+ 0x81C, 0x03E40001,
+ 0x81C, 0x02E60001,
+ 0xA0000000, 0x00000000,
+ 0x81C, 0x47D80001,
+ 0x81C, 0x46DA0001,
+ 0x81C, 0x45DC0001,
+ 0x81C, 0x44DE0001,
+ 0x81C, 0x43E00001,
+ 0x81C, 0x42E20001,
+ 0x81C, 0x08E40001,
+ 0x81C, 0x07E60001,
+ 0x81C, 0x06E80001,
+ 0x81C, 0x05EA0001,
+ 0x81C, 0x04EC0001,
+ 0x81C, 0x03EE0001,
+ 0x81C, 0x02F00001,
+ 0xB0000000, 0x00000000,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_lb, rtw_phy_cfg_agc);
+
+static const u32 rtw8812a_agc_diff_hb[] = {
+ 0x80000004, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0x45CE0001,
+ 0x81C, 0x44D00001,
+ 0x81C, 0x43D20001,
+ 0x81C, 0x42D40001,
+ 0x81C, 0x08D60001,
+ 0x81C, 0x07D80001,
+ 0x81C, 0x06DA0001,
+ 0x81C, 0x05DC0001,
+ 0x81C, 0x04DE0001,
+ 0x81C, 0x03E00001,
+ 0x81C, 0x02E20001,
+ 0x81C, 0x01E40001,
+ 0x81C, 0x01E60001,
+ 0xA0000000, 0x00000000,
+ 0x81C, 0x45D80001,
+ 0x81C, 0x44DA0001,
+ 0x81C, 0x43DC0001,
+ 0x81C, 0x42DE0001,
+ 0x81C, 0x08E00001,
+ 0x81C, 0x07E20001,
+ 0x81C, 0x06E40001,
+ 0x81C, 0x05E60001,
+ 0x81C, 0x04E80001,
+ 0x81C, 0x03EA0001,
+ 0x81C, 0x02EC0001,
+ 0x81C, 0x01EE0001,
+ 0x81C, 0x01F00001,
+ 0xB0000000, 0x00000000,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_hb, rtw_phy_cfg_agc);
+
+static const u32 rtw8812a_bb[] = {
+ 0x800, 0x8020D010,
+ 0x804, 0x080112E0,
+ 0x808, 0x0E028233,
+ 0x80C, 0x12131113,
+ 0x810, 0x20101263,
+ 0x814, 0x020C3D10,
+ 0x818, 0x03A00385,
+ 0x820, 0x00000000,
+ 0x824, 0x00030FE0,
+ 0x828, 0x00000000,
+ 0x82C, 0x002083DD,
+ 0x830, 0x2EAAEEB8,
+ 0x834, 0x0037A706,
+ 0x838, 0x06C89B44,
+ 0x83C, 0x0000095B,
+ 0x840, 0xC0000001,
+ 0x844, 0x40003CDE,
+ 0x848, 0x6210FF8B,
+ 0x84C, 0x6CFDFFB8,
+ 0x850, 0x28874706,
+ 0x854, 0x0001520C,
+ 0x858, 0x8060E000,
+ 0x85C, 0x74210168,
+ 0x860, 0x6929C321,
+ 0x864, 0x79727432,
+ 0x868, 0x8CA7A314,
+ 0x86C, 0x338C2878,
+ 0x870, 0x03333333,
+ 0x874, 0x31602C2E,
+ 0x878, 0x00003152,
+ 0x87C, 0x000FC000,
+ 0x8A0, 0x00000013,
+ 0x8A4, 0x7F7F7F7F,
+ 0x8A8, 0xA202033E,
+ 0x8AC, 0x0FF0FA0A,
+ 0x8B0, 0x00000600,
+ 0x8B4, 0x000FC080,
+ 0x8B8, 0x6C10D7FF,
+ 0x8BC, 0x4CA520A3,
+ 0x8C0, 0x27F00020,
+ 0x8C4, 0x00000000,
+ 0x8C8, 0x00012D69,
+ 0x8CC, 0x08248492,
+ 0x8D0, 0x0000B800,
+ 0x8DC, 0x00000000,
+ 0x8D4, 0x940008A0,
+ 0x8D8, 0x290B5612,
+ 0x8F8, 0x400002C0,
+ 0x8FC, 0x00000000,
+ 0x900, 0x00000701,
+ 0x90C, 0x00000000,
+ 0x910, 0x0000FC00,
+ 0x914, 0x00000404,
+ 0x918, 0x1C1028C0,
+ 0x91C, 0x64B11A1C,
+ 0x920, 0xE0767233,
+ 0x924, 0x055AA500,
+ 0x928, 0x00000004,
+ 0x92C, 0xFFFE0000,
+ 0x930, 0xFFFFFFFE,
+ 0x934, 0x001FFFFF,
+ 0x960, 0x00000000,
+ 0x964, 0x00000000,
+ 0x968, 0x00000000,
+ 0x96C, 0x00000000,
+ 0x970, 0x801FFFFF,
+ 0x978, 0x00000000,
+ 0x97C, 0x00000000,
+ 0x980, 0x00000000,
+ 0x984, 0x00000000,
+ 0x988, 0x00000000,
+ 0x990, 0x27100000,
+ 0x994, 0xFFFF0100,
+ 0x998, 0xFFFFFF5C,
+ 0x99C, 0xFFFFFFFF,
+ 0x9A0, 0x000000FF,
+ 0x9A4, 0x00080080,
+ 0x9A8, 0x00000000,
+ 0x9AC, 0x00000000,
+ 0x9B0, 0x81081008,
+ 0x9B4, 0x00000000,
+ 0x9B8, 0x01081008,
+ 0x9BC, 0x01081008,
+ 0x9D0, 0x00000000,
+ 0x9D4, 0x00000000,
+ 0x9D8, 0x00000000,
+ 0x9DC, 0x00000000,
+ 0x9E4, 0x00000003,
+ 0x9E8, 0x000002D5,
+ 0xA00, 0x00D047C8,
+ 0xA04, 0x01FF000C,
+ 0xA08, 0x8C838300,
+ 0xA0C, 0x2E7F000F,
+ 0xA10, 0x9500BB78,
+ 0xA14, 0x11144028,
+ 0xA18, 0x00881117,
+ 0xA1C, 0x89140F00,
+ 0xA20, 0x1A1B0000,
+ 0xA24, 0x090E1217,
+ 0xA28, 0x00000305,
+ 0xA2C, 0x00900000,
+ 0xA70, 0x101FFF00,
+ 0xA74, 0x00000008,
+ 0xA78, 0x00000900,
+ 0xA7C, 0x225B0606,
+ 0xA80, 0x218075B2,
+ 0xA84, 0x001F8C80,
+ 0xB00, 0x03100000,
+ 0xB04, 0x0000B000,
+ 0xB08, 0xAE0201EB,
+ 0xB0C, 0x01003207,
+ 0xB10, 0x00009807,
+ 0xB14, 0x01000000,
+ 0xB18, 0x00000002,
+ 0xB1C, 0x00000002,
+ 0xB20, 0x0000001F,
+ 0xB24, 0x03020100,
+ 0xB28, 0x07060504,
+ 0xB2C, 0x0B0A0908,
+ 0xB30, 0x0F0E0D0C,
+ 0xB34, 0x13121110,
+ 0xB38, 0x17161514,
+ 0xB3C, 0x0000003A,
+ 0xB40, 0x00000000,
+ 0xB44, 0x00000000,
+ 0xB48, 0x13000032,
+ 0xB4C, 0x48080000,
+ 0xB50, 0x00000000,
+ 0xB54, 0x00000000,
+ 0xB58, 0x00000000,
+ 0xB5C, 0x00000000,
+ 0xC00, 0x00000007,
+ 0xC04, 0x00042020,
+ 0xC08, 0x80410231,
+ 0xC0C, 0x00000000,
+ 0xC10, 0x00000100,
+ 0xC14, 0x01000000,
+ 0xC1C, 0x40000003,
+ 0xC20, 0x12121212,
+ 0xC24, 0x12121212,
+ 0xC28, 0x12121212,
+ 0xC2C, 0x12121212,
+ 0xC30, 0x12121212,
+ 0xC34, 0x12121212,
+ 0xC38, 0x12121212,
+ 0xC3C, 0x12121212,
+ 0xC40, 0x12121212,
+ 0xC44, 0x12121212,
+ 0xC48, 0x12121212,
+ 0xC4C, 0x12121212,
+ 0xC50, 0x00000020,
+ 0xC54, 0x0008121C,
+ 0xC58, 0x30000C1C,
+ 0xC5C, 0x00000058,
+ 0xC60, 0x34344443,
+ 0xC64, 0x07003333,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0x90000002, 0x00000000, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0x90000004, 0x00000000, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0x90000001, 0x00000000, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0xC68, 0x59791979,
+ 0xA0000000, 0x00000000,
+ 0xC68, 0x59799979,
+ 0xB0000000, 0x00000000,
+ 0xC6C, 0x59795979,
+ 0xC70, 0x19795979,
+ 0xC74, 0x19795979,
+ 0xC78, 0x19791979,
+ 0xC7C, 0x19791979,
+ 0xC80, 0x19791979,
+ 0xC84, 0x19791979,
+ 0xC94, 0x0100005C,
+ 0xC98, 0x00000000,
+ 0xC9C, 0x00000000,
+ 0xCA0, 0x00000029,
+ 0xCA4, 0x08040201,
+ 0xCA8, 0x80402010,
+ 0xCB0, 0x77547777,
+ 0xCB4, 0x00000077,
+ 0xCB8, 0x00508242,
+ 0xE00, 0x00000007,
+ 0xE04, 0x00042020,
+ 0xE08, 0x80410231,
+ 0xE0C, 0x00000000,
+ 0xE10, 0x00000100,
+ 0xE14, 0x01000000,
+ 0xE1C, 0x40000003,
+ 0xE20, 0x12121212,
+ 0xE24, 0x12121212,
+ 0xE28, 0x12121212,
+ 0xE2C, 0x12121212,
+ 0xE30, 0x12121212,
+ 0xE34, 0x12121212,
+ 0xE38, 0x12121212,
+ 0xE3C, 0x12121212,
+ 0xE40, 0x12121212,
+ 0xE44, 0x12121212,
+ 0xE48, 0x12121212,
+ 0xE4C, 0x12121212,
+ 0xE50, 0x00000020,
+ 0xE54, 0x0008121C,
+ 0xE58, 0x30000C1C,
+ 0xE5C, 0x00000058,
+ 0xE60, 0x34344443,
+ 0xE64, 0x07003333,
+ 0xE68, 0x59791979,
+ 0xE6C, 0x59795979,
+ 0xE70, 0x19795979,
+ 0xE74, 0x19795979,
+ 0xE78, 0x19791979,
+ 0xE7C, 0x19791979,
+ 0xE80, 0x19791979,
+ 0xE84, 0x19791979,
+ 0xE94, 0x0100005C,
+ 0xE98, 0x00000000,
+ 0xE9C, 0x00000000,
+ 0xEA0, 0x00000029,
+ 0xEA4, 0x08040201,
+ 0xEA8, 0x80402010,
+ 0xEB0, 0x77547777,
+ 0xEB4, 0x00000077,
+ 0xEB8, 0x00508242,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8812a_bb, rtw_phy_cfg_bb);
+
+static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg[] = {
+ { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34363840, },
+ { 0, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, },
+ { 0, 0, 0, 0x00000c28, 0xffffffff, 0x30323638, },
+ { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, },
+ { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, },
+ { 0, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, },
+ { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, },
+ { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, },
+ { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, },
+ { 0, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, },
+ { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, },
+ { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, },
+ { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34363840, },
+ { 0, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, },
+ { 0, 1, 0, 0x00000e28, 0xffffffff, 0x30323638, },
+ { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, },
+ { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, },
+ { 0, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, },
+ { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, },
+ { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, },
+ { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, },
+ { 0, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, },
+ { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, },
+ { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, },
+ { 1, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, },
+ { 1, 0, 0, 0x00000c28, 0xffffffff, 0x30323640, },
+ { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, },
+ { 1, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, },
+ { 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, },
+ { 1, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, },
+ { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, },
+ { 1, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, },
+ { 1, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, },
+ { 1, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, },
+ { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, },
+ { 1, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, },
+ { 1, 1, 0, 0x00000e28, 0xffffffff, 0x30323640, },
+ { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, },
+ { 1, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, },
+ { 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, },
+ { 1, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, },
+ { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, },
+ { 1, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, },
+ { 1, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, },
+ { 1, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, },
+ { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, },
+};
+
+RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg);
+
+static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg_rfe3[] = {
+ { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34343434, },
+ { 0, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, },
+ { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, },
+ { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, },
+ { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303232, },
+ { 0, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, },
+ { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, },
+ { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, },
+ { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303232, },
+ { 0, 0, 0, 0x00000c44, 0xffffffff, 0x32322426, },
+ { 0, 0, 1, 0x00000c48, 0xffffffff, 0x32323232, },
+ { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x24262830, },
+ { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34343434, },
+ { 0, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, },
+ { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, },
+ { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, },
+ { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303232, },
+ { 0, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, },
+ { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, },
+ { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, },
+ { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303232, },
+ { 0, 1, 0, 0x00000e44, 0xffffffff, 0x32322426, },
+ { 0, 1, 1, 0x00000e48, 0xffffffff, 0x32323232, },
+ { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x24262830, },
+ { 1, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, },
+ { 1, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, },
+ { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, },
+ { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, },
+ { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, },
+ { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, },
+ { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, },
+ { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, },
+ { 1, 0, 0, 0x00000c44, 0xffffffff, 0x32322222, },
+ { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303232, },
+ { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22222426, },
+ { 1, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, },
+ { 1, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, },
+ { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, },
+ { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, },
+ { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, },
+ { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, },
+ { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, },
+ { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, },
+ { 1, 1, 0, 0x00000e44, 0xffffffff, 0x32322222, },
+ { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303232, },
+ { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22222426, },
+};
+
+RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg_rfe3);
+
+static const u32 rtw8812a_rf_a[] = {
+ 0x000, 0x00010000,
+ 0x018, 0x0001712A,
+ 0x056, 0x00051CF2,
+ 0x066, 0x00040000,
+ 0x01E, 0x00080000,
+ 0x089, 0x00000080,
+ 0x80000001, 0x00000000, 0x40000000, 0x00000000,
+ 0x086, 0x00014B3A,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0x086, 0x00014B3A,
+ 0xA0000000, 0x00000000,
+ 0x086, 0x00014B38,
+ 0xB0000000, 0x00000000,
+ 0x80000004, 0x00000000, 0x40000000, 0x00000000,
+ 0x08B, 0x00080180,
+ 0xA0000000, 0x00000000,
+ 0x08B, 0x00087180,
+ 0xB0000000, 0x00000000,
+ 0x0B1, 0x0001FC1A,
+ 0x0B3, 0x000F0810,
+ 0x0B4, 0x0001A78D,
+ 0x0BA, 0x00086180,
+ 0x018, 0x00000006,
+ 0x0EF, 0x00002000,
+ 0x80000001, 0x00000000, 0x40000000, 0x00000000,
+ 0x03B, 0x0003F218,
+ 0x03B, 0x00030A58,
+ 0x03B, 0x0002FA58,
+ 0x03B, 0x00022590,
+ 0x03B, 0x0001FA50,
+ 0x03B, 0x00010248,
+ 0x03B, 0x00008240,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0x03B, 0x0003F218,
+ 0x03B, 0x00030A58,
+ 0x03B, 0x0002FA58,
+ 0x03B, 0x00022590,
+ 0x03B, 0x0001FA50,
+ 0x03B, 0x00010248,
+ 0x03B, 0x00008240,
+ 0xA0000000, 0x00000000,
+ 0x03B, 0x00038A58,
+ 0x03B, 0x00037A58,
+ 0x03B, 0x0002A590,
+ 0x03B, 0x00027A50,
+ 0x03B, 0x00018248,
+ 0x03B, 0x00010240,
+ 0x03B, 0x00008240,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000100,
+ 0x80000002, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A4EE,
+ 0x034, 0x00009076,
+ 0x034, 0x00008073,
+ 0x034, 0x00007070,
+ 0x034, 0x0000606D,
+ 0x034, 0x0000506A,
+ 0x034, 0x00004049,
+ 0x034, 0x00003046,
+ 0x034, 0x00002028,
+ 0x034, 0x00001025,
+ 0x034, 0x00000022,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0000ADF4,
+ 0x034, 0x00009DF1,
+ 0x034, 0x00008DEE,
+ 0x034, 0x00007DEB,
+ 0x034, 0x00006DE8,
+ 0x034, 0x00005DE5,
+ 0x034, 0x00004DE2,
+ 0x034, 0x00003CE6,
+ 0x034, 0x000024E7,
+ 0x034, 0x000014E4,
+ 0x034, 0x000004E1,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x000020A2,
+ 0x0DF, 0x00000080,
+ 0x035, 0x00000192,
+ 0x035, 0x00008192,
+ 0x035, 0x00010192,
+ 0x036, 0x00000024,
+ 0x036, 0x00008024,
+ 0x036, 0x00010024,
+ 0x036, 0x00018024,
+ 0x0EF, 0x00000000,
+ 0x051, 0x00000C21,
+ 0x052, 0x000006D9,
+ 0x053, 0x000FC649,
+ 0x054, 0x0000017E,
+ 0x0EF, 0x00000002,
+ 0x008, 0x00008400,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00001000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x0003A02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x0003202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x0002B064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x00023070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0001B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00012085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0000A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00002080,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x0007A02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x0007202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x0006B064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x00063070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0005B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00052085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0004A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00042080,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x000BA02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x000B202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x000AB064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x000A3070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0009B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00092085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0008A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00082080,
+ 0x03C, 0x00010000,
+ 0x0EF, 0x00001100,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0B2,
+ 0x034, 0x000490AF,
+ 0x034, 0x00048070,
+ 0x034, 0x0004706D,
+ 0x034, 0x00046050,
+ 0x034, 0x0004504D,
+ 0x034, 0x0004404A,
+ 0x034, 0x00043047,
+ 0x034, 0x0004200A,
+ 0x034, 0x00041007,
+ 0x034, 0x00040004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0B2,
+ 0x034, 0x000490AF,
+ 0x034, 0x00048070,
+ 0x034, 0x0004706D,
+ 0x034, 0x0004604D,
+ 0x034, 0x0004504A,
+ 0x034, 0x00044047,
+ 0x034, 0x00043044,
+ 0x034, 0x00042007,
+ 0x034, 0x00041004,
+ 0x034, 0x00040001,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0004ADF5,
+ 0x034, 0x00049DF2,
+ 0x034, 0x00048DEF,
+ 0x034, 0x00047DEC,
+ 0x034, 0x00046DE9,
+ 0x034, 0x00045DE6,
+ 0x034, 0x00044DE3,
+ 0x034, 0x000438C8,
+ 0x034, 0x000428C5,
+ 0x034, 0x000418C2,
+ 0x034, 0x000408C0,
+ 0xB0000000, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0B2,
+ 0x034, 0x000290AF,
+ 0x034, 0x00028070,
+ 0x034, 0x0002706D,
+ 0x034, 0x00026050,
+ 0x034, 0x0002504D,
+ 0x034, 0x0002404A,
+ 0x034, 0x00023047,
+ 0x034, 0x0002200A,
+ 0x034, 0x00021007,
+ 0x034, 0x00020004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0B4,
+ 0x034, 0x000290B1,
+ 0x034, 0x00028072,
+ 0x034, 0x0002706F,
+ 0x034, 0x0002604F,
+ 0x034, 0x0002504C,
+ 0x034, 0x00024049,
+ 0x034, 0x00023046,
+ 0x034, 0x00022009,
+ 0x034, 0x00021006,
+ 0x034, 0x00020003,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0002ADF5,
+ 0x034, 0x00029DF2,
+ 0x034, 0x00028DEF,
+ 0x034, 0x00027DEC,
+ 0x034, 0x00026DE9,
+ 0x034, 0x00025DE6,
+ 0x034, 0x00024DE3,
+ 0x034, 0x000238C8,
+ 0x034, 0x000228C5,
+ 0x034, 0x000218C2,
+ 0x034, 0x000208C0,
+ 0xB0000000, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0B2,
+ 0x034, 0x000090AF,
+ 0x034, 0x00008070,
+ 0x034, 0x0000706D,
+ 0x034, 0x00006050,
+ 0x034, 0x0000504D,
+ 0x034, 0x0000404A,
+ 0x034, 0x00003047,
+ 0x034, 0x0000200A,
+ 0x034, 0x00001007,
+ 0x034, 0x00000004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0B2,
+ 0x034, 0x000090AF,
+ 0x034, 0x00008070,
+ 0x034, 0x0000706D,
+ 0x034, 0x0000604D,
+ 0x034, 0x0000504A,
+ 0x034, 0x00004047,
+ 0x034, 0x00003044,
+ 0x034, 0x00002007,
+ 0x034, 0x00001004,
+ 0x034, 0x00000001,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0000AFF7,
+ 0x034, 0x00009DF7,
+ 0x034, 0x00008DF4,
+ 0x034, 0x00007DF1,
+ 0x034, 0x00006DEE,
+ 0x034, 0x00005DEB,
+ 0x034, 0x00004DE8,
+ 0x034, 0x000038CC,
+ 0x034, 0x000028C9,
+ 0x034, 0x000018C6,
+ 0x034, 0x000008C3,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x000001D4,
+ 0x035, 0x000081D4,
+ 0x035, 0x000101D4,
+ 0x035, 0x000201B4,
+ 0x035, 0x000281B4,
+ 0x035, 0x000301B4,
+ 0x035, 0x000401B4,
+ 0x035, 0x000481B4,
+ 0x035, 0x000501B4,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x000001D4,
+ 0x035, 0x000081D4,
+ 0x035, 0x000101D4,
+ 0x035, 0x000201B4,
+ 0x035, 0x000281B4,
+ 0x035, 0x000301B4,
+ 0x035, 0x000401B4,
+ 0x035, 0x000481B4,
+ 0x035, 0x000501B4,
+ 0xA0000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x00000188,
+ 0x035, 0x00008147,
+ 0x035, 0x00010147,
+ 0x035, 0x000201D7,
+ 0x035, 0x000281D7,
+ 0x035, 0x000301D7,
+ 0x035, 0x000401D8,
+ 0x035, 0x000481D8,
+ 0x035, 0x000501D8,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00004BFB,
+ 0x036, 0x0000CBFB,
+ 0x036, 0x00014BFB,
+ 0x036, 0x0001CBFB,
+ 0x036, 0x00024F4B,
+ 0x036, 0x0002CF4B,
+ 0x036, 0x00034F4B,
+ 0x036, 0x0003CF4B,
+ 0x036, 0x00044F4B,
+ 0x036, 0x0004CF4B,
+ 0x036, 0x00054F4B,
+ 0x036, 0x0005CF4B,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00004BFB,
+ 0x036, 0x0000CBFB,
+ 0x036, 0x00014BFB,
+ 0x036, 0x0001CBFB,
+ 0x036, 0x00024F4B,
+ 0x036, 0x0002CF4B,
+ 0x036, 0x00034F4B,
+ 0x036, 0x0003CF4B,
+ 0x036, 0x00044F4B,
+ 0x036, 0x0004CF4B,
+ 0x036, 0x00054F4B,
+ 0x036, 0x0005CF4B,
+ 0xA0000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00084EB4,
+ 0x036, 0x0008CC35,
+ 0x036, 0x00094C35,
+ 0x036, 0x0009CC35,
+ 0x036, 0x000A4C35,
+ 0x036, 0x000ACC35,
+ 0x036, 0x000B4C35,
+ 0x036, 0x000BCC35,
+ 0x036, 0x000C4C34,
+ 0x036, 0x000CCC35,
+ 0x036, 0x000D4C35,
+ 0x036, 0x000DCC35,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00000008,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000002CC,
+ 0x03C, 0x00000522,
+ 0x03C, 0x00000902,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000002CC,
+ 0x03C, 0x00000522,
+ 0x03C, 0x00000902,
+ 0xA0000000, 0x00000000,
+ 0x03C, 0x000002A8,
+ 0x03C, 0x000005A2,
+ 0x03C, 0x00000880,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000002,
+ 0x0DF, 0x00000080,
+ 0x01F, 0x00000064,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000FDD43,
+ 0x062, 0x00038F4B,
+ 0x063, 0x00032117,
+ 0x064, 0x000194AC,
+ 0x065, 0x000931D1,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x061, 0x000FDD43,
+ 0x062, 0x00038F4B,
+ 0x063, 0x00032117,
+ 0x064, 0x000194AC,
+ 0x065, 0x000931D2,
+ 0xA0000000, 0x00000000,
+ 0x061, 0x000E5D53,
+ 0x062, 0x00038FCD,
+ 0x063, 0x000114EB,
+ 0x064, 0x000196AC,
+ 0x065, 0x000911D7,
+ 0xB0000000, 0x00000000,
+ 0x008, 0x00008400,
+ 0x01C, 0x000739D2,
+ 0x0B4, 0x0001E78D,
+ 0x018, 0x0001F12A,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x0B4, 0x0001A78D,
+ 0x018, 0x0001712A,
+};
+
+RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_a, A);
+
+static const u32 rtw8812a_rf_b[] = {
+ 0x056, 0x00051CF2,
+ 0x066, 0x00040000,
+ 0x089, 0x00000080,
+ 0x80000001, 0x00000000, 0x40000000, 0x00000000,
+ 0x086, 0x00014B3A,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0x086, 0x00014B3A,
+ 0xA0000000, 0x00000000,
+ 0x086, 0x00014B38,
+ 0xB0000000, 0x00000000,
+ 0x80000004, 0x00000000, 0x40000000, 0x00000000,
+ 0x08B, 0x00080180,
+ 0xA0000000, 0x00000000,
+ 0x08B, 0x00087180,
+ 0xB0000000, 0x00000000,
+ 0x018, 0x00000006,
+ 0x0EF, 0x00002000,
+ 0x80000001, 0x00000000, 0x40000000, 0x00000000,
+ 0x03B, 0x0003F218,
+ 0x03B, 0x00030A58,
+ 0x03B, 0x0002FA58,
+ 0x03B, 0x00022590,
+ 0x03B, 0x0001FA50,
+ 0x03B, 0x00010248,
+ 0x03B, 0x00008240,
+ 0x90000001, 0x00000005, 0x40000000, 0x00000000,
+ 0x03B, 0x0003F218,
+ 0x03B, 0x00030A58,
+ 0x03B, 0x0002FA58,
+ 0x03B, 0x00022590,
+ 0x03B, 0x0001FA50,
+ 0x03B, 0x00010248,
+ 0x03B, 0x00008240,
+ 0xA0000000, 0x00000000,
+ 0x03B, 0x00038A58,
+ 0x03B, 0x00037A58,
+ 0x03B, 0x0002A590,
+ 0x03B, 0x00027A50,
+ 0x03B, 0x00018248,
+ 0x03B, 0x00010240,
+ 0x03B, 0x00008240,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000100,
+ 0x80000002, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A4EE,
+ 0x034, 0x00009076,
+ 0x034, 0x00008073,
+ 0x034, 0x00007070,
+ 0x034, 0x0000606D,
+ 0x034, 0x0000506A,
+ 0x034, 0x00004049,
+ 0x034, 0x00003046,
+ 0x034, 0x00002028,
+ 0x034, 0x00001025,
+ 0x034, 0x00000022,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0000ADF4,
+ 0x034, 0x00009DF1,
+ 0x034, 0x00008DEE,
+ 0x034, 0x00007DEB,
+ 0x034, 0x00006DE8,
+ 0x034, 0x00005DE5,
+ 0x034, 0x00004DE2,
+ 0x034, 0x00003CE6,
+ 0x034, 0x000024E7,
+ 0x034, 0x000014E4,
+ 0x034, 0x000004E1,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x000020A2,
+ 0x0DF, 0x00000080,
+ 0x035, 0x00000192,
+ 0x035, 0x00008192,
+ 0x035, 0x00010192,
+ 0x036, 0x00000024,
+ 0x036, 0x00008024,
+ 0x036, 0x00010024,
+ 0x036, 0x00018024,
+ 0x0EF, 0x00000000,
+ 0x051, 0x00000C21,
+ 0x052, 0x000006D9,
+ 0x053, 0x000FC649,
+ 0x054, 0x0000017E,
+ 0x0EF, 0x00000002,
+ 0x008, 0x00008400,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00001000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x0003A02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x0003202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x0002B064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x00023070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0001B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00012085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0000A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00002080,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x0007A02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x0007202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x0006B064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x00063070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0005B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00052085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0004A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00042080,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000080,
+ 0x03B, 0x000BA02C,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000400,
+ 0x03B, 0x000B202C,
+ 0x03C, 0x00010000,
+ 0x03A, 0x000000A0,
+ 0x03B, 0x000AB064,
+ 0x03C, 0x00004000,
+ 0x03A, 0x000000D8,
+ 0x03B, 0x000A3070,
+ 0x03C, 0x00004000,
+ 0x03A, 0x00000468,
+ 0x03B, 0x0009B870,
+ 0x03C, 0x00010000,
+ 0x03A, 0x00000098,
+ 0x03B, 0x00092085,
+ 0x03C, 0x000E4000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x0008A080,
+ 0x03C, 0x000F0000,
+ 0x03A, 0x00000418,
+ 0x03B, 0x00082080,
+ 0x03C, 0x00010000,
+ 0x0EF, 0x00001100,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0B2,
+ 0x034, 0x000490AF,
+ 0x034, 0x00048070,
+ 0x034, 0x0004706D,
+ 0x034, 0x00046050,
+ 0x034, 0x0004504D,
+ 0x034, 0x0004404A,
+ 0x034, 0x00043047,
+ 0x034, 0x0004200A,
+ 0x034, 0x00041007,
+ 0x034, 0x00040004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0B1,
+ 0x034, 0x000490AE,
+ 0x034, 0x0004806F,
+ 0x034, 0x0004706C,
+ 0x034, 0x0004604C,
+ 0x034, 0x00045049,
+ 0x034, 0x00044046,
+ 0x034, 0x00043043,
+ 0x034, 0x00042006,
+ 0x034, 0x00041003,
+ 0x034, 0x00040000,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0004ADF5,
+ 0x034, 0x00049DF2,
+ 0x034, 0x00048DEF,
+ 0x034, 0x00047DEC,
+ 0x034, 0x00046DE9,
+ 0x034, 0x00045DE6,
+ 0x034, 0x00044DE3,
+ 0x034, 0x000438C8,
+ 0x034, 0x000428C5,
+ 0x034, 0x000418C2,
+ 0x034, 0x000408C0,
+ 0xB0000000, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0B2,
+ 0x034, 0x000290AF,
+ 0x034, 0x00028070,
+ 0x034, 0x0002706D,
+ 0x034, 0x00026050,
+ 0x034, 0x0002504D,
+ 0x034, 0x0002404A,
+ 0x034, 0x00023047,
+ 0x034, 0x0002200A,
+ 0x034, 0x00021007,
+ 0x034, 0x00020004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0B3,
+ 0x034, 0x000290B0,
+ 0x034, 0x00028071,
+ 0x034, 0x0002706E,
+ 0x034, 0x0002604E,
+ 0x034, 0x0002504B,
+ 0x034, 0x00024048,
+ 0x034, 0x00023045,
+ 0x034, 0x00022008,
+ 0x034, 0x00021005,
+ 0x034, 0x00020002,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0002ADF5,
+ 0x034, 0x00029DF2,
+ 0x034, 0x00028DEF,
+ 0x034, 0x00027DEC,
+ 0x034, 0x00026DE9,
+ 0x034, 0x00025DE6,
+ 0x034, 0x00024DE3,
+ 0x034, 0x000238C8,
+ 0x034, 0x000228C5,
+ 0x034, 0x000218C2,
+ 0x034, 0x000208C0,
+ 0xB0000000, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0B2,
+ 0x034, 0x000090AF,
+ 0x034, 0x00008070,
+ 0x034, 0x0000706D,
+ 0x034, 0x00006050,
+ 0x034, 0x0000504D,
+ 0x034, 0x0000404A,
+ 0x034, 0x00003047,
+ 0x034, 0x0000200A,
+ 0x034, 0x00001007,
+ 0x034, 0x00000004,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0B3,
+ 0x034, 0x000090B0,
+ 0x034, 0x00008070,
+ 0x034, 0x0000706D,
+ 0x034, 0x0000604D,
+ 0x034, 0x0000504A,
+ 0x034, 0x00004047,
+ 0x034, 0x00003044,
+ 0x034, 0x00002007,
+ 0x034, 0x00001004,
+ 0x034, 0x00000001,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0000AFF7,
+ 0x034, 0x00009DF7,
+ 0x034, 0x00008DF4,
+ 0x034, 0x00007DF1,
+ 0x034, 0x00006DEE,
+ 0x034, 0x00005DEB,
+ 0x034, 0x00004DE8,
+ 0x034, 0x000038CC,
+ 0x034, 0x000028C9,
+ 0x034, 0x000018C6,
+ 0x034, 0x000008C3,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x000001C5,
+ 0x035, 0x000081C5,
+ 0x035, 0x000101C5,
+ 0x035, 0x00020174,
+ 0x035, 0x00028174,
+ 0x035, 0x00030174,
+ 0x035, 0x00040185,
+ 0x035, 0x00048185,
+ 0x035, 0x00050185,
+ 0x0EF, 0x00000000,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x000001C5,
+ 0x035, 0x000081C5,
+ 0x035, 0x000101C5,
+ 0x035, 0x00020174,
+ 0x035, 0x00028174,
+ 0x035, 0x00030174,
+ 0x035, 0x00040185,
+ 0x035, 0x00048185,
+ 0x035, 0x00050185,
+ 0x0EF, 0x00000000,
+ 0xA0000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x035, 0x00000188,
+ 0x035, 0x00008147,
+ 0x035, 0x00010147,
+ 0x035, 0x000201D7,
+ 0x035, 0x000281D7,
+ 0x035, 0x000301D7,
+ 0x035, 0x000401D8,
+ 0x035, 0x000481D8,
+ 0x035, 0x000501D8,
+ 0x0EF, 0x00000000,
+ 0xB0000000, 0x00000000,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00005B8B,
+ 0x036, 0x0000DB8B,
+ 0x036, 0x00015B8B,
+ 0x036, 0x0001DB8B,
+ 0x036, 0x000262DB,
+ 0x036, 0x0002E2DB,
+ 0x036, 0x000362DB,
+ 0x036, 0x0003E2DB,
+ 0x036, 0x0004553B,
+ 0x036, 0x0004D53B,
+ 0x036, 0x0005553B,
+ 0x036, 0x0005D53B,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00005B8B,
+ 0x036, 0x0000DB8B,
+ 0x036, 0x00015B8B,
+ 0x036, 0x0001DB8B,
+ 0x036, 0x000262DB,
+ 0x036, 0x0002E2DB,
+ 0x036, 0x000362DB,
+ 0x036, 0x0003E2DB,
+ 0x036, 0x0004553B,
+ 0x036, 0x0004D53B,
+ 0x036, 0x0005553B,
+ 0x036, 0x0005D53B,
+ 0xA0000000, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x036, 0x00084EB4,
+ 0x036, 0x0008CC35,
+ 0x036, 0x00094C35,
+ 0x036, 0x0009CC35,
+ 0x036, 0x000A4C35,
+ 0x036, 0x000ACC35,
+ 0x036, 0x000B4C35,
+ 0x036, 0x000BCC35,
+ 0x036, 0x000C4C34,
+ 0x036, 0x000CCC35,
+ 0x036, 0x000D4C35,
+ 0x036, 0x000DCC35,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00000008,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000002DC,
+ 0x03C, 0x00000524,
+ 0x03C, 0x00000902,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000002DC,
+ 0x03C, 0x00000524,
+ 0x03C, 0x00000902,
+ 0xA0000000, 0x00000000,
+ 0x03C, 0x000002A8,
+ 0x03C, 0x000005A2,
+ 0x03C, 0x00000880,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000002,
+ 0x0DF, 0x00000080,
+ 0x80000008, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EAC43,
+ 0x062, 0x00038F47,
+ 0x063, 0x00031157,
+ 0x064, 0x0001C4AC,
+ 0x065, 0x000931D1,
+ 0x90000008, 0x05000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EAC43,
+ 0x062, 0x00038F47,
+ 0x063, 0x00031157,
+ 0x064, 0x0001C4AC,
+ 0x065, 0x000931D2,
+ 0x90000002, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EAC43,
+ 0x062, 0x00038F47,
+ 0x063, 0x00031157,
+ 0x064, 0x0001C4AC,
+ 0x065, 0x000931D1,
+ 0xA0000000, 0x00000000,
+ 0x061, 0x000E5D53,
+ 0x062, 0x00038FCD,
+ 0x063, 0x000114EB,
+ 0x064, 0x000196AC,
+ 0x065, 0x000911D7,
+ 0xB0000000, 0x00000000,
+ 0x008, 0x00008400,
+};
+
+RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_b, B);
+
+static const struct rtw_txpwr_lmt_cfg_pair rtw8812a_txpwr_lmt[] = {
+ { 0, 0, 0, 0, 1, 36, },
+ { 2, 0, 0, 0, 1, 32, },
+ { 1, 0, 0, 0, 1, 32, },
+ { 0, 0, 0, 0, 2, 36, },
+ { 2, 0, 0, 0, 2, 32, },
+ { 1, 0, 0, 0, 2, 32, },
+ { 0, 0, 0, 0, 3, 36, },
+ { 2, 0, 0, 0, 3, 32, },
+ { 1, 0, 0, 0, 3, 32, },
+ { 0, 0, 0, 0, 4, 36, },
+ { 2, 0, 0, 0, 4, 32, },
+ { 1, 0, 0, 0, 4, 32, },
+ { 0, 0, 0, 0, 5, 36, },
+ { 2, 0, 0, 0, 5, 32, },
+ { 1, 0, 0, 0, 5, 32, },
+ { 0, 0, 0, 0, 6, 36, },
+ { 2, 0, 0, 0, 6, 32, },
+ { 1, 0, 0, 0, 6, 32, },
+ { 0, 0, 0, 0, 7, 36, },
+ { 2, 0, 0, 0, 7, 32, },
+ { 1, 0, 0, 0, 7, 32, },
+ { 0, 0, 0, 0, 8, 36, },
+ { 2, 0, 0, 0, 8, 32, },
+ { 1, 0, 0, 0, 8, 32, },
+ { 0, 0, 0, 0, 9, 36, },
+ { 2, 0, 0, 0, 9, 32, },
+ { 1, 0, 0, 0, 9, 32, },
+ { 0, 0, 0, 0, 10, 36, },
+ { 2, 0, 0, 0, 10, 32, },
+ { 1, 0, 0, 0, 10, 32, },
+ { 0, 0, 0, 0, 11, 36, },
+ { 2, 0, 0, 0, 11, 32, },
+ { 1, 0, 0, 0, 11, 32, },
+ { 0, 0, 0, 0, 12, 63, },
+ { 2, 0, 0, 0, 12, 32, },
+ { 1, 0, 0, 0, 12, 32, },
+ { 0, 0, 0, 0, 13, 63, },
+ { 2, 0, 0, 0, 13, 32, },
+ { 1, 0, 0, 0, 13, 32, },
+ { 0, 0, 0, 0, 14, 63, },
+ { 2, 0, 0, 0, 14, 63, },
+ { 1, 0, 0, 0, 14, 32, },
+ { 0, 0, 0, 1, 1, 34, },
+ { 2, 0, 0, 1, 1, 32, },
+ { 1, 0, 0, 1, 1, 32, },
+ { 0, 0, 0, 1, 2, 36, },
+ { 2, 0, 0, 1, 2, 32, },
+ { 1, 0, 0, 1, 2, 32, },
+ { 0, 0, 0, 1, 3, 36, },
+ { 2, 0, 0, 1, 3, 32, },
+ { 1, 0, 0, 1, 3, 32, },
+ { 0, 0, 0, 1, 4, 36, },
+ { 2, 0, 0, 1, 4, 32, },
+ { 1, 0, 0, 1, 4, 32, },
+ { 0, 0, 0, 1, 5, 36, },
+ { 2, 0, 0, 1, 5, 32, },
+ { 1, 0, 0, 1, 5, 32, },
+ { 0, 0, 0, 1, 6, 36, },
+ { 2, 0, 0, 1, 6, 32, },
+ { 1, 0, 0, 1, 6, 32, },
+ { 0, 0, 0, 1, 7, 36, },
+ { 2, 0, 0, 1, 7, 32, },
+ { 1, 0, 0, 1, 7, 32, },
+ { 0, 0, 0, 1, 8, 36, },
+ { 2, 0, 0, 1, 8, 32, },
+ { 1, 0, 0, 1, 8, 32, },
+ { 0, 0, 0, 1, 9, 36, },
+ { 2, 0, 0, 1, 9, 32, },
+ { 1, 0, 0, 1, 9, 32, },
+ { 0, 0, 0, 1, 10, 36, },
+ { 2, 0, 0, 1, 10, 32, },
+ { 1, 0, 0, 1, 10, 32, },
+ { 0, 0, 0, 1, 11, 32, },
+ { 2, 0, 0, 1, 11, 32, },
+ { 1, 0, 0, 1, 11, 32, },
+ { 0, 0, 0, 1, 12, 63, },
+ { 2, 0, 0, 1, 12, 32, },
+ { 1, 0, 0, 1, 12, 32, },
+ { 0, 0, 0, 1, 13, 63, },
+ { 2, 0, 0, 1, 13, 32, },
+ { 1, 0, 0, 1, 13, 32, },
+ { 0, 0, 0, 1, 14, 63, },
+ { 2, 0, 0, 1, 14, 63, },
+ { 1, 0, 0, 1, 14, 63, },
+ { 0, 0, 0, 2, 1, 34, },
+ { 2, 0, 0, 2, 1, 32, },
+ { 1, 0, 0, 2, 1, 32, },
+ { 0, 0, 0, 2, 2, 36, },
+ { 2, 0, 0, 2, 2, 32, },
+ { 1, 0, 0, 2, 2, 32, },
+ { 0, 0, 0, 2, 3, 36, },
+ { 2, 0, 0, 2, 3, 32, },
+ { 1, 0, 0, 2, 3, 32, },
+ { 0, 0, 0, 2, 4, 36, },
+ { 2, 0, 0, 2, 4, 32, },
+ { 1, 0, 0, 2, 4, 32, },
+ { 0, 0, 0, 2, 5, 36, },
+ { 2, 0, 0, 2, 5, 32, },
+ { 1, 0, 0, 2, 5, 32, },
+ { 0, 0, 0, 2, 6, 36, },
+ { 2, 0, 0, 2, 6, 32, },
+ { 1, 0, 0, 2, 6, 32, },
+ { 0, 0, 0, 2, 7, 36, },
+ { 2, 0, 0, 2, 7, 32, },
+ { 1, 0, 0, 2, 7, 32, },
+ { 0, 0, 0, 2, 8, 36, },
+ { 2, 0, 0, 2, 8, 32, },
+ { 1, 0, 0, 2, 8, 32, },
+ { 0, 0, 0, 2, 9, 36, },
+ { 2, 0, 0, 2, 9, 32, },
+ { 1, 0, 0, 2, 9, 32, },
+ { 0, 0, 0, 2, 10, 36, },
+ { 2, 0, 0, 2, 10, 32, },
+ { 1, 0, 0, 2, 10, 32, },
+ { 0, 0, 0, 2, 11, 32, },
+ { 2, 0, 0, 2, 11, 32, },
+ { 1, 0, 0, 2, 11, 32, },
+ { 0, 0, 0, 2, 12, 63, },
+ { 2, 0, 0, 2, 12, 32, },
+ { 1, 0, 0, 2, 12, 32, },
+ { 0, 0, 0, 2, 13, 63, },
+ { 2, 0, 0, 2, 13, 32, },
+ { 1, 0, 0, 2, 13, 32, },
+ { 0, 0, 0, 2, 14, 63, },
+ { 2, 0, 0, 2, 14, 63, },
+ { 1, 0, 0, 2, 14, 63, },
+ { 0, 0, 0, 3, 1, 32, },
+ { 2, 0, 0, 3, 1, 32, },
+ { 1, 0, 0, 3, 1, 32, },
+ { 0, 0, 0, 3, 2, 34, },
+ { 2, 0, 0, 3, 2, 32, },
+ { 1, 0, 0, 3, 2, 32, },
+ { 0, 0, 0, 3, 3, 34, },
+ { 2, 0, 0, 3, 3, 32, },
+ { 1, 0, 0, 3, 3, 32, },
+ { 0, 0, 0, 3, 4, 34, },
+ { 2, 0, 0, 3, 4, 32, },
+ { 1, 0, 0, 3, 4, 32, },
+ { 0, 0, 0, 3, 5, 34, },
+ { 2, 0, 0, 3, 5, 32, },
+ { 1, 0, 0, 3, 5, 32, },
+ { 0, 0, 0, 3, 6, 34, },
+ { 2, 0, 0, 3, 6, 32, },
+ { 1, 0, 0, 3, 6, 32, },
+ { 0, 0, 0, 3, 7, 34, },
+ { 2, 0, 0, 3, 7, 32, },
+ { 1, 0, 0, 3, 7, 32, },
+ { 0, 0, 0, 3, 8, 34, },
+ { 2, 0, 0, 3, 8, 32, },
+ { 1, 0, 0, 3, 8, 32, },
+ { 0, 0, 0, 3, 9, 34, },
+ { 2, 0, 0, 3, 9, 32, },
+ { 1, 0, 0, 3, 9, 32, },
+ { 0, 0, 0, 3, 10, 34, },
+ { 2, 0, 0, 3, 10, 32, },
+ { 1, 0, 0, 3, 10, 32, },
+ { 0, 0, 0, 3, 11, 30, },
+ { 2, 0, 0, 3, 11, 32, },
+ { 1, 0, 0, 3, 11, 32, },
+ { 0, 0, 0, 3, 12, 63, },
+ { 2, 0, 0, 3, 12, 32, },
+ { 1, 0, 0, 3, 12, 32, },
+ { 0, 0, 0, 3, 13, 63, },
+ { 2, 0, 0, 3, 13, 32, },
+ { 1, 0, 0, 3, 13, 32, },
+ { 0, 0, 0, 3, 14, 63, },
+ { 2, 0, 0, 3, 14, 63, },
+ { 1, 0, 0, 3, 14, 63, },
+ { 0, 0, 1, 2, 1, 63, },
+ { 2, 0, 1, 2, 1, 63, },
+ { 1, 0, 1, 2, 1, 63, },
+ { 0, 0, 1, 2, 2, 63, },
+ { 2, 0, 1, 2, 2, 63, },
+ { 1, 0, 1, 2, 2, 63, },
+ { 0, 0, 1, 2, 3, 32, },
+ { 2, 0, 1, 2, 3, 32, },
+ { 1, 0, 1, 2, 3, 32, },
+ { 0, 0, 1, 2, 4, 36, },
+ { 2, 0, 1, 2, 4, 32, },
+ { 1, 0, 1, 2, 4, 32, },
+ { 0, 0, 1, 2, 5, 36, },
+ { 2, 0, 1, 2, 5, 32, },
+ { 1, 0, 1, 2, 5, 32, },
+ { 0, 0, 1, 2, 6, 36, },
+ { 2, 0, 1, 2, 6, 32, },
+ { 1, 0, 1, 2, 6, 32, },
+ { 0, 0, 1, 2, 7, 36, },
+ { 2, 0, 1, 2, 7, 32, },
+ { 1, 0, 1, 2, 7, 32, },
+ { 0, 0, 1, 2, 8, 36, },
+ { 2, 0, 1, 2, 8, 32, },
+ { 1, 0, 1, 2, 8, 32, },
+ { 0, 0, 1, 2, 9, 36, },
+ { 2, 0, 1, 2, 9, 32, },
+ { 1, 0, 1, 2, 9, 32, },
+ { 0, 0, 1, 2, 10, 36, },
+ { 2, 0, 1, 2, 10, 32, },
+ { 1, 0, 1, 2, 10, 32, },
+ { 0, 0, 1, 2, 11, 32, },
+ { 2, 0, 1, 2, 11, 32, },
+ { 1, 0, 1, 2, 11, 32, },
+ { 0, 0, 1, 2, 12, 63, },
+ { 2, 0, 1, 2, 12, 32, },
+ { 1, 0, 1, 2, 12, 32, },
+ { 0, 0, 1, 2, 13, 63, },
+ { 2, 0, 1, 2, 13, 32, },
+ { 1, 0, 1, 2, 13, 32, },
+ { 0, 0, 1, 2, 14, 63, },
+ { 2, 0, 1, 2, 14, 63, },
+ { 1, 0, 1, 2, 14, 63, },
+ { 0, 0, 1, 3, 1, 63, },
+ { 2, 0, 1, 3, 1, 63, },
+ { 1, 0, 1, 3, 1, 63, },
+ { 0, 0, 1, 3, 2, 63, },
+ { 2, 0, 1, 3, 2, 63, },
+ { 1, 0, 1, 3, 2, 63, },
+ { 0, 0, 1, 3, 3, 30, },
+ { 2, 0, 1, 3, 3, 30, },
+ { 1, 0, 1, 3, 3, 30, },
+ { 0, 0, 1, 3, 4, 34, },
+ { 2, 0, 1, 3, 4, 30, },
+ { 1, 0, 1, 3, 4, 30, },
+ { 0, 0, 1, 3, 5, 34, },
+ { 2, 0, 1, 3, 5, 30, },
+ { 1, 0, 1, 3, 5, 30, },
+ { 0, 0, 1, 3, 6, 34, },
+ { 2, 0, 1, 3, 6, 30, },
+ { 1, 0, 1, 3, 6, 30, },
+ { 0, 0, 1, 3, 7, 34, },
+ { 2, 0, 1, 3, 7, 30, },
+ { 1, 0, 1, 3, 7, 30, },
+ { 0, 0, 1, 3, 8, 34, },
+ { 2, 0, 1, 3, 8, 30, },
+ { 1, 0, 1, 3, 8, 30, },
+ { 0, 0, 1, 3, 9, 34, },
+ { 2, 0, 1, 3, 9, 30, },
+ { 1, 0, 1, 3, 9, 30, },
+ { 0, 0, 1, 3, 10, 34, },
+ { 2, 0, 1, 3, 10, 30, },
+ { 1, 0, 1, 3, 10, 30, },
+ { 0, 0, 1, 3, 11, 30, },
+ { 2, 0, 1, 3, 11, 30, },
+ { 1, 0, 1, 3, 11, 30, },
+ { 0, 0, 1, 3, 12, 63, },
+ { 2, 0, 1, 3, 12, 32, },
+ { 1, 0, 1, 3, 12, 32, },
+ { 0, 0, 1, 3, 13, 63, },
+ { 2, 0, 1, 3, 13, 32, },
+ { 1, 0, 1, 3, 13, 32, },
+ { 0, 0, 1, 3, 14, 63, },
+ { 2, 0, 1, 3, 14, 63, },
+ { 1, 0, 1, 3, 14, 63, },
+ { 0, 1, 0, 1, 36, 30, },
+ { 2, 1, 0, 1, 36, 32, },
+ { 1, 1, 0, 1, 36, 32, },
+ { 0, 1, 0, 1, 40, 30, },
+ { 2, 1, 0, 1, 40, 32, },
+ { 1, 1, 0, 1, 40, 32, },
+ { 0, 1, 0, 1, 44, 30, },
+ { 2, 1, 0, 1, 44, 32, },
+ { 1, 1, 0, 1, 44, 32, },
+ { 0, 1, 0, 1, 48, 30, },
+ { 2, 1, 0, 1, 48, 32, },
+ { 1, 1, 0, 1, 48, 32, },
+ { 0, 1, 0, 1, 52, 36, },
+ { 2, 1, 0, 1, 52, 32, },
+ { 1, 1, 0, 1, 52, 32, },
+ { 0, 1, 0, 1, 56, 34, },
+ { 2, 1, 0, 1, 56, 32, },
+ { 1, 1, 0, 1, 56, 32, },
+ { 0, 1, 0, 1, 60, 32, },
+ { 2, 1, 0, 1, 60, 32, },
+ { 1, 1, 0, 1, 60, 32, },
+ { 0, 1, 0, 1, 64, 28, },
+ { 2, 1, 0, 1, 64, 32, },
+ { 1, 1, 0, 1, 64, 32, },
+ { 0, 1, 0, 1, 100, 30, },
+ { 2, 1, 0, 1, 100, 32, },
+ { 1, 1, 0, 1, 100, 32, },
+ { 0, 1, 0, 1, 104, 30, },
+ { 2, 1, 0, 1, 104, 32, },
+ { 1, 1, 0, 1, 104, 32, },
+ { 0, 1, 0, 1, 108, 32, },
+ { 2, 1, 0, 1, 108, 32, },
+ { 1, 1, 0, 1, 108, 32, },
+ { 0, 1, 0, 1, 112, 34, },
+ { 2, 1, 0, 1, 112, 32, },
+ { 1, 1, 0, 1, 112, 32, },
+ { 0, 1, 0, 1, 116, 34, },
+ { 2, 1, 0, 1, 116, 32, },
+ { 1, 1, 0, 1, 116, 32, },
+ { 0, 1, 0, 1, 120, 36, },
+ { 2, 1, 0, 1, 120, 32, },
+ { 1, 1, 0, 1, 120, 32, },
+ { 0, 1, 0, 1, 124, 34, },
+ { 2, 1, 0, 1, 124, 32, },
+ { 1, 1, 0, 1, 124, 32, },
+ { 0, 1, 0, 1, 128, 32, },
+ { 2, 1, 0, 1, 128, 32, },
+ { 1, 1, 0, 1, 128, 32, },
+ { 0, 1, 0, 1, 132, 30, },
+ { 2, 1, 0, 1, 132, 32, },
+ { 1, 1, 0, 1, 132, 32, },
+ { 0, 1, 0, 1, 136, 30, },
+ { 2, 1, 0, 1, 136, 32, },
+ { 1, 1, 0, 1, 136, 32, },
+ { 0, 1, 0, 1, 140, 28, },
+ { 2, 1, 0, 1, 140, 32, },
+ { 1, 1, 0, 1, 140, 32, },
+ { 0, 1, 0, 1, 149, 36, },
+ { 2, 1, 0, 1, 149, 32, },
+ { 1, 1, 0, 1, 149, 63, },
+ { 0, 1, 0, 1, 153, 36, },
+ { 2, 1, 0, 1, 153, 32, },
+ { 1, 1, 0, 1, 153, 63, },
+ { 0, 1, 0, 1, 157, 36, },
+ { 2, 1, 0, 1, 157, 32, },
+ { 1, 1, 0, 1, 157, 63, },
+ { 0, 1, 0, 1, 161, 36, },
+ { 2, 1, 0, 1, 161, 32, },
+ { 1, 1, 0, 1, 161, 63, },
+ { 0, 1, 0, 1, 165, 36, },
+ { 2, 1, 0, 1, 165, 32, },
+ { 1, 1, 0, 1, 165, 63, },
+ { 0, 1, 0, 2, 36, 30, },
+ { 2, 1, 0, 2, 36, 32, },
+ { 1, 1, 0, 2, 36, 32, },
+ { 0, 1, 0, 2, 40, 30, },
+ { 2, 1, 0, 2, 40, 32, },
+ { 1, 1, 0, 2, 40, 32, },
+ { 0, 1, 0, 2, 44, 30, },
+ { 2, 1, 0, 2, 44, 32, },
+ { 1, 1, 0, 2, 44, 32, },
+ { 0, 1, 0, 2, 48, 30, },
+ { 2, 1, 0, 2, 48, 32, },
+ { 1, 1, 0, 2, 48, 32, },
+ { 0, 1, 0, 2, 52, 36, },
+ { 2, 1, 0, 2, 52, 32, },
+ { 1, 1, 0, 2, 52, 32, },
+ { 0, 1, 0, 2, 56, 34, },
+ { 2, 1, 0, 2, 56, 32, },
+ { 1, 1, 0, 2, 56, 32, },
+ { 0, 1, 0, 2, 60, 32, },
+ { 2, 1, 0, 2, 60, 32, },
+ { 1, 1, 0, 2, 60, 32, },
+ { 0, 1, 0, 2, 64, 28, },
+ { 2, 1, 0, 2, 64, 32, },
+ { 1, 1, 0, 2, 64, 32, },
+ { 0, 1, 0, 2, 100, 30, },
+ { 2, 1, 0, 2, 100, 32, },
+ { 1, 1, 0, 2, 100, 32, },
+ { 0, 1, 0, 2, 104, 30, },
+ { 2, 1, 0, 2, 104, 32, },
+ { 1, 1, 0, 2, 104, 32, },
+ { 0, 1, 0, 2, 108, 32, },
+ { 2, 1, 0, 2, 108, 32, },
+ { 1, 1, 0, 2, 108, 32, },
+ { 0, 1, 0, 2, 112, 34, },
+ { 2, 1, 0, 2, 112, 32, },
+ { 1, 1, 0, 2, 112, 32, },
+ { 0, 1, 0, 2, 116, 34, },
+ { 2, 1, 0, 2, 116, 32, },
+ { 1, 1, 0, 2, 116, 32, },
+ { 0, 1, 0, 2, 120, 36, },
+ { 2, 1, 0, 2, 120, 32, },
+ { 1, 1, 0, 2, 120, 32, },
+ { 0, 1, 0, 2, 124, 34, },
+ { 2, 1, 0, 2, 124, 32, },
+ { 1, 1, 0, 2, 124, 32, },
+ { 0, 1, 0, 2, 128, 32, },
+ { 2, 1, 0, 2, 128, 32, },
+ { 1, 1, 0, 2, 128, 32, },
+ { 0, 1, 0, 2, 132, 30, },
+ { 2, 1, 0, 2, 132, 32, },
+ { 1, 1, 0, 2, 132, 32, },
+ { 0, 1, 0, 2, 136, 30, },
+ { 2, 1, 0, 2, 136, 32, },
+ { 1, 1, 0, 2, 136, 32, },
+ { 0, 1, 0, 2, 140, 28, },
+ { 2, 1, 0, 2, 140, 32, },
+ { 1, 1, 0, 2, 140, 32, },
+ { 0, 1, 0, 2, 149, 36, },
+ { 2, 1, 0, 2, 149, 32, },
+ { 1, 1, 0, 2, 149, 63, },
+ { 0, 1, 0, 2, 153, 36, },
+ { 2, 1, 0, 2, 153, 32, },
+ { 1, 1, 0, 2, 153, 63, },
+ { 0, 1, 0, 2, 157, 36, },
+ { 2, 1, 0, 2, 157, 32, },
+ { 1, 1, 0, 2, 157, 63, },
+ { 0, 1, 0, 2, 161, 36, },
+ { 2, 1, 0, 2, 161, 32, },
+ { 1, 1, 0, 2, 161, 63, },
+ { 0, 1, 0, 2, 165, 36, },
+ { 2, 1, 0, 2, 165, 32, },
+ { 1, 1, 0, 2, 165, 63, },
+ { 0, 1, 0, 3, 36, 28, },
+ { 2, 1, 0, 3, 36, 30, },
+ { 1, 1, 0, 3, 36, 30, },
+ { 0, 1, 0, 3, 40, 28, },
+ { 2, 1, 0, 3, 40, 30, },
+ { 1, 1, 0, 3, 40, 30, },
+ { 0, 1, 0, 3, 44, 28, },
+ { 2, 1, 0, 3, 44, 30, },
+ { 1, 1, 0, 3, 44, 30, },
+ { 0, 1, 0, 3, 48, 28, },
+ { 2, 1, 0, 3, 48, 30, },
+ { 1, 1, 0, 3, 48, 30, },
+ { 0, 1, 0, 3, 52, 34, },
+ { 2, 1, 0, 3, 52, 30, },
+ { 1, 1, 0, 3, 52, 30, },
+ { 0, 1, 0, 3, 56, 32, },
+ { 2, 1, 0, 3, 56, 30, },
+ { 1, 1, 0, 3, 56, 30, },
+ { 0, 1, 0, 3, 60, 30, },
+ { 2, 1, 0, 3, 60, 30, },
+ { 1, 1, 0, 3, 60, 30, },
+ { 0, 1, 0, 3, 64, 26, },
+ { 2, 1, 0, 3, 64, 30, },
+ { 1, 1, 0, 3, 64, 30, },
+ { 0, 1, 0, 3, 100, 28, },
+ { 2, 1, 0, 3, 100, 30, },
+ { 1, 1, 0, 3, 100, 30, },
+ { 0, 1, 0, 3, 104, 28, },
+ { 2, 1, 0, 3, 104, 30, },
+ { 1, 1, 0, 3, 104, 30, },
+ { 0, 1, 0, 3, 108, 30, },
+ { 2, 1, 0, 3, 108, 30, },
+ { 1, 1, 0, 3, 108, 30, },
+ { 0, 1, 0, 3, 112, 32, },
+ { 2, 1, 0, 3, 112, 30, },
+ { 1, 1, 0, 3, 112, 30, },
+ { 0, 1, 0, 3, 116, 32, },
+ { 2, 1, 0, 3, 116, 30, },
+ { 1, 1, 0, 3, 116, 30, },
+ { 0, 1, 0, 3, 120, 34, },
+ { 2, 1, 0, 3, 120, 30, },
+ { 1, 1, 0, 3, 120, 30, },
+ { 0, 1, 0, 3, 124, 32, },
+ { 2, 1, 0, 3, 124, 30, },
+ { 1, 1, 0, 3, 124, 30, },
+ { 0, 1, 0, 3, 128, 30, },
+ { 2, 1, 0, 3, 128, 30, },
+ { 1, 1, 0, 3, 128, 30, },
+ { 0, 1, 0, 3, 132, 28, },
+ { 2, 1, 0, 3, 132, 30, },
+ { 1, 1, 0, 3, 132, 30, },
+ { 0, 1, 0, 3, 136, 28, },
+ { 2, 1, 0, 3, 136, 30, },
+ { 1, 1, 0, 3, 136, 30, },
+ { 0, 1, 0, 3, 140, 26, },
+ { 2, 1, 0, 3, 140, 30, },
+ { 1, 1, 0, 3, 140, 30, },
+ { 0, 1, 0, 3, 149, 34, },
+ { 2, 1, 0, 3, 149, 30, },
+ { 1, 1, 0, 3, 149, 63, },
+ { 0, 1, 0, 3, 153, 34, },
+ { 2, 1, 0, 3, 153, 30, },
+ { 1, 1, 0, 3, 153, 63, },
+ { 0, 1, 0, 3, 157, 34, },
+ { 2, 1, 0, 3, 157, 30, },
+ { 1, 1, 0, 3, 157, 63, },
+ { 0, 1, 0, 3, 161, 34, },
+ { 2, 1, 0, 3, 161, 30, },
+ { 1, 1, 0, 3, 161, 63, },
+ { 0, 1, 0, 3, 165, 34, },
+ { 2, 1, 0, 3, 165, 30, },
+ { 1, 1, 0, 3, 165, 63, },
+ { 0, 1, 1, 2, 38, 30, },
+ { 2, 1, 1, 2, 38, 32, },
+ { 1, 1, 1, 2, 38, 32, },
+ { 0, 1, 1, 2, 46, 30, },
+ { 2, 1, 1, 2, 46, 32, },
+ { 1, 1, 1, 2, 46, 32, },
+ { 0, 1, 1, 2, 54, 32, },
+ { 2, 1, 1, 2, 54, 32, },
+ { 1, 1, 1, 2, 54, 32, },
+ { 0, 1, 1, 2, 62, 32, },
+ { 2, 1, 1, 2, 62, 32, },
+ { 1, 1, 1, 2, 62, 32, },
+ { 0, 1, 1, 2, 102, 28, },
+ { 2, 1, 1, 2, 102, 32, },
+ { 1, 1, 1, 2, 102, 32, },
+ { 0, 1, 1, 2, 110, 32, },
+ { 2, 1, 1, 2, 110, 32, },
+ { 1, 1, 1, 2, 110, 32, },
+ { 0, 1, 1, 2, 118, 36, },
+ { 2, 1, 1, 2, 118, 32, },
+ { 1, 1, 1, 2, 118, 32, },
+ { 0, 1, 1, 2, 126, 34, },
+ { 2, 1, 1, 2, 126, 32, },
+ { 1, 1, 1, 2, 126, 32, },
+ { 0, 1, 1, 2, 134, 32, },
+ { 2, 1, 1, 2, 134, 32, },
+ { 1, 1, 1, 2, 134, 32, },
+ { 0, 1, 1, 2, 151, 36, },
+ { 2, 1, 1, 2, 151, 32, },
+ { 1, 1, 1, 2, 151, 63, },
+ { 0, 1, 1, 2, 159, 36, },
+ { 2, 1, 1, 2, 159, 32, },
+ { 1, 1, 1, 2, 159, 63, },
+ { 0, 1, 1, 3, 38, 28, },
+ { 2, 1, 1, 3, 38, 30, },
+ { 1, 1, 1, 3, 38, 30, },
+ { 0, 1, 1, 3, 46, 28, },
+ { 2, 1, 1, 3, 46, 30, },
+ { 1, 1, 1, 3, 46, 30, },
+ { 0, 1, 1, 3, 54, 30, },
+ { 2, 1, 1, 3, 54, 30, },
+ { 1, 1, 1, 3, 54, 30, },
+ { 0, 1, 1, 3, 62, 30, },
+ { 2, 1, 1, 3, 62, 30, },
+ { 1, 1, 1, 3, 62, 30, },
+ { 0, 1, 1, 3, 102, 26, },
+ { 2, 1, 1, 3, 102, 30, },
+ { 1, 1, 1, 3, 102, 30, },
+ { 0, 1, 1, 3, 110, 30, },
+ { 2, 1, 1, 3, 110, 30, },
+ { 1, 1, 1, 3, 110, 30, },
+ { 0, 1, 1, 3, 118, 34, },
+ { 2, 1, 1, 3, 118, 30, },
+ { 1, 1, 1, 3, 118, 30, },
+ { 0, 1, 1, 3, 126, 32, },
+ { 2, 1, 1, 3, 126, 30, },
+ { 1, 1, 1, 3, 126, 30, },
+ { 0, 1, 1, 3, 134, 30, },
+ { 2, 1, 1, 3, 134, 30, },
+ { 1, 1, 1, 3, 134, 30, },
+ { 0, 1, 1, 3, 151, 34, },
+ { 2, 1, 1, 3, 151, 30, },
+ { 1, 1, 1, 3, 151, 63, },
+ { 0, 1, 1, 3, 159, 34, },
+ { 2, 1, 1, 3, 159, 30, },
+ { 1, 1, 1, 3, 159, 63, },
+ { 0, 1, 2, 4, 42, 30, },
+ { 2, 1, 2, 4, 42, 32, },
+ { 1, 1, 2, 4, 42, 32, },
+ { 0, 1, 2, 4, 58, 28, },
+ { 2, 1, 2, 4, 58, 32, },
+ { 1, 1, 2, 4, 58, 32, },
+ { 0, 1, 2, 4, 106, 30, },
+ { 2, 1, 2, 4, 106, 32, },
+ { 1, 1, 2, 4, 106, 32, },
+ { 0, 1, 2, 4, 122, 34, },
+ { 2, 1, 2, 4, 122, 32, },
+ { 1, 1, 2, 4, 122, 32, },
+ { 0, 1, 2, 4, 155, 36, },
+ { 2, 1, 2, 4, 155, 32, },
+ { 1, 1, 2, 4, 155, 63, },
+ { 0, 1, 2, 5, 42, 28, },
+ { 2, 1, 2, 5, 42, 30, },
+ { 1, 1, 2, 5, 42, 30, },
+ { 0, 1, 2, 5, 58, 26, },
+ { 2, 1, 2, 5, 58, 30, },
+ { 1, 1, 2, 5, 58, 30, },
+ { 0, 1, 2, 5, 106, 28, },
+ { 2, 1, 2, 5, 106, 30, },
+ { 1, 1, 2, 5, 106, 30, },
+ { 0, 1, 2, 5, 122, 32, },
+ { 2, 1, 2, 5, 122, 30, },
+ { 1, 1, 2, 5, 122, 30, },
+ { 0, 1, 2, 5, 155, 34, },
+ { 2, 1, 2, 5, 155, 30, },
+ { 1, 1, 2, 5, 155, 63, },
+};
+
+RTW_DECL_TABLE_TXPWR_LMT(rtw8812a_txpwr_lmt);
+
+static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8812a[] = {
+ {0x0012,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0014,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x80, 0},
+ {0x0015,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x01, 0},
+ {0x0023,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x10, 0},
+ {0x0046,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x00},
+ {0x0043,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x00},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(2), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3), 0},
+ {0x0003,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(2), BIT(2)},
+ {0x0301,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0},
+ {0x0024,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x0028,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3), BIT(3)},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8812a[] = {
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(2), 0},
+ {0x0006,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(1), BIT(1)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(7), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(0), 0},
+ {0x0024,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0028,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3), 0},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_act_to_lps_8812a[] = {
+ {0x0301,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0xFF},
+ {0x0522,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x7F},
+ {0x05F8,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05F9,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05FA,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05FB,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x0c00,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x04},
+ {0x0e00,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x04},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0100,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x03},
+ {0x0101,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0553,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(5), BIT(5)},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8812a[] = {
+ {0x0c00,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x04},
+ {0x0e00,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x04},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0007,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x2A},
+ {0x0008,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x02, 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(1), 0},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8812a[] = {
+ {0x0003,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(2), 0},
+ {0x0080,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x05},
+ {0x0042,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xF0, 0xcc},
+ {0x0042,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xF0, 0xEC},
+ {0x0043,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x07},
+ {0x0045,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x00},
+ {0x0046,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0xff},
+ {0x0047,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0},
+ {0x0014,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x80, BIT(7)},
+ {0x0015,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x01, BIT(0)},
+ {0x0012,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x01, 0},
+ {0x0023,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x10, BIT(4)},
+ {0x0008,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0x02, 0},
+ {0x0007,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x20},
+ {0x001f,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0076,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3), BIT(3)},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[] = {
+ trans_carddis_to_cardemu_8812a,
+ trans_cardemu_to_act_8812a,
+ NULL
+};
+
+const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[] = {
+ trans_act_to_lps_8812a,
+ NULL
+};
+
+const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[] = {
+ trans_act_to_cardemu_8812a,
+ trans_cardemu_to_carddis_8812a,
+ NULL
+};
+
+static const u8 rtw8812a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 14, 14, 14, 14, 14},
+ {0, 1, 1, 2, 2, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 14, 14, 14, 14, 14},
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 11, 12, 12, 13,
+ 13, 14, 14, 15, 16, 16, 16, 16, 16},
+};
+
+static const u8 rtw8812a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static const u8 rtw8812a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 15, 15, 15, 15, 15},
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 15, 15, 15, 15, 15},
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 15, 15, 15, 15, 15},
+};
+
+static const u8 rtw8812a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static const u8 rtw8812a_pwrtrk_2gb_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11
+};
+
+static const u8 rtw8812a_pwrtrk_2gb_p[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+static const u8 rtw8812a_pwrtrk_2ga_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10
+};
+
+static const u8 rtw8812a_pwrtrk_2ga_p[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+static const u8 rtw8812a_pwrtrk_2g_cck_b_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11
+};
+
+static const u8 rtw8812a_pwrtrk_2g_cck_b_p[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+static const u8 rtw8812a_pwrtrk_2g_cck_a_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10
+};
+
+static const u8 rtw8812a_pwrtrk_2g_cck_a_p[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+};
+
+const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl = {
+ .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_5gb_n[0],
+ .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_5gb_n[1],
+ .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_5gb_n[2],
+ .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_5gb_p[0],
+ .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_5gb_p[1],
+ .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_5gb_p[2],
+ .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_5ga_n[0],
+ .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_5ga_n[1],
+ .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_5ga_n[2],
+ .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_5ga_p[0],
+ .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_5ga_p[1],
+ .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_5ga_p[2],
+ .pwrtrk_2gb_n = rtw8812a_pwrtrk_2gb_n,
+ .pwrtrk_2gb_p = rtw8812a_pwrtrk_2gb_p,
+ .pwrtrk_2ga_n = rtw8812a_pwrtrk_2ga_n,
+ .pwrtrk_2ga_p = rtw8812a_pwrtrk_2ga_p,
+ .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_2g_cck_b_n,
+ .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_2g_cck_b_p,
+ .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_2g_cck_a_n,
+ .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_2g_cck_a_p,
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_5gb_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13,
+ 13, 14, 15, 16, 16, 17, 17, 18, 18},
+ {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11,
+ 12, 14, 13, 13, 14, 14, 14, 15, 15},
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 14, 15, 15, 16, 16},
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_5gb_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_5ga_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
+ 13, 14, 15, 16, 16, 17, 17, 18, 18},
+ {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12,
+ 12, 13, 13, 14, 15, 16, 16, 17, 17},
+ {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13,
+ 13, 14, 14, 15, 15, 16, 17, 18, 18},
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_5ga_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+ {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2gb_n[] = {
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7,
+ 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2gb_p[] = {
+ 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2ga_n[] = {
+ 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9,
+ 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2ga_p[] = {
+ 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_n[] = {
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7,
+ 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_p[] = {
+ 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_n[] = {
+ 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9,
+ 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15
+};
+
+static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_p[] = {
+ 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11
+};
+
+const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl = {
+ .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_rfe3_5gb_n[0],
+ .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_rfe3_5gb_n[1],
+ .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_rfe3_5gb_n[2],
+ .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_rfe3_5gb_p[0],
+ .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_rfe3_5gb_p[1],
+ .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_rfe3_5gb_p[2],
+ .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_rfe3_5ga_n[0],
+ .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_rfe3_5ga_n[1],
+ .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_rfe3_5ga_n[2],
+ .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_rfe3_5ga_p[0],
+ .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_rfe3_5ga_p[1],
+ .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_rfe3_5ga_p[2],
+ .pwrtrk_2gb_n = rtw8812a_pwrtrk_rfe3_2gb_n,
+ .pwrtrk_2gb_p = rtw8812a_pwrtrk_rfe3_2gb_p,
+ .pwrtrk_2ga_n = rtw8812a_pwrtrk_rfe3_2ga_n,
+ .pwrtrk_2ga_p = rtw8812a_pwrtrk_rfe3_2ga_p,
+ .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_rfe3_2g_cck_b_n,
+ .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_rfe3_2g_cck_b_p,
+ .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_rfe3_2g_cck_a_n,
+ .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_rfe3_2g_cck_a_p,
+};
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h
new file mode 100644
index 000000000000..f7ab5e4cf059
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#ifndef __RTW8812A_TABLE_H__
+#define __RTW8812A_TABLE_H__
+
+extern const struct rtw_table rtw8812a_mac_tbl;
+extern const struct rtw_table rtw8812a_agc_tbl;
+extern const struct rtw_table rtw8812a_agc_diff_lb_tbl;
+extern const struct rtw_table rtw8812a_agc_diff_hb_tbl;
+extern const struct rtw_table rtw8812a_bb_tbl;
+extern const struct rtw_table rtw8812a_bb_pg_tbl;
+extern const struct rtw_table rtw8812a_bb_pg_rfe3_tbl;
+extern const struct rtw_table rtw8812a_rf_a_tbl;
+extern const struct rtw_table rtw8812a_rf_b_tbl;
+extern const struct rtw_table rtw8812a_txpwr_lmt_tbl;
+
+extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[];
+extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[];
+extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[];
+
+extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl;
+extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812au.c b/drivers/net/wireless/realtek/rtw88/rtw8812au.c
new file mode 100644
index 000000000000..4da69590a423
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8812au.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "main.h"
+#include "rtw8812a.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8812au_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2604, 0x0012, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, rtw_8812au_id_table);
+
+static struct usb_driver rtw_8812au_driver = {
+ .name = "rtw_8812au",
+ .id_table = rtw_8812au_id_table,
+ .probe = rtw_usb_probe,
+ .disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8812au_driver);
+
+MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812au driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
new file mode 100644
index 000000000000..db242c9ad68f
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -0,0 +1,1197 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include "main.h"
+#include "coex.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw88xxa.h"
+#include "rtw8821a.h"
+#include "rtw8821a_table.h"
+#include "tx.h"
+
+static void rtw8821a_power_off(struct rtw_dev *rtwdev)
+{
+ rtw88xxa_power_off(rtwdev, enter_lps_flow_8821a);
+}
+
+static s8 rtw8821a_cck_rx_pwr(u8 lna_idx, u8 vga_idx)
+{
+ static const s8 lna_gain_table[] = {15, -1, -17, 0, -30, -38};
+ s8 rx_pwr_all = 0;
+ s8 lna_gain;
+
+ switch (lna_idx) {
+ case 5:
+ case 4:
+ case 2:
+ case 1:
+ case 0:
+ lna_gain = lna_gain_table[lna_idx];
+ rx_pwr_all = lna_gain - 2 * vga_idx;
+ break;
+ default:
+ break;
+ }
+
+ return rx_pwr_all;
+}
+
+static void rtw8821a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+ struct rtw_rx_pkt_stat *pkt_stat)
+{
+ rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat,
+ rtw8821a_cck_rx_pwr);
+}
+
+static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
+{
+}
+
+#define CAL_NUM_8821A 3
+#define MACBB_REG_NUM_8821A 8
+#define AFE_REG_NUM_8821A 4
+#define RF_REG_NUM_8821A 3
+
+static void rtw8821a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup,
+ const u32 *backup_rf_reg, u32 rf_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Save RF Parameters */
+ for (i = 0; i < rf_num; i++)
+ rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A,
+ backup_rf_reg[i], MASKDWORD);
+}
+
+static void rtw8821a_iqk_restore_rf(struct rtw_dev *rtwdev,
+ const u32 *backup_rf_reg,
+ u32 *RF_backup, u32 rf_reg_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ for (i = 0; i < rf_reg_num; i++)
+ rtw_write_rf(rtwdev, RF_PATH_A, backup_rf_reg[i],
+ RFREG_MASK, RF_backup[i]);
+}
+
+static void rtw8821a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
+ const u32 *backup_afe_reg, u32 afe_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Reload AFE Parameters */
+ for (i = 0; i < afe_num; i++)
+ rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0);
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0);
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0);
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000);
+ rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080);
+ rtw_write32(rtwdev, REG_TXAGCIDX, 0x00000000);
+ rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000);
+ rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x0);
+}
+
+static void rtw8821a_iqk_rx_fill(struct rtw_dev *rtwdev,
+ unsigned int rx_x, unsigned int rx_y)
+{
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x000003ff, rx_x >> 1);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x03ff0000, (rx_y >> 1) & 0x3ff);
+}
+
+static void rtw8821a_iqk_tx_fill(struct rtw_dev *rtwdev,
+ unsigned int tx_x, unsigned int tx_y)
+{
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080);
+ rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000);
+ rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000);
+ rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y);
+ rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x);
+}
+
+static void rtw8821a_iqk_tx_vdf_true(struct rtw_dev *rtwdev, u32 cal,
+ bool *tx0iqkok,
+ int tx_x0[CAL_NUM_8821A],
+ int tx_y0[CAL_NUM_8821A])
+{
+ u32 cal_retry, delay_count, iqk_ready, tx_fail;
+ int tx_dt[3], vdf_y[3], vdf_x[3];
+ int k;
+
+ for (k = 0; k < 3; k++) {
+ switch (k) {
+ case 0:
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
+ 0x18008c38);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c38);
+ rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0);
+ break;
+ case 1:
+ rtw_write32_mask(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
+ BIT(28), 0x0);
+ rtw_write32_mask(rtwdev, REG_OFDM0_A_TX_AFE,
+ BIT(28), 0x0);
+ rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0);
+ break;
+ case 2:
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "vdf_y[1] = %x vdf_y[0] = %x\n",
+ vdf_y[1] >> 21 & 0x00007ff,
+ vdf_y[0] >> 21 & 0x00007ff);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "vdf_x[1] = %x vdf_x[0] = %x\n",
+ vdf_x[1] >> 21 & 0x00007ff,
+ vdf_x[0] >> 21 & 0x00007ff);
+
+ tx_dt[cal] = (vdf_y[1] >> 20) - (vdf_y[0] >> 20);
+ tx_dt[cal] = (16 * tx_dt[cal]) * 10000 / 15708;
+ tx_dt[cal] = (tx_dt[cal] >> 1) + (tx_dt[cal] & BIT(0));
+
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE,
+ 0x18008c20);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c20);
+ rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x1);
+ rtw_write32_mask(rtwdev, REG_INTPO_SETA, 0x3fff0000,
+ tx_dt[cal] & 0x00003fff);
+ break;
+ }
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+
+ for (cal_retry = 0; cal_retry < 10; cal_retry++) {
+ /* one shot */
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+ mdelay(10);
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+
+ for (delay_count = 0; delay_count < 20; delay_count++) {
+ iqk_ready = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ BIT(10));
+
+ /* Originally: if (~iqk_ready || delay_count > 20)
+ * that looks like a typo so make it more explicit
+ */
+ iqk_ready = true;
+
+ if (iqk_ready)
+ break;
+
+ mdelay(1);
+ }
+
+ if (delay_count < 20) {
+ /* ============TXIQK Check============== */
+ tx_fail = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ BIT(12));
+
+ /* Originally: if (~tx_fail) {
+ * It looks like a typo, so make it more explicit.
+ */
+ tx_fail = false;
+
+ if (!tx_fail) {
+ rtw_write32(rtwdev, REG_RFECTL_A,
+ 0x02000000);
+ vdf_x[k] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+ vdf_x[k] <<= 21;
+
+ rtw_write32(rtwdev, REG_RFECTL_A,
+ 0x04000000);
+ vdf_y[k] = rtw_read32_mask(rtwdev,
+ REG_IQKA_END,
+ 0x07ff0000);
+ vdf_y[k] <<= 21;
+
+ *tx0iqkok = true;
+ break;
+ }
+
+ rtw_write32_mask(rtwdev, REG_IQC_Y,
+ 0x000007ff, 0x0);
+ rtw_write32_mask(rtwdev, REG_IQC_X,
+ 0x000007ff, 0x200);
+ }
+
+ *tx0iqkok = false;
+ }
+ }
+
+ if (k == 3) {
+ tx_x0[cal] = vdf_x[k - 1];
+ tx_y0[cal] = vdf_y[k - 1];
+ }
+}
+
+static void rtw8821a_iqk_tx_vdf_false(struct rtw_dev *rtwdev, u32 cal,
+ bool *tx0iqkok,
+ int tx_x0[CAL_NUM_8821A],
+ int tx_y0[CAL_NUM_8821A])
+{
+ u32 cal_retry, delay_count, iqk_ready, tx_fail;
+
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+
+ for (cal_retry = 0; cal_retry < 10; cal_retry++) {
+ /* one shot */
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+ mdelay(10);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+
+ for (delay_count = 0; delay_count < 20; delay_count++) {
+ iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10));
+
+ /* Originally: if (~iqk_ready || delay_count > 20)
+ * that looks like a typo so make it more explicit
+ */
+ iqk_ready = true;
+
+ if (iqk_ready)
+ break;
+
+ mdelay(1);
+ }
+
+ if (delay_count < 20) {
+ /* ============TXIQK Check============== */
+ tx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12));
+
+ /* Originally: if (~tx_fail) {
+ * It looks like a typo, so make it more explicit.
+ */
+ tx_fail = false;
+
+ if (!tx_fail) {
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000);
+ tx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
+ 0x07ff0000);
+ tx_x0[cal] <<= 21;
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000);
+ tx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
+ 0x07ff0000);
+ tx_y0[cal] <<= 21;
+
+ *tx0iqkok = true;
+ break;
+ }
+
+ rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, 0x0);
+ rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, 0x200);
+ }
+
+ *tx0iqkok = false;
+ }
+}
+
+static void rtw8821a_iqk_rx(struct rtw_dev *rtwdev, u32 cal, bool *rx0iqkok,
+ int rx_x0[CAL_NUM_8821A],
+ int rx_y0[CAL_NUM_8821A])
+{
+ u32 cal_retry, delay_count, iqk_ready, rx_fail;
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+
+ for (cal_retry = 0; cal_retry < 10; cal_retry++) {
+ /* one shot */
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+ mdelay(10);
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+
+ for (delay_count = 0; delay_count < 20; delay_count++) {
+ iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10));
+
+ /* Originally: if (~iqk_ready || delay_count > 20)
+ * that looks like a typo so make it more explicit
+ */
+ iqk_ready = true;
+
+ if (iqk_ready)
+ break;
+
+ mdelay(1);
+ }
+
+ if (delay_count < 20) {
+ /* ============RXIQK Check============== */
+ rx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11));
+ if (!rx_fail) {
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000);
+ rx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
+ 0x07ff0000);
+ rx_x0[cal] <<= 21;
+
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000);
+ rx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END,
+ 0x07ff0000);
+ rx_y0[cal] <<= 21;
+
+ *rx0iqkok = true;
+ break;
+ }
+
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x000003ff, 0x200 >> 1);
+ rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A,
+ 0x03ff0000, 0x0 >> 1);
+ }
+
+ *rx0iqkok = false;
+ }
+}
+
+static void rtw8821a_iqk(struct rtw_dev *rtwdev)
+{
+ int tx_average = 0, rx_average = 0, rx_iqk_loop = 0;
+ const struct rtw_efuse *efuse = &rtwdev->efuse;
+ int tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0;
+ const struct rtw_hal *hal = &rtwdev->hal;
+ bool tx0iqkok = false, rx0iqkok = false;
+ int rx_x_temp = 0, rx_y_temp = 0;
+ int rx_x0[2][CAL_NUM_8821A];
+ int rx_y0[2][CAL_NUM_8821A];
+ int tx_x0[CAL_NUM_8821A];
+ int tx_y0[CAL_NUM_8821A];
+ bool rx_finish1 = false;
+ bool rx_finish2 = false;
+ bool vdf_enable;
+ u32 cal;
+ int i;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "band_width = %d, ext_pa = %d, ext_pa_5g = %d\n",
+ hal->current_band_width, efuse->ext_pa_2g, efuse->ext_pa_5g);
+
+ vdf_enable = hal->current_band_width == RTW_CHANNEL_WIDTH_80;
+
+ for (cal = 0; cal < CAL_NUM_8821A; cal++) {
+ /* path-A LOK */
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* ========path-A AFE all on======== */
+ /* Port 0 DAC/ADC on */
+ rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777);
+ rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777);
+
+ rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979);
+
+ /* hardware 3-wire off */
+ rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4);
+
+ /* LOK setting */
+
+ /* 1. DAC/ADC sampling rate (160 MHz) */
+ rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7);
+
+ /* 2. LoK RF setting (at BW = 20M) */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x00c00, 0x3);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x20000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ 0x0003f);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ 0xf3fc3);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK,
+ 0x931d5);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001);
+ rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+ rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1);
+ /* TX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000);
+ /* RX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000);
+ /* [0]:AGC_en, [15]:idac_K_Mask */
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ if (efuse->ext_pa_5g)
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403f7);
+ else
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403f4);
+
+ if (hal->current_band_type == RTW_BAND_5G)
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96);
+ else
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96);
+
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000);
+ rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000);
+
+ mdelay(10);
+ rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000);
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00,
+ rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00));
+
+ if (hal->current_band_width == RTW_CHANNEL_WIDTH_40)
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH,
+ RF18_BW_MASK, 0x1);
+ else if (hal->current_band_width == RTW_CHANNEL_WIDTH_80)
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH,
+ RF18_BW_MASK, 0x0);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ /* 3. TX RF setting */
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x20000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ 0x0003f);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ 0xf3fc3);
+
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000);
+ rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+ rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1);
+ /* TX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000);
+ /* RX (X,Y) */
+ rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000);
+ /* [0]:AGC_en, [15]:idac_K_Mask */
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a910);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ if (efuse->ext_pa_5g)
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403f7);
+ else
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE,
+ 0x821403e3);
+
+ if (hal->current_band_type == RTW_BAND_5G)
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x40163e96);
+ else
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x00163e96);
+
+ if (vdf_enable)
+ rtw8821a_iqk_tx_vdf_true(rtwdev, cal, &tx0iqkok,
+ tx_x0, tx_y0);
+ else
+ rtw8821a_iqk_tx_vdf_false(rtwdev, cal, &tx0iqkok,
+ tx_x0, tx_y0);
+
+ if (!tx0iqkok)
+ break; /* TXK fail, Don't do RXK */
+
+ /* ====== RX IQK ====== */
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+ /* 1. RX RF setting */
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK,
+ 0x30000);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK,
+ 0x0002f);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK,
+ 0xfffbb);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d8);
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000);
+
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000,
+ (tx_x0[cal] >> 21) & 0x000007ff);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF,
+ (tx_y0[cal] >> 21) & 0x000007ff);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1);
+ rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0);
+ rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000);
+ rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911);
+
+ /* [31] = 1 --> Page C1 */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1);
+
+ /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+ rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10);
+ /* RX_Tone_idx[9:0], RxK_Mask[29] */
+ rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10);
+ rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x02140119);
+
+ if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE)
+ rx_iqk_loop = 2; /* for 2% fail; */
+ else
+ rx_iqk_loop = 1;
+
+ for (i = 0; i < rx_iqk_loop; i++) {
+ if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && i == 0)
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161100); /* Good */
+ else
+ rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160d00);
+
+ rtw8821a_iqk_rx(rtwdev, cal, &rx0iqkok,
+ rx_x0[i], rx_y0[i]);
+ }
+
+ if (tx0iqkok)
+ tx_average++;
+ if (rx0iqkok)
+ rx_average++;
+ }
+
+ /* FillIQK Result */
+
+ if (tx_average == 0)
+ return;
+
+ for (i = 0; i < tx_average; i++)
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n",
+ i, (tx_x0[i] >> 21) & 0x000007ff,
+ i, (tx_y0[i] >> 21) & 0x000007ff);
+
+ if (rtw88xxa_iqk_finish(tx_average, 3, tx_x0, tx_y0,
+ &tx_x, &tx_y, true, true))
+ rtw8821a_iqk_tx_fill(rtwdev, tx_x, tx_y);
+ else
+ rtw8821a_iqk_tx_fill(rtwdev, 0x200, 0x0);
+
+ if (rx_average == 0)
+ return;
+
+ for (i = 0; i < rx_average; i++) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x0[0][%d] = %x ;; rx_y0[0][%d] = %x\n",
+ i, (rx_x0[0][i] >> 21) & 0x000007ff,
+ i, (rx_y0[0][i] >> 21) & 0x000007ff);
+
+ if (rx_iqk_loop == 2)
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "rx_x0[1][%d] = %x ;; rx_y0[1][%d] = %x\n",
+ i, (rx_x0[1][i] >> 21) & 0x000007ff,
+ i, (rx_y0[1][i] >> 21) & 0x000007ff);
+ }
+
+ rx_finish1 = rtw88xxa_iqk_finish(rx_average, 4, rx_x0[0], rx_y0[0],
+ &rx_x_temp, &rx_y_temp, true, true);
+
+ if (rx_finish1) {
+ rx_x = rx_x_temp;
+ rx_y = rx_y_temp;
+ }
+
+ if (rx_iqk_loop == 2) {
+ rx_finish2 = rtw88xxa_iqk_finish(rx_average, 4,
+ rx_x0[1], rx_y0[1],
+ &rx_x, &rx_y, true, true);
+
+ if (rx_finish1 && rx_finish2) {
+ rx_x = (rx_x + rx_x_temp) / 2;
+ rx_y = (rx_y + rx_y_temp) / 2;
+ }
+ }
+
+ if (rx_finish1 || rx_finish2)
+ rtw8821a_iqk_rx_fill(rtwdev, rx_x, rx_y);
+ else
+ rtw8821a_iqk_rx_fill(rtwdev, 0x200, 0x0);
+}
+
+static void rtw8821a_do_iqk(struct rtw_dev *rtwdev)
+{
+ static const u32 backup_macbb_reg[MACBB_REG_NUM_8821A] = {
+ 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c
+ };
+ static const u32 backup_afe_reg[AFE_REG_NUM_8821A] = {
+ 0xc5c, 0xc60, 0xc64, 0xc68
+ };
+ static const u32 backup_rf_reg[RF_REG_NUM_8821A] = {
+ 0x65, 0x8f, 0x0
+ };
+ u32 macbb_backup[MACBB_REG_NUM_8821A];
+ u32 afe_backup[AFE_REG_NUM_8821A];
+ u32 rfa_backup[RF_REG_NUM_8821A];
+
+ rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup,
+ backup_macbb_reg, MACBB_REG_NUM_8821A);
+ rtw88xxa_iqk_backup_afe(rtwdev, afe_backup,
+ backup_afe_reg, AFE_REG_NUM_8821A);
+ rtw8821a_iqk_backup_rf(rtwdev, rfa_backup,
+ backup_rf_reg, RF_REG_NUM_8821A);
+
+ rtw88xxa_iqk_configure_mac(rtwdev);
+
+ rtw8821a_iqk(rtwdev);
+
+ rtw8821a_iqk_restore_rf(rtwdev, backup_rf_reg,
+ rfa_backup, RF_REG_NUM_8821A);
+ rtw8821a_iqk_restore_afe(rtwdev, afe_backup,
+ backup_afe_reg, AFE_REG_NUM_8821A);
+ rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup,
+ backup_macbb_reg, MACBB_REG_NUM_8821A);
+}
+
+static void rtw8821a_phy_calibration(struct rtw_dev *rtwdev)
+{
+ rtw8821a_do_iqk(rtwdev);
+}
+
+static void rtw8821a_pwr_track(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+
+ if (!dm_info->pwr_trk_triggered) {
+ rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER,
+ GENMASK(17, 16), 0x03);
+ dm_info->pwr_trk_triggered = true;
+ return;
+ }
+
+ rtw88xxa_phy_pwrtrack(rtwdev, NULL, rtw8821a_do_iqk);
+ dm_info->pwr_trk_triggered = false;
+}
+
+static void rtw8821a_fill_txdesc_checksum(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info,
+ u8 *txdesc)
+{
+ fill_txdesc_checksum_common(txdesc, 16);
+}
+
+static void rtw8821a_coex_cfg_init(struct rtw_dev *rtwdev)
+{
+ u8 val8;
+
+ /* BT report packet sample rate */
+ rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5);
+
+ val8 = BIT_STATIS_BT_EN;
+ if (rtwdev->efuse.share_ant)
+ val8 |= BIT_R_GRANTALL_WLMASK;
+ rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, val8);
+
+ /* enable BT counter statistics */
+ rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x3);
+
+ /* enable PTA */
+ rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN);
+}
+
+static void rtw8821a_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type,
+ u8 pos_type)
+{
+ bool share_ant = rtwdev->efuse.share_ant;
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ u32 phase = coex_dm->cur_ant_pos_type;
+
+ if (!rtwdev->efuse.btcoex)
+ return;
+
+ switch (phase) {
+ case COEX_SET_ANT_POWERON:
+ case COEX_SET_ANT_INIT:
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
+ rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
+ rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
+
+ rtw_write8(rtwdev, REG_RFE_CTRL8,
+ share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN);
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1);
+ break;
+ case COEX_SET_ANT_WONLY:
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
+ rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
+ rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
+
+ rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1);
+ break;
+ case COEX_SET_ANT_2G:
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
+ rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
+ rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
+
+ rtw_write8(rtwdev, REG_RFE_CTRL8,
+ share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN);
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1);
+ break;
+ case COEX_SET_ANT_5G:
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
+ rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
+ rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
+
+ rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000,
+ share_ant ? 0x2 : 0x1);
+ break;
+ case COEX_SET_ANT_WOFF:
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN);
+ rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL);
+ rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL);
+
+ rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN);
+ rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000,
+ share_ant ? 0x2 : 0x1);
+ break;
+ default:
+ rtw_warn(rtwdev, "%s: not handling phase %d\n",
+ __func__, phase);
+ break;
+ }
+}
+
+static void rtw8821a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_gnt_debug(struct rtw_dev *rtwdev)
+{
+}
+
+static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_rfe *coex_rfe = &coex->rfe;
+
+ coex_rfe->ant_switch_exist = true;
+}
+
+static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
+{
+ struct rtw_coex *coex = &rtwdev->coex;
+ struct rtw_coex_dm *coex_dm = &coex->dm;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ bool share_ant = efuse->share_ant;
+
+ if (share_ant)
+ return;
+
+ if (wl_pwr == coex_dm->cur_wl_pwr_lvl)
+ return;
+
+ coex_dm->cur_wl_pwr_lvl = wl_pwr;
+}
+
+static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
+{
+}
+
+static const struct rtw_chip_ops rtw8821a_ops = {
+ .power_on = rtw88xxa_power_on,
+ .power_off = rtw8821a_power_off,
+ .phy_set_param = NULL,
+ .read_efuse = rtw88xxa_read_efuse,
+ .query_phy_status = rtw8821a_query_phy_status,
+ .set_channel = rtw88xxa_set_channel,
+ .mac_init = NULL,
+ .read_rf = rtw88xxa_phy_read_rf,
+ .write_rf = rtw_phy_write_rf_reg_sipi,
+ .set_antenna = NULL,
+ .set_tx_power_index = rtw88xxa_set_tx_power_index,
+ .cfg_ldo25 = rtw8821a_cfg_ldo25,
+ .efuse_grant = rtw88xxa_efuse_grant,
+ .false_alarm_statistics = rtw88xxa_false_alarm_statistics,
+ .phy_calibration = rtw8821a_phy_calibration,
+ .cck_pd_set = rtw88xxa_phy_cck_pd_set,
+ .pwr_track = rtw8821a_pwr_track,
+ .config_bfee = NULL,
+ .set_gid_table = NULL,
+ .cfg_csi_rate = NULL,
+ .fill_txdesc_checksum = rtw8821a_fill_txdesc_checksum,
+ .coex_set_init = rtw8821a_coex_cfg_init,
+ .coex_set_ant_switch = rtw8821a_coex_cfg_ant_switch,
+ .coex_set_gnt_fix = rtw8821a_coex_cfg_gnt_fix,
+ .coex_set_gnt_debug = rtw8821a_coex_cfg_gnt_debug,
+ .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type,
+ .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power,
+ .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain,
+};
+
+static const struct rtw_page_table page_table_8821a[] = {
+ /* hq_num, nq_num, lq_num, exq_num, gapq_num */
+ {0, 0, 0, 0, 0}, /* SDIO */
+ {0, 0, 0, 0, 0}, /* PCI */
+ {8, 0, 0, 0, 1}, /* 2 bulk out endpoints */
+ {8, 0, 8, 0, 1}, /* 3 bulk out endpoints */
+ {8, 0, 8, 4, 1}, /* 4 bulk out endpoints */
+};
+
+static const struct rtw_rqpn rqpn_table_8821a[] = {
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH,
+ RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH},
+
+ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
+ RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
+ RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
+};
+
+static const struct rtw_prioq_addrs prioq_addrs_8821a = {
+ .prio[RTW_DMA_MAPPING_EXTRA] = {
+ .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3,
+ },
+ .prio[RTW_DMA_MAPPING_LOW] = {
+ .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1,
+ },
+ .prio[RTW_DMA_MAPPING_NORMAL] = {
+ .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1,
+ },
+ .prio[RTW_DMA_MAPPING_HIGH] = {
+ .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2,
+ },
+ .wsize = false,
+};
+
+static const struct rtw_hw_reg rtw8821a_dig[] = {
+ [0] = { .addr = REG_RXIGI_A, .mask = 0x7f },
+};
+
+static const struct rtw_rfe_def rtw8821a_rfe_defs[] = {
+ [0] = { .phy_pg_tbl = &rtw8821a_bb_pg_tbl,
+ .txpwr_lmt_tbl = &rtw8821a_txpwr_lmt_tbl,
+ .pwr_track_tbl = &rtw8821a_rtw_pwr_track_tbl, },
+};
+
+/* TODO */
+/* rssi in percentage % (dbm = % - 100) */
+static const u8 wl_rssi_step_8821a[] = {101, 45, 101, 40};
+static const u8 bt_rssi_step_8821a[] = {101, 101, 101, 101};
+
+/* table_sant_8821a, table_nsant_8821a, tdma_sant_8821a, and tdma_nsant_8821a
+ * are copied from rtw8821c.c because the 8821au driver's tables are not
+ * compatible with the coex code in rtw88.
+ *
+ * tdma case 112 (A2DP) byte 0 had to be modified from 0x61 to 0x51,
+ * otherwise the firmware gets confused after pausing the music:
+ * rtw_8821au 1-2:1.2: [BTCoex], Bt_info[1], len=7, data=[81 00 0a 01 00 00]
+ * - 81 means PAN (personal area network) when it should be 4x (A2DP)
+ * The music is not smooth with the PAN algorithm.
+ */
+
+/* Shared-Antenna Coex Table */
+static const struct coex_table_para table_sant_8821a[] = {
+ {0x55555555, 0x55555555}, /* case-0 */
+ {0x55555555, 0x55555555},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xfafafafa, 0xfafafafa}, /* case-5 */
+ {0x6a5a5555, 0xaaaaaaaa},
+ {0x6a5a56aa, 0x6a5a56aa},
+ {0x6a5a5a5a, 0x6a5a5a5a},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-10 */
+ {0x66555555, 0xaaaaaaaa},
+ {0x66555555, 0x6a5a5aaa},
+ {0x66555555, 0x6aaa6aaa},
+ {0x66555555, 0x6a5a5aaa},
+ {0x66555555, 0xaaaaaaaa}, /* case-15 */
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x6afa5afa},
+ {0xaaffffaa, 0xfafafafa},
+ {0xaa5555aa, 0x5a5a5a5a},
+ {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */
+ {0xaa5555aa, 0xaaaaaaaa},
+ {0xffffffff, 0x55555555},
+ {0xffffffff, 0x5a5a5a5a},
+ {0xffffffff, 0x5a5a5a5a},
+ {0xffffffff, 0x5a5a5aaa}, /* case-25 */
+ {0x55555555, 0x5a5a5a5a},
+ {0x55555555, 0xaaaaaaaa},
+ {0x66555555, 0x6a5a6a5a},
+ {0x66556655, 0x66556655},
+ {0x66556aaa, 0x6a5a6aaa}, /* case-30 */
+ {0xffffffff, 0x5aaa5aaa},
+ {0x56555555, 0x5a5a5aaa}
+};
+
+/* Non-Shared-Antenna Coex Table */
+static const struct coex_table_para table_nsant_8821a[] = {
+ {0xffffffff, 0xffffffff}, /* case-100 */
+ {0xffff55ff, 0xfafafafa},
+ {0x66555555, 0x66555555},
+ {0xaaaaaaaa, 0xaaaaaaaa},
+ {0x5a5a5a5a, 0x5a5a5a5a},
+ {0xffffffff, 0xffffffff}, /* case-105 */
+ {0x5afa5afa, 0x5afa5afa},
+ {0x55555555, 0xfafafafa},
+ {0x66555555, 0xfafafafa},
+ {0x66555555, 0x5a5a5a5a},
+ {0x66555555, 0x6a5a5a5a}, /* case-110 */
+ {0x66555555, 0xaaaaaaaa},
+ {0xffff55ff, 0xfafafafa},
+ {0xffff55ff, 0x5afa5afa},
+ {0xffff55ff, 0xaaaaaaaa},
+ {0xffff55ff, 0xffff55ff}, /* case-115 */
+ {0xaaffffaa, 0x5afa5afa},
+ {0xaaffffaa, 0xaaaaaaaa},
+ {0xffffffff, 0xfafafafa},
+ {0xffff55ff, 0xfafafafa},
+ {0xffffffff, 0xaaaaaaaa}, /* case-120 */
+ {0xffff55ff, 0x5afa5afa},
+ {0xffff55ff, 0x5afa5afa},
+ {0x55ff55ff, 0x55ff55ff}
+};
+
+/* Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_sant_8821a[] = {
+ { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} },
+ { {0x61, 0x35, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x3a, 0x03, 0x11, 0x11} }, /* case-5 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x35, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */
+ { {0x61, 0x08, 0x03, 0x11, 0x15} },
+ { {0x61, 0x08, 0x03, 0x10, 0x14} },
+ { {0x51, 0x08, 0x03, 0x10, 0x54} },
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */
+ { {0x51, 0x45, 0x03, 0x10, 0x50} },
+ { {0x51, 0x3a, 0x03, 0x11, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x21, 0x03, 0x10, 0x50} },
+ { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */
+ { {0x51, 0x4a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x08, 0x03, 0x30, 0x54} },
+ { {0x55, 0x08, 0x03, 0x10, 0x54} },
+ { {0x65, 0x10, 0x03, 0x11, 0x10} },
+ { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */
+ { {0x51, 0x21, 0x03, 0x10, 0x50} },
+ { {0x61, 0x08, 0x03, 0x11, 0x11} }
+};
+
+/* Non-Shared-Antenna TDMA */
+static const struct coex_tdma_para tdma_nsant_8821a[] = {
+ { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */
+ { {0x61, 0x45, 0x03, 0x11, 0x11} },
+ { {0x61, 0x25, 0x03, 0x11, 0x11} },
+ { {0x61, 0x35, 0x03, 0x11, 0x11} },
+ { {0x61, 0x20, 0x03, 0x11, 0x11} },
+ { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */
+ { {0x61, 0x45, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x30, 0x03, 0x11, 0x10} },
+ { {0x61, 0x20, 0x03, 0x11, 0x10} },
+ { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */
+ { {0x61, 0x10, 0x03, 0x11, 0x11} },
+ { {0x51, 0x08, 0x03, 0x10, 0x14} }, /* a2dp high rssi */
+ { {0x51, 0x08, 0x03, 0x10, 0x54} }, /* a2dp not high rssi */
+ { {0x51, 0x08, 0x03, 0x10, 0x55} },
+ { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */
+ { {0x51, 0x45, 0x03, 0x10, 0x50} },
+ { {0x51, 0x3a, 0x03, 0x10, 0x50} },
+ { {0x51, 0x30, 0x03, 0x10, 0x50} },
+ { {0x51, 0x21, 0x03, 0x10, 0x50} },
+ { {0x51, 0x21, 0x03, 0x10, 0x50} }, /* case-120 */
+ { {0x51, 0x10, 0x03, 0x10, 0x50} }
+};
+
+/* TODO */
+static const struct coex_rf_para rf_para_tx_8821a[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 20, false, 7}, /* for WL-CPT */
+ {8, 17, true, 4},
+ {7, 18, true, 4},
+ {6, 19, true, 4},
+ {5, 20, true, 4}
+};
+
+static const struct coex_rf_para rf_para_rx_8821a[] = {
+ {0, 0, false, 7}, /* for normal */
+ {0, 20, false, 7}, /* for WL-CPT */
+ {3, 24, true, 5},
+ {2, 26, true, 5},
+ {1, 27, true, 5},
+ {0, 28, true, 5}
+};
+
+static_assert(ARRAY_SIZE(rf_para_tx_8821a) == ARRAY_SIZE(rf_para_rx_8821a));
+
+static const struct coex_5g_afh_map afh_5g_8821a[] = { {0, 0, 0} };
+
+static const struct rtw_reg_domain coex_info_hw_regs_8821a[] = {
+ {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32},
+ {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32},
+ {0xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
+ {0, 0, RTW_REG_DOMAIN_NL},
+ {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32},
+ {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32},
+ {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16},
+ {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
+ {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8},
+ {0x454, MASKLWORD, RTW_REG_DOMAIN_MAC16},
+ {0, 0, RTW_REG_DOMAIN_NL},
+ {0x4c, BIT(24) | BIT(23), RTW_REG_DOMAIN_MAC32},
+ {0x64, BIT(0), RTW_REG_DOMAIN_MAC8},
+ {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8},
+ {0x40, BIT(5), RTW_REG_DOMAIN_MAC8},
+ {0x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A},
+ {0, 0, RTW_REG_DOMAIN_NL},
+ {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32},
+ {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
+ {0x953, BIT(1), RTW_REG_DOMAIN_MAC8},
+ {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
+ {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
+};
+
+const struct rtw_chip_info rtw8821a_hw_spec = {
+ .ops = &rtw8821a_ops,
+ .id = RTW_CHIP_TYPE_8821A,
+ .fw_name = "rtw88/rtw8821a_fw.bin",
+ .wlan_cpu = RTW_WCPU_11N,
+ .tx_pkt_desc_sz = 40,
+ .tx_buf_desc_sz = 16,
+ .rx_pkt_desc_sz = 24,
+ .rx_buf_desc_sz = 8,
+ .phy_efuse_size = 512,
+ .log_efuse_size = 512,
+ .ptct_efuse_size = 96 + 1, /* TODO or just 18? */
+ .txff_size = 65536,
+ .rxff_size = 16128,
+ .rsvd_drv_pg_num = 8,
+ .txgi_factor = 1,
+ .is_pwr_by_rate_dec = true,
+ .max_power_index = 0x3f,
+ .csi_buf_pg_num = 0,
+ .band = RTW_BAND_2G | RTW_BAND_5G,
+ .page_size = 256,
+ .dig_min = 0x20,
+ .ht_supported = true,
+ .vht_supported = true,
+ .lps_deep_mode_supported = 0,
+ .sys_func_en = 0xFD,
+ .pwr_on_seq = card_enable_flow_8821a,
+ .pwr_off_seq = card_disable_flow_8821a,
+ .page_table = page_table_8821a,
+ .rqpn_table = rqpn_table_8821a,
+ .prioq_addrs = &prioq_addrs_8821a,
+ .intf_table = NULL,
+ .dig = rtw8821a_dig,
+ .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B},
+ .ltecoex_addr = NULL,
+ .mac_tbl = &rtw8821a_mac_tbl,
+ .agc_tbl = &rtw8821a_agc_tbl,
+ .bb_tbl = &rtw8821a_bb_tbl,
+ .rf_tbl = {&rtw8821a_rf_a_tbl},
+ .rfe_defs = rtw8821a_rfe_defs,
+ .rfe_defs_size = ARRAY_SIZE(rtw8821a_rfe_defs),
+ .rx_ldpc = false,
+ .hw_feature_report = false,
+ .c2h_ra_report_size = 4,
+ .old_datarate_fb_limit = true,
+ .usb_tx_agg_desc_num = 6,
+ .iqk_threshold = 8,
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+ .max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
+
+ .coex_para_ver = 20190509, /* glcoex_ver_date_8821a_1ant */
+ .bt_desired_ver = 0x62, /* But for 2 ant it's 0x5c */
+ .scbd_support = false,
+ .new_scbd10_def = false,
+ .ble_hid_profile_support = false,
+ .wl_mimo_ps_support = false,
+ .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
+ .bt_rssi_type = COEX_BTRSSI_RATIO,
+ .ant_isolation = 10,
+ .rssi_tolerance = 2,
+ .wl_rssi_step = wl_rssi_step_8821a,
+ .bt_rssi_step = bt_rssi_step_8821a,
+ .table_sant_num = ARRAY_SIZE(table_sant_8821a),
+ .table_sant = table_sant_8821a,
+ .table_nsant_num = ARRAY_SIZE(table_nsant_8821a),
+ .table_nsant = table_nsant_8821a,
+ .tdma_sant_num = ARRAY_SIZE(tdma_sant_8821a),
+ .tdma_sant = tdma_sant_8821a,
+ .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821a),
+ .tdma_nsant = tdma_nsant_8821a,
+ .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821a),
+ .wl_rf_para_tx = rf_para_tx_8821a,
+ .wl_rf_para_rx = rf_para_rx_8821a,
+ .bt_afh_span_bw20 = 0x20,
+ .bt_afh_span_bw40 = 0x30,
+ .afh_5g_num = ARRAY_SIZE(afh_5g_8821a),
+ .afh_5g = afh_5g_8821a,
+
+ .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821a),
+ .coex_info_hw_regs = coex_info_hw_regs_8821a,
+};
+EXPORT_SYMBOL(rtw8821a_hw_spec);
+
+MODULE_FIRMWARE("rtw88/rtw8821a_fw.bin");
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.h b/drivers/net/wireless/realtek/rtw88/rtw8821a.h
new file mode 100644
index 000000000000..1b2e548f7234
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#ifndef __RTW8821A_H__
+#define __RTW8821A_H__
+
+extern const struct rtw_chip_info rtw8821a_hw_spec;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c
new file mode 100644
index 000000000000..c8fd8e331f69
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c
@@ -0,0 +1,2350 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include "main.h"
+#include "phy.h"
+#include "rtw8821a_table.h"
+
+static const u32 rtw8821a_mac[] = {
+ 0x421, 0x0000000F,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000000,
+ 0x432, 0x00000000,
+ 0x433, 0x00000001,
+ 0x434, 0x00000004,
+ 0x435, 0x00000005,
+ 0x436, 0x00000007,
+ 0x437, 0x00000008,
+ 0x43C, 0x00000004,
+ 0x43D, 0x00000005,
+ 0x43E, 0x00000007,
+ 0x43F, 0x00000008,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000010,
+ 0x445, 0x00000000,
+ 0x446, 0x00000000,
+ 0x447, 0x00000000,
+ 0x448, 0x00000000,
+ 0x449, 0x000000F0,
+ 0x44A, 0x0000000F,
+ 0x44B, 0x0000003E,
+ 0x44C, 0x00000010,
+ 0x44D, 0x00000000,
+ 0x44E, 0x00000000,
+ 0x44F, 0x00000000,
+ 0x450, 0x00000000,
+ 0x451, 0x000000F0,
+ 0x452, 0x0000000F,
+ 0x453, 0x00000000,
+ 0x456, 0x0000005E,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x4C8, 0x0000003F,
+ 0x4C9, 0x000000FF,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000A2,
+ 0x502, 0x0000002F,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000A3,
+ 0x506, 0x0000005E,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002B,
+ 0x509, 0x000000A4,
+ 0x50A, 0x0000005E,
+ 0x50B, 0x00000000,
+ 0x50C, 0x0000004F,
+ 0x50D, 0x000000A4,
+ 0x50E, 0x00000000,
+ 0x50F, 0x00000000,
+ 0x512, 0x0000001C,
+ 0x514, 0x0000000A,
+ 0x516, 0x0000000A,
+ 0x525, 0x0000004F,
+ 0x550, 0x00000010,
+ 0x551, 0x00000010,
+ 0x559, 0x00000002,
+ 0x55C, 0x00000050,
+ 0x55D, 0x000000FF,
+ 0x605, 0x00000030,
+ 0x607, 0x00000007,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x638, 0x00000050,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000040,
+ 0x642, 0x00000040,
+ 0x643, 0x00000000,
+ 0x652, 0x000000C8,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+ 0x718, 0x00000040,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8821a_mac, rtw_phy_cfg_mac);
+
+static const u32 rtw8821a_agc[] = {
+ 0x81C, 0xBF000001,
+ 0x81C, 0xBF020001,
+ 0x81C, 0xBF040001,
+ 0x81C, 0xBF060001,
+ 0x81C, 0xBE080001,
+ 0x81C, 0xBD0A0001,
+ 0x81C, 0xBC0C0001,
+ 0x81C, 0xBA0E0001,
+ 0x81C, 0xB9100001,
+ 0x81C, 0xB8120001,
+ 0x81C, 0xB7140001,
+ 0x81C, 0xB6160001,
+ 0x81C, 0xB5180001,
+ 0x81C, 0xB41A0001,
+ 0x81C, 0xB31C0001,
+ 0x81C, 0xB21E0001,
+ 0x81C, 0xB1200001,
+ 0x81C, 0xB0220001,
+ 0x81C, 0xAF240001,
+ 0x81C, 0xAE260001,
+ 0x81C, 0xAD280001,
+ 0x81C, 0xAC2A0001,
+ 0x81C, 0xAB2C0001,
+ 0x81C, 0xAA2E0001,
+ 0x81C, 0xA9300001,
+ 0x81C, 0xA8320001,
+ 0x81C, 0xA7340001,
+ 0x81C, 0xA6360001,
+ 0x81C, 0xA5380001,
+ 0x81C, 0xA43A0001,
+ 0x81C, 0x683C0001,
+ 0x81C, 0x673E0001,
+ 0x81C, 0x66400001,
+ 0x81C, 0x65420001,
+ 0x81C, 0x64440001,
+ 0x81C, 0x63460001,
+ 0x81C, 0x62480001,
+ 0x81C, 0x614A0001,
+ 0x81C, 0x474C0001,
+ 0x81C, 0x464E0001,
+ 0x81C, 0x45500001,
+ 0x81C, 0x44520001,
+ 0x81C, 0x43540001,
+ 0x81C, 0x42560001,
+ 0x81C, 0x41580001,
+ 0x81C, 0x285A0001,
+ 0x81C, 0x275C0001,
+ 0x81C, 0x265E0001,
+ 0x81C, 0x25600001,
+ 0x81C, 0x24620001,
+ 0x81C, 0x0A640001,
+ 0x81C, 0x09660001,
+ 0x81C, 0x08680001,
+ 0x81C, 0x076A0001,
+ 0x81C, 0x066C0001,
+ 0x81C, 0x056E0001,
+ 0x81C, 0x04700001,
+ 0x81C, 0x03720001,
+ 0x81C, 0x02740001,
+ 0x81C, 0x01760001,
+ 0x81C, 0x01780001,
+ 0x81C, 0x017A0001,
+ 0x81C, 0x017C0001,
+ 0x81C, 0x017E0001,
+ 0x8000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0xFB000101,
+ 0x81C, 0xFA020101,
+ 0x81C, 0xF9040101,
+ 0x81C, 0xF8060101,
+ 0x81C, 0xF7080101,
+ 0x81C, 0xF60A0101,
+ 0x81C, 0xF50C0101,
+ 0x81C, 0xF40E0101,
+ 0x81C, 0xF3100101,
+ 0x81C, 0xF2120101,
+ 0x81C, 0xF1140101,
+ 0x81C, 0xF0160101,
+ 0x81C, 0xEF180101,
+ 0x81C, 0xEE1A0101,
+ 0x81C, 0xED1C0101,
+ 0x81C, 0xEC1E0101,
+ 0x81C, 0xEB200101,
+ 0x81C, 0xEA220101,
+ 0x81C, 0xE9240101,
+ 0x81C, 0xE8260101,
+ 0x81C, 0xE7280101,
+ 0x81C, 0xE62A0101,
+ 0x81C, 0xE52C0101,
+ 0x81C, 0xE42E0101,
+ 0x81C, 0xE3300101,
+ 0x81C, 0xA5320101,
+ 0x81C, 0xA4340101,
+ 0x81C, 0xA3360101,
+ 0x81C, 0x87380101,
+ 0x81C, 0x863A0101,
+ 0x81C, 0x853C0101,
+ 0x81C, 0x843E0101,
+ 0x81C, 0x69400101,
+ 0x81C, 0x68420101,
+ 0x81C, 0x67440101,
+ 0x81C, 0x66460101,
+ 0x81C, 0x49480101,
+ 0x81C, 0x484A0101,
+ 0x81C, 0x474C0101,
+ 0x81C, 0x2A4E0101,
+ 0x81C, 0x29500101,
+ 0x81C, 0x28520101,
+ 0x81C, 0x27540101,
+ 0x81C, 0x26560101,
+ 0x81C, 0x25580101,
+ 0x81C, 0x245A0101,
+ 0x81C, 0x235C0101,
+ 0x81C, 0x055E0101,
+ 0x81C, 0x04600101,
+ 0x81C, 0x03620101,
+ 0x81C, 0x02640101,
+ 0x81C, 0x01660101,
+ 0x81C, 0x01680101,
+ 0x81C, 0x016A0101,
+ 0x81C, 0x016C0101,
+ 0x81C, 0x016E0101,
+ 0x81C, 0x01700101,
+ 0x81C, 0x01720101,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x81C, 0xFB000101,
+ 0x81C, 0xFA020101,
+ 0x81C, 0xF9040101,
+ 0x81C, 0xF8060101,
+ 0x81C, 0xF7080101,
+ 0x81C, 0xF60A0101,
+ 0x81C, 0xF50C0101,
+ 0x81C, 0xF40E0101,
+ 0x81C, 0xF3100101,
+ 0x81C, 0xF2120101,
+ 0x81C, 0xF1140101,
+ 0x81C, 0xF0160101,
+ 0x81C, 0xEF180101,
+ 0x81C, 0xEE1A0101,
+ 0x81C, 0xED1C0101,
+ 0x81C, 0xEC1E0101,
+ 0x81C, 0xEB200101,
+ 0x81C, 0xEA220101,
+ 0x81C, 0xE9240101,
+ 0x81C, 0xE8260101,
+ 0x81C, 0xE7280101,
+ 0x81C, 0xE62A0101,
+ 0x81C, 0xE52C0101,
+ 0x81C, 0xE42E0101,
+ 0x81C, 0xE3300101,
+ 0x81C, 0xA5320101,
+ 0x81C, 0xA4340101,
+ 0x81C, 0xA3360101,
+ 0x81C, 0x87380101,
+ 0x81C, 0x863A0101,
+ 0x81C, 0x853C0101,
+ 0x81C, 0x843E0101,
+ 0x81C, 0x69400101,
+ 0x81C, 0x68420101,
+ 0x81C, 0x67440101,
+ 0x81C, 0x66460101,
+ 0x81C, 0x49480101,
+ 0x81C, 0x484A0101,
+ 0x81C, 0x474C0101,
+ 0x81C, 0x2A4E0101,
+ 0x81C, 0x29500101,
+ 0x81C, 0x28520101,
+ 0x81C, 0x27540101,
+ 0x81C, 0x26560101,
+ 0x81C, 0x25580101,
+ 0x81C, 0x245A0101,
+ 0x81C, 0x235C0101,
+ 0x81C, 0x055E0101,
+ 0x81C, 0x04600101,
+ 0x81C, 0x03620101,
+ 0x81C, 0x02640101,
+ 0x81C, 0x01660101,
+ 0x81C, 0x01680101,
+ 0x81C, 0x016A0101,
+ 0x81C, 0x016C0101,
+ 0x81C, 0x016E0101,
+ 0x81C, 0x01700101,
+ 0x81C, 0x01720101,
+ 0xA0000000, 0x00000000,
+ 0x81C, 0xFF000101,
+ 0x81C, 0xFF020101,
+ 0x81C, 0xFE040101,
+ 0x81C, 0xFD060101,
+ 0x81C, 0xFC080101,
+ 0x81C, 0xFD0A0101,
+ 0x81C, 0xFC0C0101,
+ 0x81C, 0xFB0E0101,
+ 0x81C, 0xFA100101,
+ 0x81C, 0xF9120101,
+ 0x81C, 0xF8140101,
+ 0x81C, 0xF7160101,
+ 0x81C, 0xF6180101,
+ 0x81C, 0xF51A0101,
+ 0x81C, 0xF41C0101,
+ 0x81C, 0xF31E0101,
+ 0x81C, 0xF2200101,
+ 0x81C, 0xF1220101,
+ 0x81C, 0xF0240101,
+ 0x81C, 0xEF260101,
+ 0x81C, 0xEE280101,
+ 0x81C, 0xED2A0101,
+ 0x81C, 0xEC2C0101,
+ 0x81C, 0xEB2E0101,
+ 0x81C, 0xEA300101,
+ 0x81C, 0xE9320101,
+ 0x81C, 0xE8340101,
+ 0x81C, 0xE7360101,
+ 0x81C, 0xE6380101,
+ 0x81C, 0xE53A0101,
+ 0x81C, 0xE43C0101,
+ 0x81C, 0xE33E0101,
+ 0x81C, 0xA5400101,
+ 0x81C, 0xA4420101,
+ 0x81C, 0xA3440101,
+ 0x81C, 0x87460101,
+ 0x81C, 0x86480101,
+ 0x81C, 0x854A0101,
+ 0x81C, 0x844C0101,
+ 0x81C, 0x694E0101,
+ 0x81C, 0x68500101,
+ 0x81C, 0x67520101,
+ 0x81C, 0x66540101,
+ 0x81C, 0x49560101,
+ 0x81C, 0x48580101,
+ 0x81C, 0x475A0101,
+ 0x81C, 0x2A5C0101,
+ 0x81C, 0x295E0101,
+ 0x81C, 0x28600101,
+ 0x81C, 0x27620101,
+ 0x81C, 0x26640101,
+ 0x81C, 0x25660101,
+ 0x81C, 0x24680101,
+ 0x81C, 0x236A0101,
+ 0x81C, 0x056C0101,
+ 0x81C, 0x046E0101,
+ 0x81C, 0x03700101,
+ 0x81C, 0x02720101,
+ 0xB0000000, 0x00000000,
+ 0x81C, 0x01740101,
+ 0x81C, 0x01760101,
+ 0x81C, 0x01780101,
+ 0x81C, 0x017A0101,
+ 0x81C, 0x017C0101,
+ 0x81C, 0x017E0101,
+ 0xC50, 0x00000022,
+ 0xC50, 0x00000020,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8821a_agc, rtw_phy_cfg_agc);
+
+static const u32 rtw8821a_bb[] = {
+ 0x800, 0x0020D090,
+ 0x804, 0x080112E0,
+ 0x808, 0x0E028211,
+ 0x80C, 0x92131111,
+ 0x810, 0x20101261,
+ 0x814, 0x020C3D10,
+ 0x818, 0x03A00385,
+ 0x820, 0x00000000,
+ 0x824, 0x00030FE0,
+ 0x828, 0x00000000,
+ 0x82C, 0x002081DD,
+ 0x830, 0x2AAAEEC8,
+ 0x834, 0x0037A706,
+ 0x838, 0x06489B44,
+ 0x83C, 0x0000095B,
+ 0x840, 0xC0000001,
+ 0x844, 0x40003CDE,
+ 0x848, 0x62103F8B,
+ 0x84C, 0x6CFDFFB8,
+ 0x850, 0x28874706,
+ 0x854, 0x0001520C,
+ 0x858, 0x8060E000,
+ 0x85C, 0x74210168,
+ 0x860, 0x6929C321,
+ 0x864, 0x79727432,
+ 0x868, 0x8CA7A314,
+ 0x86C, 0x888C2878,
+ 0x870, 0x08888888,
+ 0x874, 0x31612C2E,
+ 0x878, 0x00000152,
+ 0x87C, 0x000FD000,
+ 0x8A0, 0x00000013,
+ 0x8A4, 0x7F7F7F7F,
+ 0x8A8, 0xA2000338,
+ 0x8AC, 0x0FF0FA0A,
+ 0x8B4, 0x000FC080,
+ 0x8B8, 0x6C10D7FF,
+ 0x8BC, 0x0CA52090,
+ 0x8C0, 0x1BF00020,
+ 0x8C4, 0x00000000,
+ 0x8C8, 0x00013169,
+ 0x8CC, 0x08248492,
+ 0x8D4, 0x940008A0,
+ 0x8D8, 0x290B5612,
+ 0x8F8, 0x400002C0,
+ 0x8FC, 0x00000000,
+ 0x900, 0x00000700,
+ 0x90C, 0x00000000,
+ 0x910, 0x0000FC00,
+ 0x914, 0x00000404,
+ 0x918, 0x1C1028C0,
+ 0x91C, 0x64B11A1C,
+ 0x920, 0xE0767233,
+ 0x924, 0x055AA500,
+ 0x928, 0x00000004,
+ 0x92C, 0xFFFE0000,
+ 0x930, 0xFFFFFFFE,
+ 0x934, 0x001FFFFF,
+ 0x960, 0x00000000,
+ 0x964, 0x00000000,
+ 0x968, 0x00000000,
+ 0x96C, 0x00000000,
+ 0x970, 0x801FFFFF,
+ 0x974, 0x000003FF,
+ 0x978, 0x00000000,
+ 0x97C, 0x00000000,
+ 0x980, 0x00000000,
+ 0x984, 0x00000000,
+ 0x988, 0x00000000,
+ 0x990, 0x27100000,
+ 0x994, 0xFFFF0100,
+ 0x998, 0xFFFFFF5C,
+ 0x99C, 0xFFFFFFFF,
+ 0x9A0, 0x000000FF,
+ 0x9A4, 0x00480080,
+ 0x9A8, 0x00000000,
+ 0x9AC, 0x00000000,
+ 0x9B0, 0x81081008,
+ 0x9B4, 0x01081008,
+ 0x9B8, 0x01081008,
+ 0x9BC, 0x01081008,
+ 0x9D0, 0x00000000,
+ 0x9D4, 0x00000000,
+ 0x9D8, 0x00000000,
+ 0x9DC, 0x00000000,
+ 0x9E0, 0x00005D00,
+ 0x9E4, 0x00000003,
+ 0x9E8, 0x00000001,
+ 0xA00, 0x00D047C8,
+ 0xA04, 0x01FF800C,
+ 0xA08, 0x8C8A8300,
+ 0xA0C, 0x2E68000F,
+ 0xA10, 0x9500BB78,
+ 0xA14, 0x11144028,
+ 0xA18, 0x00881117,
+ 0xA1C, 0x89140F00,
+ 0xA20, 0x1A1B0000,
+ 0xA24, 0x090E1317,
+ 0xA28, 0x00000204,
+ 0xA2C, 0x00900000,
+ 0xA70, 0x101FFF00,
+ 0xA74, 0x00000008,
+ 0xA78, 0x00000900,
+ 0xA7C, 0x225B0606,
+ 0xA80, 0x21805490,
+ 0xA84, 0x001F0000,
+ 0XB00, 0x03100040,
+ 0XB04, 0x0000B000,
+ 0XB08, 0xAE0201EB,
+ 0XB0C, 0x01003207,
+ 0XB10, 0x00009807,
+ 0XB14, 0x01000000,
+ 0XB18, 0x00000002,
+ 0XB1C, 0x00000002,
+ 0XB20, 0x0000001F,
+ 0XB24, 0x03020100,
+ 0XB28, 0x07060504,
+ 0XB2C, 0x0B0A0908,
+ 0XB30, 0x0F0E0D0C,
+ 0XB34, 0x13121110,
+ 0XB38, 0x17161514,
+ 0XB3C, 0x0000003A,
+ 0XB40, 0x00000000,
+ 0XB44, 0x00000000,
+ 0XB48, 0x13000032,
+ 0XB4C, 0x48080000,
+ 0XB50, 0x00000000,
+ 0XB54, 0x00000000,
+ 0XB58, 0x00000000,
+ 0XB5C, 0x00000000,
+ 0xC00, 0x00000007,
+ 0xC04, 0x00042020,
+ 0xC08, 0x80410231,
+ 0xC0C, 0x00000000,
+ 0xC10, 0x00000100,
+ 0xC14, 0x01000000,
+ 0xC1C, 0x40000003,
+ 0xC20, 0x2C2C2C2C,
+ 0xC24, 0x30303030,
+ 0xC28, 0x30303030,
+ 0xC2C, 0x2C2C2C2C,
+ 0xC30, 0x2C2C2C2C,
+ 0xC34, 0x2C2C2C2C,
+ 0xC38, 0x2C2C2C2C,
+ 0xC3C, 0x2A2A2A2A,
+ 0xC40, 0x2A2A2A2A,
+ 0xC44, 0x2A2A2A2A,
+ 0xC48, 0x2A2A2A2A,
+ 0xC4C, 0x2A2A2A2A,
+ 0xC50, 0x00000020,
+ 0xC54, 0x001C1208,
+ 0xC58, 0x30000C1C,
+ 0xC5C, 0x00000058,
+ 0xC60, 0x34344443,
+ 0xC64, 0x07003333,
+ 0xC68, 0x19791979,
+ 0xC6C, 0x19791979,
+ 0xC70, 0x19791979,
+ 0xC74, 0x19791979,
+ 0xC78, 0x19791979,
+ 0xC7C, 0x19791979,
+ 0xC80, 0x19791979,
+ 0xC84, 0x19791979,
+ 0xC94, 0x0100005C,
+ 0xC98, 0x00000000,
+ 0xC9C, 0x00000000,
+ 0xCA0, 0x00000029,
+ 0xCA4, 0x08040201,
+ 0xCA8, 0x80402010,
+ 0xCB0, 0x77775747,
+ 0xCB4, 0x10000077,
+ 0xCB8, 0x00508240,
+};
+
+RTW_DECL_TABLE_PHY_COND(rtw8821a_bb, rtw_phy_cfg_bb);
+
+static const struct rtw_phy_pg_cfg_pair rtw8821a_bb_pg[] = {
+ { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, },
+ { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36363838, },
+ { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, },
+ { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363838, },
+ { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, },
+ { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, },
+ { 0, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, },
+ { 0, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, },
+ { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34343636, },
+ { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, },
+ { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343636, },
+ { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, },
+ { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, },
+ { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, },
+ { 1, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, },
+};
+
+RTW_DECL_TABLE_BB_PG(rtw8821a_bb_pg);
+
+static const u32 rtw8821a_rf_a[] = {
+ 0x018, 0x0001712A,
+ 0x056, 0x00051CF2,
+ 0x066, 0x00040000,
+ 0x000, 0x00010000,
+ 0x01E, 0x00080000,
+ 0x082, 0x00000830,
+ 0x083, 0x00021800,
+ 0x084, 0x00028000,
+ 0x085, 0x00048000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x086, 0x0009483A,
+ 0xA0000000, 0x00000000,
+ 0x086, 0x00094838,
+ 0xB0000000, 0x00000000,
+ 0x087, 0x00044980,
+ 0x088, 0x00048000,
+ 0x089, 0x0000D480,
+ 0x08A, 0x00042240,
+ 0x08B, 0x000F0380,
+ 0x08C, 0x00090000,
+ 0x08D, 0x00022852,
+ 0x08E, 0x00065540,
+ 0x08F, 0x00088001,
+ 0x0EF, 0x00020000,
+ 0x03E, 0x00000380,
+ 0x03F, 0x00090018,
+ 0x03E, 0x00020380,
+ 0x03F, 0x000A0018,
+ 0x03E, 0x00040308,
+ 0x03F, 0x000A0018,
+ 0x03E, 0x00060018,
+ 0x03F, 0x000A0018,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x089, 0x00000080,
+ 0x08B, 0x00080180,
+ 0x0EF, 0x00001000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x00038027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x00030113,
+ 0x03C, 0x00082000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x00028027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x000000CC,
+ 0x03B, 0x00027027,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x0001F913,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000010C,
+ 0x03B, 0x00017F10,
+ 0x03C, 0x00012000,
+ 0x03A, 0x000000D0,
+ 0x03B, 0x00008027,
+ 0x03C, 0x000CA000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x00078027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x00070113,
+ 0x03C, 0x00082000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x00068027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x000000CC,
+ 0x03B, 0x00067027,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x0005F913,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000010C,
+ 0x03B, 0x00057F10,
+ 0x03C, 0x00012000,
+ 0x03A, 0x000000D0,
+ 0x03B, 0x00048027,
+ 0x03C, 0x000CA000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x000B8027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x00000244,
+ 0x03B, 0x000B0113,
+ 0x03C, 0x00082000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x000A8027,
+ 0x03C, 0x00082000,
+ 0x03A, 0x000000CC,
+ 0x03B, 0x000A7027,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000014C,
+ 0x03B, 0x0009F913,
+ 0x03C, 0x00042000,
+ 0x03A, 0x0000010C,
+ 0x03B, 0x00097F10,
+ 0x03C, 0x00012000,
+ 0x03A, 0x000000D0,
+ 0x03B, 0x00088027,
+ 0x03C, 0x000CA000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00001100,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004ADF3,
+ 0x034, 0x00049DF0,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004ADF3,
+ 0x034, 0x00049DF0,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004ADF5,
+ 0x034, 0x00049DF2,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0F3,
+ 0x034, 0x000490B1,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004A0F3,
+ 0x034, 0x000490B1,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004ADF5,
+ 0x034, 0x00049DF2,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0004ADF3,
+ 0x034, 0x00049DF0,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0004ADF7,
+ 0x034, 0x00049DF3,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00048DED,
+ 0x034, 0x00047DEA,
+ 0x034, 0x00046DE7,
+ 0x034, 0x00045CE9,
+ 0x034, 0x00044CE6,
+ 0x034, 0x000438C6,
+ 0x034, 0x00042886,
+ 0x034, 0x00041486,
+ 0x034, 0x00040447,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00048DED,
+ 0x034, 0x00047DEA,
+ 0x034, 0x00046DE7,
+ 0x034, 0x00045CE9,
+ 0x034, 0x00044CE6,
+ 0x034, 0x000438C6,
+ 0x034, 0x00042886,
+ 0x034, 0x00041486,
+ 0x034, 0x00040447,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000480AE,
+ 0x034, 0x000470AB,
+ 0x034, 0x0004608B,
+ 0x034, 0x00045069,
+ 0x034, 0x00044048,
+ 0x034, 0x00043045,
+ 0x034, 0x00042026,
+ 0x034, 0x00041023,
+ 0x034, 0x00040002,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000480AE,
+ 0x034, 0x000470AB,
+ 0x034, 0x0004608B,
+ 0x034, 0x00045069,
+ 0x034, 0x00044048,
+ 0x034, 0x00043045,
+ 0x034, 0x00042026,
+ 0x034, 0x00041023,
+ 0x034, 0x00040002,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00048DED,
+ 0x034, 0x00047DEA,
+ 0x034, 0x00046DE7,
+ 0x034, 0x00045CE9,
+ 0x034, 0x00044CE6,
+ 0x034, 0x000438C6,
+ 0x034, 0x00042886,
+ 0x034, 0x00041486,
+ 0x034, 0x00040447,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x00048DEF,
+ 0x034, 0x00047DEC,
+ 0x034, 0x00046DE9,
+ 0x034, 0x00045CCB,
+ 0x034, 0x0004488D,
+ 0x034, 0x0004348D,
+ 0x034, 0x0004248A,
+ 0x034, 0x0004108D,
+ 0x034, 0x0004008A,
+ 0xB0000000, 0x00000000,
+ 0x80000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002ADF4,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0F3,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002A0F3,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0002ADF4,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0002ADF7,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00029DF4,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00029DF4,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00029DF1,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000290F0,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000290F0,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00029DF1,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00029DF4,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x00029DF2,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00028DF1,
+ 0x034, 0x00027DEE,
+ 0x034, 0x00026DEB,
+ 0x034, 0x00025CEC,
+ 0x034, 0x00024CE9,
+ 0x034, 0x000238CA,
+ 0x034, 0x00022889,
+ 0x034, 0x00021489,
+ 0x034, 0x0002044A,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00028DF1,
+ 0x034, 0x00027DEE,
+ 0x034, 0x00026DEB,
+ 0x034, 0x00025CEC,
+ 0x034, 0x00024CE9,
+ 0x034, 0x000238CA,
+ 0x034, 0x00022889,
+ 0x034, 0x00021489,
+ 0x034, 0x0002044A,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000280AF,
+ 0x034, 0x000270AC,
+ 0x034, 0x0002608B,
+ 0x034, 0x00025069,
+ 0x034, 0x00024048,
+ 0x034, 0x00023045,
+ 0x034, 0x00022026,
+ 0x034, 0x00021023,
+ 0x034, 0x00020002,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x000280AF,
+ 0x034, 0x000270AC,
+ 0x034, 0x0002608B,
+ 0x034, 0x00025069,
+ 0x034, 0x00024048,
+ 0x034, 0x00023045,
+ 0x034, 0x00022026,
+ 0x034, 0x00021023,
+ 0x034, 0x00020002,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00028DF1,
+ 0x034, 0x00027DEE,
+ 0x034, 0x00026DEB,
+ 0x034, 0x00025CEC,
+ 0x034, 0x00024CE9,
+ 0x034, 0x000238CA,
+ 0x034, 0x00022889,
+ 0x034, 0x00021489,
+ 0x034, 0x0002044A,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x00028DEE,
+ 0x034, 0x00027DEB,
+ 0x034, 0x00026CCD,
+ 0x034, 0x00025CCA,
+ 0x034, 0x0002488C,
+ 0x034, 0x0002384C,
+ 0x034, 0x00022849,
+ 0x034, 0x00021449,
+ 0x034, 0x0002004D,
+ 0xB0000000, 0x00000000,
+ 0x8000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0D7,
+ 0x034, 0x000090D3,
+ 0x034, 0x000080B1,
+ 0x034, 0x000070AE,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000A0D7,
+ 0x034, 0x000090D3,
+ 0x034, 0x000080B1,
+ 0x034, 0x000070AE,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x0000ADF7,
+ 0x034, 0x00009DF4,
+ 0x034, 0x00008DF1,
+ 0x034, 0x00007DEE,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00006DEB,
+ 0x034, 0x00005CEC,
+ 0x034, 0x00004CE9,
+ 0x034, 0x000038CA,
+ 0x034, 0x00002889,
+ 0x034, 0x00001489,
+ 0x034, 0x0000044A,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00006DEB,
+ 0x034, 0x00005CEC,
+ 0x034, 0x00004CE9,
+ 0x034, 0x000038CA,
+ 0x034, 0x00002889,
+ 0x034, 0x00001489,
+ 0x034, 0x0000044A,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000608D,
+ 0x034, 0x0000506B,
+ 0x034, 0x0000404A,
+ 0x034, 0x00003047,
+ 0x034, 0x00002044,
+ 0x034, 0x00001025,
+ 0x034, 0x00000004,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x0000608D,
+ 0x034, 0x0000506B,
+ 0x034, 0x0000404A,
+ 0x034, 0x00003047,
+ 0x034, 0x00002044,
+ 0x034, 0x00001025,
+ 0x034, 0x00000004,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x034, 0x00006DEB,
+ 0x034, 0x00005CEC,
+ 0x034, 0x00004CE9,
+ 0x034, 0x000038CA,
+ 0x034, 0x00002889,
+ 0x034, 0x00001489,
+ 0x034, 0x0000044A,
+ 0xA0000000, 0x00000000,
+ 0x034, 0x00006DCD,
+ 0x034, 0x00005CCD,
+ 0x034, 0x00004CCA,
+ 0x034, 0x0000388C,
+ 0x034, 0x00002888,
+ 0x034, 0x00001488,
+ 0x034, 0x00000486,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000040,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000187,
+ 0x035, 0x00008187,
+ 0x035, 0x00010187,
+ 0x035, 0x00020188,
+ 0x035, 0x00028188,
+ 0x035, 0x00030188,
+ 0x035, 0x00040188,
+ 0x035, 0x00048188,
+ 0x035, 0x00050188,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000187,
+ 0x035, 0x00008187,
+ 0x035, 0x00010187,
+ 0x035, 0x00020188,
+ 0x035, 0x00028188,
+ 0x035, 0x00030188,
+ 0x035, 0x00040188,
+ 0x035, 0x00048188,
+ 0x035, 0x00050188,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000128,
+ 0x035, 0x00008128,
+ 0x035, 0x00010128,
+ 0x035, 0x000201C8,
+ 0x035, 0x000281C8,
+ 0x035, 0x000301C8,
+ 0x035, 0x000401C8,
+ 0x035, 0x000481C8,
+ 0x035, 0x000501C8,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000145,
+ 0x035, 0x00008145,
+ 0x035, 0x00010145,
+ 0x035, 0x00020196,
+ 0x035, 0x00028196,
+ 0x035, 0x00030196,
+ 0x035, 0x000401C7,
+ 0x035, 0x000481C7,
+ 0x035, 0x000501C7,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000128,
+ 0x035, 0x00008128,
+ 0x035, 0x00010128,
+ 0x035, 0x000201C8,
+ 0x035, 0x000281C8,
+ 0x035, 0x000301C8,
+ 0x035, 0x000401C8,
+ 0x035, 0x000481C8,
+ 0x035, 0x000501C8,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x035, 0x00000187,
+ 0x035, 0x00008187,
+ 0x035, 0x00010187,
+ 0x035, 0x00020188,
+ 0x035, 0x00028188,
+ 0x035, 0x00030188,
+ 0x035, 0x00040188,
+ 0x035, 0x00048188,
+ 0x035, 0x00050188,
+ 0xA0000000, 0x00000000,
+ 0x035, 0x00000145,
+ 0x035, 0x00008145,
+ 0x035, 0x00010145,
+ 0x035, 0x00020196,
+ 0x035, 0x00028196,
+ 0x035, 0x00030196,
+ 0x035, 0x000401C7,
+ 0x035, 0x000481C7,
+ 0x035, 0x000501C7,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000010,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x00085733,
+ 0x036, 0x0008D733,
+ 0x036, 0x00095733,
+ 0x036, 0x0009D733,
+ 0x036, 0x000A64B4,
+ 0x036, 0x000AE4B4,
+ 0x036, 0x000B64B4,
+ 0x036, 0x000BE4B4,
+ 0x036, 0x000C64B4,
+ 0x036, 0x000CE4B4,
+ 0x036, 0x000D64B4,
+ 0x036, 0x000DE4B4,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x00085733,
+ 0x036, 0x0008D733,
+ 0x036, 0x00095733,
+ 0x036, 0x0009D733,
+ 0x036, 0x000A64B4,
+ 0x036, 0x000AE4B4,
+ 0x036, 0x000B64B4,
+ 0x036, 0x000BE4B4,
+ 0x036, 0x000C64B4,
+ 0x036, 0x000CE4B4,
+ 0x036, 0x000D64B4,
+ 0x036, 0x000DE4B4,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x000063B5,
+ 0x036, 0x0000E3B5,
+ 0x036, 0x000163B5,
+ 0x036, 0x0001E3B5,
+ 0x036, 0x000263B5,
+ 0x036, 0x0002E3B5,
+ 0x036, 0x000363B5,
+ 0x036, 0x0003E3B5,
+ 0x036, 0x000463B5,
+ 0x036, 0x0004E3B5,
+ 0x036, 0x000563B5,
+ 0x036, 0x0005E3B5,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x000056B3,
+ 0x036, 0x0000D6B3,
+ 0x036, 0x000156B3,
+ 0x036, 0x0001D6B3,
+ 0x036, 0x00026634,
+ 0x036, 0x0002E634,
+ 0x036, 0x00036634,
+ 0x036, 0x0003E634,
+ 0x036, 0x000467B4,
+ 0x036, 0x0004E7B4,
+ 0x036, 0x000567B4,
+ 0x036, 0x0005E7B4,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x000063B5,
+ 0x036, 0x0000E3B5,
+ 0x036, 0x000163B5,
+ 0x036, 0x0001E3B5,
+ 0x036, 0x000263B5,
+ 0x036, 0x0002E3B5,
+ 0x036, 0x000363B5,
+ 0x036, 0x0003E3B5,
+ 0x036, 0x000463B5,
+ 0x036, 0x0004E3B5,
+ 0x036, 0x000563B5,
+ 0x036, 0x0005E3B5,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x036, 0x00085733,
+ 0x036, 0x0008D733,
+ 0x036, 0x00095733,
+ 0x036, 0x0009D733,
+ 0x036, 0x000A64B4,
+ 0x036, 0x000AE4B4,
+ 0x036, 0x000B64B4,
+ 0x036, 0x000BE4B4,
+ 0x036, 0x000C64B4,
+ 0x036, 0x000CE4B4,
+ 0x036, 0x000D64B4,
+ 0x036, 0x000DE4B4,
+ 0xA0000000, 0x00000000,
+ 0x036, 0x000056B3,
+ 0x036, 0x0000D6B3,
+ 0x036, 0x000156B3,
+ 0x036, 0x0001D6B3,
+ 0x036, 0x00026634,
+ 0x036, 0x0002E634,
+ 0x036, 0x00036634,
+ 0x036, 0x0003E634,
+ 0x036, 0x000467B4,
+ 0x036, 0x0004E7B4,
+ 0x036, 0x000567B4,
+ 0x036, 0x0005E7B4,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00000008,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000001C8,
+ 0x03C, 0x00000492,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000001C8,
+ 0x03C, 0x00000492,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000001B6,
+ 0x03C, 0x00000492,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x0000022A,
+ 0x03C, 0x00000594,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000001B6,
+ 0x03C, 0x00000492,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x000001C8,
+ 0x03C, 0x00000492,
+ 0xA0000000, 0x00000000,
+ 0x03C, 0x0000022A,
+ 0x03C, 0x00000594,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000800,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000800,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000800,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000820,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000820,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000800,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x03C, 0x00000800,
+ 0xA0000000, 0x00000000,
+ 0x03C, 0x00000900,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x018, 0x0001712A,
+ 0x0EF, 0x00000002,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x0004E400,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x0004E400,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x00002000,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x00002000,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x00002000,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x00002000,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x008, 0x0004E400,
+ 0xA0000000, 0x00000000,
+ 0x008, 0x00002000,
+ 0xB0000000, 0x00000000,
+ 0x0EF, 0x00000000,
+ 0x0DF, 0x000000C0,
+ 0x01F, 0x00000064,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x000A7284,
+ 0x059, 0x000600EC,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x000A7284,
+ 0x059, 0x000600EC,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x00081184,
+ 0x059, 0x0006016C,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x00081184,
+ 0x059, 0x0006016C,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x00081184,
+ 0x059, 0x0006016C,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x058, 0x000A7284,
+ 0x059, 0x000600EC,
+ 0xA0000000, 0x00000000,
+ 0x058, 0x00081184,
+ 0x059, 0x0006016C,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000E8D73,
+ 0x062, 0x00093FC5,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000E8D73,
+ 0x062, 0x00093FC5,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EFD83,
+ 0x062, 0x00093FCC,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EAD53,
+ 0x062, 0x00093BC4,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000EFD83,
+ 0x062, 0x00093FCC,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x061, 0x000E8D73,
+ 0x062, 0x00093FC5,
+ 0xA0000000, 0x00000000,
+ 0x061, 0x000EAD53,
+ 0x062, 0x00093BC4,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110E9,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110E9,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110EB,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110E9,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110E9,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110EB,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x063, 0x000110E9,
+ 0xA0000000, 0x00000000,
+ 0x063, 0x000714E9,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C27C,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C27C,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C27C,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C67C,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C27C,
+ 0x90000410, 0x00000000, 0x40000000, 0x00000000,
+ 0x064, 0x0001C27C,
+ 0xA0000000, 0x00000000,
+ 0x064, 0x0001C67C,
+ 0xB0000000, 0x00000000,
+ 0x80000111, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00091016,
+ 0x90000110, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00091016,
+ 0x90000210, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00093016,
+ 0x9000020c, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00093015,
+ 0x9000040c, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00093015,
+ 0x90000200, 0x00000000, 0x40000000, 0x00000000,
+ 0x065, 0x00093016,
+ 0xA0000000, 0x00000000,
+ 0x065, 0x00091016,
+ 0xB0000000, 0x00000000,
+ 0x018, 0x00000006,
+ 0x0EF, 0x00002000,
+ 0x03B, 0x0003824B,
+ 0x03B, 0x0003024B,
+ 0x03B, 0x0002844B,
+ 0x03B, 0x00020F4B,
+ 0x03B, 0x00018F4B,
+ 0x03B, 0x000104B2,
+ 0x03B, 0x00008049,
+ 0x03B, 0x00000148,
+ 0x03B, 0x0007824B,
+ 0x03B, 0x0007024B,
+ 0x03B, 0x0006824B,
+ 0x03B, 0x00060F4B,
+ 0x03B, 0x00058F4B,
+ 0x03B, 0x000504B2,
+ 0x03B, 0x00048049,
+ 0x03B, 0x00040148,
+ 0x0EF, 0x00000000,
+ 0x0EF, 0x00000100,
+ 0x034, 0x0000ADF3,
+ 0x034, 0x00009DF0,
+ 0x034, 0x00008D70,
+ 0x034, 0x00007D6D,
+ 0x034, 0x00006CEE,
+ 0x034, 0x00005CCC,
+ 0x034, 0x000044EC,
+ 0x034, 0x000034AC,
+ 0x034, 0x0000246D,
+ 0x034, 0x0000106F,
+ 0x034, 0x0000006C,
+ 0x0EF, 0x00000000,
+ 0x0ED, 0x00000010,
+ 0x044, 0x0000ADF2,
+ 0x044, 0x00009DEF,
+ 0x044, 0x00008DEC,
+ 0x044, 0x00007DE9,
+ 0x044, 0x00006CEC,
+ 0x044, 0x00005CE9,
+ 0x044, 0x000044EC,
+ 0x044, 0x000034E9,
+ 0x044, 0x0000246C,
+ 0x044, 0x00001469,
+ 0x044, 0x0000006C,
+ 0x0ED, 0x00000000,
+ 0x0ED, 0x00000001,
+ 0x040, 0x00038DA7,
+ 0x040, 0x000300C2,
+ 0x040, 0x000288E2,
+ 0x040, 0x000200B8,
+ 0x040, 0x000188A5,
+ 0x040, 0x00010FBC,
+ 0x040, 0x00008F71,
+ 0x040, 0x00000240,
+ 0x0ED, 0x00000000,
+ 0x0EF, 0x000020A2,
+ 0x0DF, 0x00000080,
+ 0x035, 0x00000120,
+ 0x035, 0x00008120,
+ 0x035, 0x00010120,
+ 0x036, 0x00000085,
+ 0x036, 0x00008085,
+ 0x036, 0x00010085,
+ 0x036, 0x00018085,
+ 0x0EF, 0x00000000,
+ 0x051, 0x00000C31,
+ 0x052, 0x00000622,
+ 0x053, 0x000FC70B,
+ 0x054, 0x0000017E,
+ 0x056, 0x00051DF3,
+ 0x051, 0x00000C01,
+ 0x052, 0x000006D6,
+ 0x053, 0x000FC649,
+ 0x070, 0x00049661,
+ 0x071, 0x0007843E,
+ 0x072, 0x00000382,
+ 0x074, 0x00051400,
+ 0x035, 0x00000160,
+ 0x035, 0x00008160,
+ 0x035, 0x00010160,
+ 0x036, 0x00000124,
+ 0x036, 0x00008124,
+ 0x036, 0x00010124,
+ 0x036, 0x00018124,
+ 0x0ED, 0x0000000C,
+ 0x045, 0x00000140,
+ 0x045, 0x00008140,
+ 0x045, 0x00010140,
+ 0x046, 0x00000124,
+ 0x046, 0x00008124,
+ 0x046, 0x00010124,
+ 0x046, 0x00018124,
+ 0x0DF, 0x00000088,
+ 0x0B3, 0x000F0E18,
+ 0x0B4, 0x0001214C,
+ 0x0B7, 0x0003000C,
+ 0x01C, 0x000539D2,
+ 0x0C4, 0x000AFE00,
+ 0x018, 0x0001F12A,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x018, 0x0001712A,
+};
+
+RTW_DECL_TABLE_RF_RADIO(rtw8821a_rf_a, A);
+
+static const struct rtw_txpwr_lmt_cfg_pair rtw8821a_txpwr_lmt[] = {
+ { 0, 0, 0, 0, 1, 32, },
+ { 2, 0, 0, 0, 1, 28, },
+ { 1, 0, 0, 0, 1, 32, },
+ { 0, 0, 0, 0, 2, 32, },
+ { 2, 0, 0, 0, 2, 28, },
+ { 1, 0, 0, 0, 2, 32, },
+ { 0, 0, 0, 0, 3, 36, },
+ { 2, 0, 0, 0, 3, 28, },
+ { 1, 0, 0, 0, 3, 32, },
+ { 0, 0, 0, 0, 4, 36, },
+ { 2, 0, 0, 0, 4, 28, },
+ { 1, 0, 0, 0, 4, 32, },
+ { 0, 0, 0, 0, 5, 36, },
+ { 2, 0, 0, 0, 5, 28, },
+ { 1, 0, 0, 0, 5, 32, },
+ { 0, 0, 0, 0, 6, 36, },
+ { 2, 0, 0, 0, 6, 28, },
+ { 1, 0, 0, 0, 6, 32, },
+ { 0, 0, 0, 0, 7, 36, },
+ { 2, 0, 0, 0, 7, 28, },
+ { 1, 0, 0, 0, 7, 32, },
+ { 0, 0, 0, 0, 8, 36, },
+ { 2, 0, 0, 0, 8, 28, },
+ { 1, 0, 0, 0, 8, 32, },
+ { 0, 0, 0, 0, 9, 32, },
+ { 2, 0, 0, 0, 9, 28, },
+ { 1, 0, 0, 0, 9, 32, },
+ { 0, 0, 0, 0, 10, 32, },
+ { 2, 0, 0, 0, 10, 28, },
+ { 1, 0, 0, 0, 10, 32, },
+ { 0, 0, 0, 0, 11, 32, },
+ { 2, 0, 0, 0, 11, 28, },
+ { 1, 0, 0, 0, 11, 32, },
+ { 0, 0, 0, 0, 12, 28, },
+ { 2, 0, 0, 0, 12, 28, },
+ { 1, 0, 0, 0, 12, 32, },
+ { 0, 0, 0, 0, 13, 26, },
+ { 2, 0, 0, 0, 13, 28, },
+ { 1, 0, 0, 0, 13, 32, },
+ { 0, 0, 0, 0, 14, 63, },
+ { 2, 0, 0, 0, 14, 63, },
+ { 1, 0, 0, 0, 14, 32, },
+ { 0, 0, 0, 1, 1, 30, },
+ { 2, 0, 0, 1, 1, 30, },
+ { 1, 0, 0, 1, 1, 32, },
+ { 0, 0, 0, 1, 2, 30, },
+ { 2, 0, 0, 1, 2, 32, },
+ { 1, 0, 0, 1, 2, 32, },
+ { 0, 0, 0, 1, 3, 32, },
+ { 2, 0, 0, 1, 3, 32, },
+ { 1, 0, 0, 1, 3, 32, },
+ { 0, 0, 0, 1, 4, 32, },
+ { 2, 0, 0, 1, 4, 32, },
+ { 1, 0, 0, 1, 4, 32, },
+ { 0, 0, 0, 1, 5, 32, },
+ { 2, 0, 0, 1, 5, 32, },
+ { 1, 0, 0, 1, 5, 32, },
+ { 0, 0, 0, 1, 6, 32, },
+ { 2, 0, 0, 1, 6, 32, },
+ { 1, 0, 0, 1, 6, 32, },
+ { 0, 0, 0, 1, 7, 32, },
+ { 2, 0, 0, 1, 7, 32, },
+ { 1, 0, 0, 1, 7, 32, },
+ { 0, 0, 0, 1, 8, 32, },
+ { 2, 0, 0, 1, 8, 32, },
+ { 1, 0, 0, 1, 8, 32, },
+ { 0, 0, 0, 1, 9, 30, },
+ { 2, 0, 0, 1, 9, 32, },
+ { 1, 0, 0, 1, 9, 32, },
+ { 0, 0, 0, 1, 10, 30, },
+ { 2, 0, 0, 1, 10, 32, },
+ { 1, 0, 0, 1, 10, 32, },
+ { 0, 0, 0, 1, 11, 30, },
+ { 2, 0, 0, 1, 11, 32, },
+ { 1, 0, 0, 1, 11, 32, },
+ { 0, 0, 0, 1, 12, 26, },
+ { 2, 0, 0, 1, 12, 32, },
+ { 1, 0, 0, 1, 12, 32, },
+ { 0, 0, 0, 1, 13, 24, },
+ { 2, 0, 0, 1, 13, 30, },
+ { 1, 0, 0, 1, 13, 32, },
+ { 0, 0, 0, 1, 14, 63, },
+ { 2, 0, 0, 1, 14, 63, },
+ { 1, 0, 0, 1, 14, 63, },
+ { 0, 0, 0, 2, 1, 26, },
+ { 2, 0, 0, 2, 1, 26, },
+ { 1, 0, 0, 2, 1, 32, },
+ { 0, 0, 0, 2, 2, 26, },
+ { 2, 0, 0, 2, 2, 32, },
+ { 1, 0, 0, 2, 2, 32, },
+ { 0, 0, 0, 2, 3, 32, },
+ { 2, 0, 0, 2, 3, 32, },
+ { 1, 0, 0, 2, 3, 32, },
+ { 0, 0, 0, 2, 4, 32, },
+ { 2, 0, 0, 2, 4, 32, },
+ { 1, 0, 0, 2, 4, 32, },
+ { 0, 0, 0, 2, 5, 32, },
+ { 2, 0, 0, 2, 5, 32, },
+ { 1, 0, 0, 2, 5, 32, },
+ { 0, 0, 0, 2, 6, 32, },
+ { 2, 0, 0, 2, 6, 32, },
+ { 1, 0, 0, 2, 6, 32, },
+ { 0, 0, 0, 2, 7, 32, },
+ { 2, 0, 0, 2, 7, 32, },
+ { 1, 0, 0, 2, 7, 32, },
+ { 0, 0, 0, 2, 8, 32, },
+ { 2, 0, 0, 2, 8, 32, },
+ { 1, 0, 0, 2, 8, 32, },
+ { 0, 0, 0, 2, 9, 26, },
+ { 2, 0, 0, 2, 9, 32, },
+ { 1, 0, 0, 2, 9, 32, },
+ { 0, 0, 0, 2, 10, 26, },
+ { 2, 0, 0, 2, 10, 32, },
+ { 1, 0, 0, 2, 10, 32, },
+ { 0, 0, 0, 2, 11, 26, },
+ { 2, 0, 0, 2, 11, 32, },
+ { 1, 0, 0, 2, 11, 32, },
+ { 0, 0, 0, 2, 12, 26, },
+ { 2, 0, 0, 2, 12, 32, },
+ { 1, 0, 0, 2, 12, 32, },
+ { 0, 0, 0, 2, 13, 24, },
+ { 2, 0, 0, 2, 13, 26, },
+ { 1, 0, 0, 2, 13, 32, },
+ { 0, 0, 0, 2, 14, 63, },
+ { 2, 0, 0, 2, 14, 63, },
+ { 1, 0, 0, 2, 14, 63, },
+ { 0, 0, 0, 3, 1, 30, },
+ { 2, 0, 0, 3, 1, 32, },
+ { 1, 0, 0, 3, 1, 32, },
+ { 0, 0, 0, 3, 2, 32, },
+ { 2, 0, 0, 3, 2, 32, },
+ { 1, 0, 0, 3, 2, 32, },
+ { 0, 0, 0, 3, 3, 32, },
+ { 2, 0, 0, 3, 3, 32, },
+ { 1, 0, 0, 3, 3, 32, },
+ { 0, 0, 0, 3, 4, 32, },
+ { 2, 0, 0, 3, 4, 32, },
+ { 1, 0, 0, 3, 4, 32, },
+ { 0, 0, 0, 3, 5, 32, },
+ { 2, 0, 0, 3, 5, 32, },
+ { 1, 0, 0, 3, 5, 32, },
+ { 0, 0, 0, 3, 6, 32, },
+ { 2, 0, 0, 3, 6, 32, },
+ { 1, 0, 0, 3, 6, 32, },
+ { 0, 0, 0, 3, 7, 32, },
+ { 2, 0, 0, 3, 7, 32, },
+ { 1, 0, 0, 3, 7, 32, },
+ { 0, 0, 0, 3, 8, 32, },
+ { 2, 0, 0, 3, 8, 32, },
+ { 1, 0, 0, 3, 8, 32, },
+ { 0, 0, 0, 3, 9, 32, },
+ { 2, 0, 0, 3, 9, 32, },
+ { 1, 0, 0, 3, 9, 32, },
+ { 0, 0, 0, 3, 10, 32, },
+ { 2, 0, 0, 3, 10, 32, },
+ { 1, 0, 0, 3, 10, 32, },
+ { 0, 0, 0, 3, 11, 30, },
+ { 2, 0, 0, 3, 11, 32, },
+ { 1, 0, 0, 3, 11, 32, },
+ { 0, 0, 0, 3, 12, 63, },
+ { 2, 0, 0, 3, 12, 32, },
+ { 1, 0, 0, 3, 12, 32, },
+ { 0, 0, 0, 3, 13, 63, },
+ { 2, 0, 0, 3, 13, 32, },
+ { 1, 0, 0, 3, 13, 32, },
+ { 0, 0, 0, 3, 14, 63, },
+ { 2, 0, 0, 3, 14, 63, },
+ { 1, 0, 0, 3, 14, 63, },
+ { 0, 0, 1, 2, 1, 63, },
+ { 2, 0, 1, 2, 1, 63, },
+ { 1, 0, 1, 2, 1, 63, },
+ { 0, 0, 1, 2, 2, 63, },
+ { 2, 0, 1, 2, 2, 63, },
+ { 1, 0, 1, 2, 2, 63, },
+ { 0, 0, 1, 2, 3, 26, },
+ { 2, 0, 1, 2, 3, 26, },
+ { 1, 0, 1, 2, 3, 32, },
+ { 0, 0, 1, 2, 4, 26, },
+ { 2, 0, 1, 2, 4, 32, },
+ { 1, 0, 1, 2, 4, 32, },
+ { 0, 0, 1, 2, 5, 26, },
+ { 2, 0, 1, 2, 5, 32, },
+ { 1, 0, 1, 2, 5, 32, },
+ { 0, 0, 1, 2, 6, 32, },
+ { 2, 0, 1, 2, 6, 32, },
+ { 1, 0, 1, 2, 6, 32, },
+ { 0, 0, 1, 2, 7, 32, },
+ { 2, 0, 1, 2, 7, 32, },
+ { 1, 0, 1, 2, 7, 32, },
+ { 0, 0, 1, 2, 8, 32, },
+ { 2, 0, 1, 2, 8, 32, },
+ { 1, 0, 1, 2, 8, 32, },
+ { 0, 0, 1, 2, 9, 26, },
+ { 2, 0, 1, 2, 9, 32, },
+ { 1, 0, 1, 2, 9, 32, },
+ { 0, 0, 1, 2, 10, 24, },
+ { 2, 0, 1, 2, 10, 32, },
+ { 1, 0, 1, 2, 10, 32, },
+ { 0, 0, 1, 2, 11, 22, },
+ { 2, 0, 1, 2, 11, 26, },
+ { 1, 0, 1, 2, 11, 32, },
+ { 0, 0, 1, 2, 12, 63, },
+ { 2, 0, 1, 2, 12, 63, },
+ { 1, 0, 1, 2, 12, 63, },
+ { 0, 0, 1, 2, 13, 63, },
+ { 2, 0, 1, 2, 13, 63, },
+ { 1, 0, 1, 2, 13, 63, },
+ { 0, 0, 1, 2, 14, 63, },
+ { 2, 0, 1, 2, 14, 63, },
+ { 1, 0, 1, 2, 14, 63, },
+ { 0, 0, 1, 3, 1, 63, },
+ { 2, 0, 1, 3, 1, 63, },
+ { 1, 0, 1, 3, 1, 63, },
+ { 0, 0, 1, 3, 2, 63, },
+ { 2, 0, 1, 3, 2, 63, },
+ { 1, 0, 1, 3, 2, 63, },
+ { 0, 0, 1, 3, 3, 30, },
+ { 2, 0, 1, 3, 3, 30, },
+ { 1, 0, 1, 3, 3, 30, },
+ { 0, 0, 1, 3, 4, 32, },
+ { 2, 0, 1, 3, 4, 30, },
+ { 1, 0, 1, 3, 4, 30, },
+ { 0, 0, 1, 3, 5, 32, },
+ { 2, 0, 1, 3, 5, 30, },
+ { 1, 0, 1, 3, 5, 30, },
+ { 0, 0, 1, 3, 6, 32, },
+ { 2, 0, 1, 3, 6, 30, },
+ { 1, 0, 1, 3, 6, 30, },
+ { 0, 0, 1, 3, 7, 32, },
+ { 2, 0, 1, 3, 7, 30, },
+ { 1, 0, 1, 3, 7, 30, },
+ { 0, 0, 1, 3, 8, 32, },
+ { 2, 0, 1, 3, 8, 30, },
+ { 1, 0, 1, 3, 8, 30, },
+ { 0, 0, 1, 3, 9, 32, },
+ { 2, 0, 1, 3, 9, 30, },
+ { 1, 0, 1, 3, 9, 30, },
+ { 0, 0, 1, 3, 10, 32, },
+ { 2, 0, 1, 3, 10, 30, },
+ { 1, 0, 1, 3, 10, 30, },
+ { 0, 0, 1, 3, 11, 30, },
+ { 2, 0, 1, 3, 11, 30, },
+ { 1, 0, 1, 3, 11, 30, },
+ { 0, 0, 1, 3, 12, 63, },
+ { 2, 0, 1, 3, 12, 32, },
+ { 1, 0, 1, 3, 12, 32, },
+ { 0, 0, 1, 3, 13, 63, },
+ { 2, 0, 1, 3, 13, 32, },
+ { 1, 0, 1, 3, 13, 32, },
+ { 0, 0, 1, 3, 14, 63, },
+ { 2, 0, 1, 3, 14, 63, },
+ { 1, 0, 1, 3, 14, 63, },
+ { 0, 1, 0, 1, 36, 32, },
+ { 2, 1, 0, 1, 36, 30, },
+ { 1, 1, 0, 1, 36, 30, },
+ { 0, 1, 0, 1, 40, 32, },
+ { 2, 1, 0, 1, 40, 30, },
+ { 1, 1, 0, 1, 40, 30, },
+ { 0, 1, 0, 1, 44, 32, },
+ { 2, 1, 0, 1, 44, 30, },
+ { 1, 1, 0, 1, 44, 30, },
+ { 0, 1, 0, 1, 48, 32, },
+ { 2, 1, 0, 1, 48, 30, },
+ { 1, 1, 0, 1, 48, 30, },
+ { 0, 1, 0, 1, 52, 32, },
+ { 2, 1, 0, 1, 52, 30, },
+ { 1, 1, 0, 1, 52, 30, },
+ { 0, 1, 0, 1, 56, 32, },
+ { 2, 1, 0, 1, 56, 30, },
+ { 1, 1, 0, 1, 56, 30, },
+ { 0, 1, 0, 1, 60, 32, },
+ { 2, 1, 0, 1, 60, 30, },
+ { 1, 1, 0, 1, 60, 30, },
+ { 0, 1, 0, 1, 64, 32, },
+ { 2, 1, 0, 1, 64, 30, },
+ { 1, 1, 0, 1, 64, 30, },
+ { 0, 1, 0, 1, 100, 32, },
+ { 2, 1, 0, 1, 100, 30, },
+ { 1, 1, 0, 1, 100, 30, },
+ { 0, 1, 0, 1, 104, 32, },
+ { 2, 1, 0, 1, 104, 30, },
+ { 1, 1, 0, 1, 104, 30, },
+ { 0, 1, 0, 1, 108, 32, },
+ { 2, 1, 0, 1, 108, 30, },
+ { 1, 1, 0, 1, 108, 30, },
+ { 0, 1, 0, 1, 112, 32, },
+ { 2, 1, 0, 1, 112, 30, },
+ { 1, 1, 0, 1, 112, 30, },
+ { 0, 1, 0, 1, 116, 32, },
+ { 2, 1, 0, 1, 116, 30, },
+ { 1, 1, 0, 1, 116, 30, },
+ { 0, 1, 0, 1, 120, 32, },
+ { 2, 1, 0, 1, 120, 30, },
+ { 1, 1, 0, 1, 120, 30, },
+ { 0, 1, 0, 1, 124, 32, },
+ { 2, 1, 0, 1, 124, 30, },
+ { 1, 1, 0, 1, 124, 30, },
+ { 0, 1, 0, 1, 128, 32, },
+ { 2, 1, 0, 1, 128, 30, },
+ { 1, 1, 0, 1, 128, 30, },
+ { 0, 1, 0, 1, 132, 32, },
+ { 2, 1, 0, 1, 132, 30, },
+ { 1, 1, 0, 1, 132, 30, },
+ { 0, 1, 0, 1, 136, 32, },
+ { 2, 1, 0, 1, 136, 30, },
+ { 1, 1, 0, 1, 136, 30, },
+ { 0, 1, 0, 1, 140, 32, },
+ { 2, 1, 0, 1, 140, 30, },
+ { 1, 1, 0, 1, 140, 30, },
+ { 0, 1, 0, 1, 149, 32, },
+ { 2, 1, 0, 1, 149, 30, },
+ { 1, 1, 0, 1, 149, 63, },
+ { 0, 1, 0, 1, 153, 32, },
+ { 2, 1, 0, 1, 153, 30, },
+ { 1, 1, 0, 1, 153, 63, },
+ { 0, 1, 0, 1, 157, 32, },
+ { 2, 1, 0, 1, 157, 30, },
+ { 1, 1, 0, 1, 157, 63, },
+ { 0, 1, 0, 1, 161, 32, },
+ { 2, 1, 0, 1, 161, 30, },
+ { 1, 1, 0, 1, 161, 63, },
+ { 0, 1, 0, 1, 165, 32, },
+ { 2, 1, 0, 1, 165, 30, },
+ { 1, 1, 0, 1, 165, 63, },
+ { 0, 1, 0, 2, 36, 32, },
+ { 2, 1, 0, 2, 36, 30, },
+ { 1, 1, 0, 2, 36, 30, },
+ { 0, 1, 0, 2, 40, 32, },
+ { 2, 1, 0, 2, 40, 30, },
+ { 1, 1, 0, 2, 40, 30, },
+ { 0, 1, 0, 2, 44, 32, },
+ { 2, 1, 0, 2, 44, 30, },
+ { 1, 1, 0, 2, 44, 30, },
+ { 0, 1, 0, 2, 48, 32, },
+ { 2, 1, 0, 2, 48, 30, },
+ { 1, 1, 0, 2, 48, 30, },
+ { 0, 1, 0, 2, 52, 32, },
+ { 2, 1, 0, 2, 52, 30, },
+ { 1, 1, 0, 2, 52, 30, },
+ { 0, 1, 0, 2, 56, 32, },
+ { 2, 1, 0, 2, 56, 30, },
+ { 1, 1, 0, 2, 56, 30, },
+ { 0, 1, 0, 2, 60, 32, },
+ { 2, 1, 0, 2, 60, 30, },
+ { 1, 1, 0, 2, 60, 30, },
+ { 0, 1, 0, 2, 64, 32, },
+ { 2, 1, 0, 2, 64, 30, },
+ { 1, 1, 0, 2, 64, 30, },
+ { 0, 1, 0, 2, 100, 32, },
+ { 2, 1, 0, 2, 100, 30, },
+ { 1, 1, 0, 2, 100, 30, },
+ { 0, 1, 0, 2, 104, 32, },
+ { 2, 1, 0, 2, 104, 30, },
+ { 1, 1, 0, 2, 104, 30, },
+ { 0, 1, 0, 2, 108, 32, },
+ { 2, 1, 0, 2, 108, 30, },
+ { 1, 1, 0, 2, 108, 30, },
+ { 0, 1, 0, 2, 112, 32, },
+ { 2, 1, 0, 2, 112, 30, },
+ { 1, 1, 0, 2, 112, 30, },
+ { 0, 1, 0, 2, 116, 32, },
+ { 2, 1, 0, 2, 116, 30, },
+ { 1, 1, 0, 2, 116, 30, },
+ { 0, 1, 0, 2, 120, 32, },
+ { 2, 1, 0, 2, 120, 30, },
+ { 1, 1, 0, 2, 120, 30, },
+ { 0, 1, 0, 2, 124, 32, },
+ { 2, 1, 0, 2, 124, 30, },
+ { 1, 1, 0, 2, 124, 30, },
+ { 0, 1, 0, 2, 128, 32, },
+ { 2, 1, 0, 2, 128, 30, },
+ { 1, 1, 0, 2, 128, 30, },
+ { 0, 1, 0, 2, 132, 32, },
+ { 2, 1, 0, 2, 132, 30, },
+ { 1, 1, 0, 2, 132, 30, },
+ { 0, 1, 0, 2, 136, 32, },
+ { 2, 1, 0, 2, 136, 30, },
+ { 1, 1, 0, 2, 136, 30, },
+ { 0, 1, 0, 2, 140, 32, },
+ { 2, 1, 0, 2, 140, 30, },
+ { 1, 1, 0, 2, 140, 30, },
+ { 0, 1, 0, 2, 149, 32, },
+ { 2, 1, 0, 2, 149, 30, },
+ { 1, 1, 0, 2, 149, 63, },
+ { 0, 1, 0, 2, 153, 32, },
+ { 2, 1, 0, 2, 153, 30, },
+ { 1, 1, 0, 2, 153, 63, },
+ { 0, 1, 0, 2, 157, 32, },
+ { 2, 1, 0, 2, 157, 30, },
+ { 1, 1, 0, 2, 157, 63, },
+ { 0, 1, 0, 2, 161, 32, },
+ { 2, 1, 0, 2, 161, 30, },
+ { 1, 1, 0, 2, 161, 63, },
+ { 0, 1, 0, 2, 165, 32, },
+ { 2, 1, 0, 2, 165, 30, },
+ { 1, 1, 0, 2, 165, 63, },
+ { 0, 1, 0, 3, 36, 28, },
+ { 2, 1, 0, 3, 36, 30, },
+ { 1, 1, 0, 3, 36, 30, },
+ { 0, 1, 0, 3, 40, 28, },
+ { 2, 1, 0, 3, 40, 30, },
+ { 1, 1, 0, 3, 40, 30, },
+ { 0, 1, 0, 3, 44, 28, },
+ { 2, 1, 0, 3, 44, 30, },
+ { 1, 1, 0, 3, 44, 30, },
+ { 0, 1, 0, 3, 48, 28, },
+ { 2, 1, 0, 3, 48, 30, },
+ { 1, 1, 0, 3, 48, 30, },
+ { 0, 1, 0, 3, 52, 34, },
+ { 2, 1, 0, 3, 52, 30, },
+ { 1, 1, 0, 3, 52, 30, },
+ { 0, 1, 0, 3, 56, 32, },
+ { 2, 1, 0, 3, 56, 30, },
+ { 1, 1, 0, 3, 56, 30, },
+ { 0, 1, 0, 3, 60, 30, },
+ { 2, 1, 0, 3, 60, 30, },
+ { 1, 1, 0, 3, 60, 30, },
+ { 0, 1, 0, 3, 64, 26, },
+ { 2, 1, 0, 3, 64, 30, },
+ { 1, 1, 0, 3, 64, 30, },
+ { 0, 1, 0, 3, 100, 28, },
+ { 2, 1, 0, 3, 100, 30, },
+ { 1, 1, 0, 3, 100, 30, },
+ { 0, 1, 0, 3, 104, 28, },
+ { 2, 1, 0, 3, 104, 30, },
+ { 1, 1, 0, 3, 104, 30, },
+ { 0, 1, 0, 3, 108, 30, },
+ { 2, 1, 0, 3, 108, 30, },
+ { 1, 1, 0, 3, 108, 30, },
+ { 0, 1, 0, 3, 112, 32, },
+ { 2, 1, 0, 3, 112, 30, },
+ { 1, 1, 0, 3, 112, 30, },
+ { 0, 1, 0, 3, 116, 32, },
+ { 2, 1, 0, 3, 116, 30, },
+ { 1, 1, 0, 3, 116, 30, },
+ { 0, 1, 0, 3, 120, 34, },
+ { 2, 1, 0, 3, 120, 30, },
+ { 1, 1, 0, 3, 120, 30, },
+ { 0, 1, 0, 3, 124, 32, },
+ { 2, 1, 0, 3, 124, 30, },
+ { 1, 1, 0, 3, 124, 30, },
+ { 0, 1, 0, 3, 128, 30, },
+ { 2, 1, 0, 3, 128, 30, },
+ { 1, 1, 0, 3, 128, 30, },
+ { 0, 1, 0, 3, 132, 28, },
+ { 2, 1, 0, 3, 132, 30, },
+ { 1, 1, 0, 3, 132, 30, },
+ { 0, 1, 0, 3, 136, 28, },
+ { 2, 1, 0, 3, 136, 30, },
+ { 1, 1, 0, 3, 136, 30, },
+ { 0, 1, 0, 3, 140, 26, },
+ { 2, 1, 0, 3, 140, 30, },
+ { 1, 1, 0, 3, 140, 30, },
+ { 0, 1, 0, 3, 149, 34, },
+ { 2, 1, 0, 3, 149, 30, },
+ { 1, 1, 0, 3, 149, 63, },
+ { 0, 1, 0, 3, 153, 34, },
+ { 2, 1, 0, 3, 153, 30, },
+ { 1, 1, 0, 3, 153, 63, },
+ { 0, 1, 0, 3, 157, 34, },
+ { 2, 1, 0, 3, 157, 30, },
+ { 1, 1, 0, 3, 157, 63, },
+ { 0, 1, 0, 3, 161, 34, },
+ { 2, 1, 0, 3, 161, 30, },
+ { 1, 1, 0, 3, 161, 63, },
+ { 0, 1, 0, 3, 165, 34, },
+ { 2, 1, 0, 3, 165, 30, },
+ { 1, 1, 0, 3, 165, 63, },
+ { 0, 1, 1, 2, 38, 26, },
+ { 2, 1, 1, 2, 38, 30, },
+ { 1, 1, 1, 2, 38, 30, },
+ { 0, 1, 1, 2, 46, 32, },
+ { 2, 1, 1, 2, 46, 30, },
+ { 1, 1, 1, 2, 46, 30, },
+ { 0, 1, 1, 2, 54, 32, },
+ { 2, 1, 1, 2, 54, 30, },
+ { 1, 1, 1, 2, 54, 30, },
+ { 0, 1, 1, 2, 62, 24, },
+ { 2, 1, 1, 2, 62, 30, },
+ { 1, 1, 1, 2, 62, 30, },
+ { 0, 1, 1, 2, 102, 24, },
+ { 2, 1, 1, 2, 102, 30, },
+ { 1, 1, 1, 2, 102, 30, },
+ { 0, 1, 1, 2, 110, 32, },
+ { 2, 1, 1, 2, 110, 30, },
+ { 1, 1, 1, 2, 110, 30, },
+ { 0, 1, 1, 2, 118, 32, },
+ { 2, 1, 1, 2, 118, 30, },
+ { 1, 1, 1, 2, 118, 30, },
+ { 0, 1, 1, 2, 126, 32, },
+ { 2, 1, 1, 2, 126, 30, },
+ { 1, 1, 1, 2, 126, 30, },
+ { 0, 1, 1, 2, 134, 32, },
+ { 2, 1, 1, 2, 134, 30, },
+ { 1, 1, 1, 2, 134, 30, },
+ { 0, 1, 1, 2, 151, 30, },
+ { 2, 1, 1, 2, 151, 30, },
+ { 1, 1, 1, 2, 151, 63, },
+ { 0, 1, 1, 2, 159, 32, },
+ { 2, 1, 1, 2, 159, 30, },
+ { 1, 1, 1, 2, 159, 63, },
+ { 0, 1, 1, 3, 38, 28, },
+ { 2, 1, 1, 3, 38, 30, },
+ { 1, 1, 1, 3, 38, 30, },
+ { 0, 1, 1, 3, 46, 28, },
+ { 2, 1, 1, 3, 46, 30, },
+ { 1, 1, 1, 3, 46, 30, },
+ { 0, 1, 1, 3, 54, 30, },
+ { 2, 1, 1, 3, 54, 30, },
+ { 1, 1, 1, 3, 54, 30, },
+ { 0, 1, 1, 3, 62, 30, },
+ { 2, 1, 1, 3, 62, 30, },
+ { 1, 1, 1, 3, 62, 30, },
+ { 0, 1, 1, 3, 102, 26, },
+ { 2, 1, 1, 3, 102, 30, },
+ { 1, 1, 1, 3, 102, 30, },
+ { 0, 1, 1, 3, 110, 30, },
+ { 2, 1, 1, 3, 110, 30, },
+ { 1, 1, 1, 3, 110, 30, },
+ { 0, 1, 1, 3, 118, 34, },
+ { 2, 1, 1, 3, 118, 30, },
+ { 1, 1, 1, 3, 118, 30, },
+ { 0, 1, 1, 3, 126, 32, },
+ { 2, 1, 1, 3, 126, 30, },
+ { 1, 1, 1, 3, 126, 30, },
+ { 0, 1, 1, 3, 134, 30, },
+ { 2, 1, 1, 3, 134, 30, },
+ { 1, 1, 1, 3, 134, 30, },
+ { 0, 1, 1, 3, 151, 34, },
+ { 2, 1, 1, 3, 151, 30, },
+ { 1, 1, 1, 3, 151, 63, },
+ { 0, 1, 1, 3, 159, 34, },
+ { 2, 1, 1, 3, 159, 30, },
+ { 1, 1, 1, 3, 159, 63, },
+ { 0, 1, 2, 4, 42, 22, },
+ { 2, 1, 2, 4, 42, 30, },
+ { 1, 1, 2, 4, 42, 30, },
+ { 0, 1, 2, 4, 58, 20, },
+ { 2, 1, 2, 4, 58, 30, },
+ { 1, 1, 2, 4, 58, 30, },
+ { 0, 1, 2, 4, 106, 20, },
+ { 2, 1, 2, 4, 106, 30, },
+ { 1, 1, 2, 4, 106, 30, },
+ { 0, 1, 2, 4, 122, 20, },
+ { 2, 1, 2, 4, 122, 30, },
+ { 1, 1, 2, 4, 122, 30, },
+ { 0, 1, 2, 4, 155, 28, },
+ { 2, 1, 2, 4, 155, 30, },
+ { 1, 1, 2, 4, 155, 63, },
+ { 0, 1, 2, 5, 42, 28, },
+ { 2, 1, 2, 5, 42, 30, },
+ { 1, 1, 2, 5, 42, 30, },
+ { 0, 1, 2, 5, 58, 26, },
+ { 2, 1, 2, 5, 58, 30, },
+ { 1, 1, 2, 5, 58, 30, },
+ { 0, 1, 2, 5, 106, 28, },
+ { 2, 1, 2, 5, 106, 30, },
+ { 1, 1, 2, 5, 106, 30, },
+ { 0, 1, 2, 5, 122, 32, },
+ { 2, 1, 2, 5, 122, 30, },
+ { 1, 1, 2, 5, 122, 30, },
+ { 0, 1, 2, 5, 155, 34, },
+ { 2, 1, 2, 5, 155, 30, },
+ { 1, 1, 2, 5, 155, 63, },
+};
+
+RTW_DECL_TABLE_TXPWR_LMT(rtw8821a_txpwr_lmt);
+
+static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821a[] = {
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3) | BIT(7), 0},
+ {0x0086,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_SDIO,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0086,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_SDIO,
+ RTW_PWR_CMD_POLLING, BIT(1), BIT(1)},
+ {0x004A,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
+ {0x0023,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(4), 0},
+ {0x0301,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821a[] = {
+ {0x0020,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0067,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(4), 0},
+ {0x0001,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_DELAY, 1, RTW_PWR_DELAY_MS},
+ {0x0000,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(5), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(4) | BIT(3) | BIT(2), 0},
+ {0x0075,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0006,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(1), BIT(1)},
+ {0x0075,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0006,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(7), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(4) | BIT(3), 0},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(0), 0},
+ {0x004F,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0067,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(5) | BIT(4), BIT(5) | BIT(4)},
+ {0x0025,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(6), 0},
+ {0x0049,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x0063,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x0062,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0058,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x005A,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x002E,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x82},
+ {0x0010,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(6), BIT(6)},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_act_to_lps_8821a[] = {
+ {0x0301,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0xFF},
+ {0x0522,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0xFF},
+ {0x05F8,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05F9,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05FA,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x05FB,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, 0xFF, 0},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US},
+ {0x0002,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0100,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x03},
+ {0x0101,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0093,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x00},
+ {0x0553,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(5), BIT(5)},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821a[] = {
+ {0x001F,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0},
+ {0x004F,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0x0049,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), 0},
+ {0x0006,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(1), BIT(1)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_POLLING, BIT(1), 0},
+ {0x0000,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(5), BIT(5)},
+ {0x0020,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 0},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821a[] = {
+ {0x0007,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, 0xFF, 0x20},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},
+ {0x0005,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_PCI_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(2), BIT(2)},
+ {0x004A,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_USB_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(0), 1},
+ {0x0023,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_MAC,
+ RTW_PWR_CMD_WRITE, BIT(4), BIT(4)},
+ {0x0086,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_SDIO,
+ RTW_PWR_CMD_WRITE, BIT(0), BIT(0)},
+ {0x0086,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_SDIO_MSK,
+ RTW_PWR_ADDR_SDIO,
+ RTW_PWR_CMD_POLLING, BIT(1), 0},
+ {0xFFFF,
+ RTW_PWR_CUT_ALL_MSK,
+ RTW_PWR_INTF_ALL_MSK,
+ 0,
+ RTW_PWR_CMD_END, 0, 0},
+};
+
+const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[] = {
+ trans_carddis_to_cardemu_8821a,
+ trans_cardemu_to_act_8821a,
+ NULL
+};
+
+const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[] = {
+ trans_act_to_lps_8821a,
+ NULL
+};
+
+const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[] = {
+ trans_act_to_cardemu_8821a,
+ trans_cardemu_to_carddis_8821a,
+ NULL
+};
+
+static const u8 rtw8821a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static const u8 rtw8821a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static const u8 rtw8821a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static const u8 rtw8821a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = {
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+ {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15,
+ 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static const u8 rtw8821a_pwrtrk_2gb_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10
+};
+
+static const u8 rtw8821a_pwrtrk_2gb_p[] = {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12
+};
+
+static const u8 rtw8821a_pwrtrk_2ga_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10
+};
+
+static const u8 rtw8821a_pwrtrk_2ga_p[] = {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12
+};
+
+static const u8 rtw8821a_pwrtrk_2g_cck_b_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10
+};
+
+static const u8 rtw8821a_pwrtrk_2g_cck_b_p[] = {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12
+};
+
+static const u8 rtw8821a_pwrtrk_2g_cck_a_n[] = {
+ 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10
+};
+
+static const u8 rtw8821a_pwrtrk_2g_cck_a_p[] = {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12
+};
+
+const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl = {
+ .pwrtrk_5gb_n[0] = rtw8821a_pwrtrk_5gb_n[0],
+ .pwrtrk_5gb_n[1] = rtw8821a_pwrtrk_5gb_n[1],
+ .pwrtrk_5gb_n[2] = rtw8821a_pwrtrk_5gb_n[2],
+ .pwrtrk_5gb_p[0] = rtw8821a_pwrtrk_5gb_p[0],
+ .pwrtrk_5gb_p[1] = rtw8821a_pwrtrk_5gb_p[1],
+ .pwrtrk_5gb_p[2] = rtw8821a_pwrtrk_5gb_p[2],
+ .pwrtrk_5ga_n[0] = rtw8821a_pwrtrk_5ga_n[0],
+ .pwrtrk_5ga_n[1] = rtw8821a_pwrtrk_5ga_n[1],
+ .pwrtrk_5ga_n[2] = rtw8821a_pwrtrk_5ga_n[2],
+ .pwrtrk_5ga_p[0] = rtw8821a_pwrtrk_5ga_p[0],
+ .pwrtrk_5ga_p[1] = rtw8821a_pwrtrk_5ga_p[1],
+ .pwrtrk_5ga_p[2] = rtw8821a_pwrtrk_5ga_p[2],
+ .pwrtrk_2gb_n = rtw8821a_pwrtrk_2gb_n,
+ .pwrtrk_2gb_p = rtw8821a_pwrtrk_2gb_p,
+ .pwrtrk_2ga_n = rtw8821a_pwrtrk_2ga_n,
+ .pwrtrk_2ga_p = rtw8821a_pwrtrk_2ga_p,
+ .pwrtrk_2g_cckb_n = rtw8821a_pwrtrk_2g_cck_b_n,
+ .pwrtrk_2g_cckb_p = rtw8821a_pwrtrk_2g_cck_b_p,
+ .pwrtrk_2g_ccka_n = rtw8821a_pwrtrk_2g_cck_a_n,
+ .pwrtrk_2g_ccka_p = rtw8821a_pwrtrk_2g_cck_a_p,
+};
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h
new file mode 100644
index 000000000000..90379ac7a817
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#ifndef __RTW8821A_TABLE_H__
+#define __RTW8821A_TABLE_H__
+
+extern const struct rtw_table rtw8821a_mac_tbl;
+extern const struct rtw_table rtw8821a_agc_tbl;
+extern const struct rtw_table rtw8821a_bb_tbl;
+extern const struct rtw_table rtw8821a_bb_pg_tbl;
+extern const struct rtw_table rtw8821a_rf_a_tbl;
+extern const struct rtw_table rtw8821a_txpwr_lmt_tbl;
+
+extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[];
+extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[];
+extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[];
+
+extern const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821au.c b/drivers/net/wireless/realtek/rtw88/rtw8821au.c
new file mode 100644
index 000000000000..730018773e1c
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821au.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "main.h"
+#include "rtw8821a.h"
+#include "usb.h"
+
+static const struct usb_device_id rtw_8821au_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x011e, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, rtw_8821au_id_table);
+
+static struct usb_driver rtw_8821au_driver = {
+ .name = "rtw_8821au",
+ .id_table = rtw_8821au_id_table,
+ .probe = rtw_usb_probe,
+ .disconnect = rtw_usb_disconnect,
+};
+module_usb_driver(rtw_8821au_driver);
+
+MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821au/8811au driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index 526e8de77b3e..0270225b9c20 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -679,47 +679,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
}
}
-static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
- u8 *phy_status = NULL;
-
- memset(pkt_stat, 0, sizeof(*pkt_stat));
-
- pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
- pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
- pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
- GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
- pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
- pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
- pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
- pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
- pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
- pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
- pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
- pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
-
- /* drv_info_sz is in unit of 8-bytes */
- pkt_stat->drv_info_sz *= 8;
-
- /* c2h cmd pkt's rx/phy status is not interested */
- if (pkt_stat->is_c2h)
- return;
-
- hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
- pkt_stat->drv_info_sz);
- if (pkt_stat->phy_status) {
- phy_status = rx_desc + desc_sz + pkt_stat->shift;
- query_phy_status(rtwdev, phy_status, pkt_stat);
- }
-
- rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
-}
-
static void
rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
{
@@ -1254,7 +1213,7 @@ static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev,
fill_txdesc_checksum_common(txdesc, 16);
}
-static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
+static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
{0x0086,
RTW_PWR_CUT_ALL_MSK,
RTW_PWR_INTF_SDIO_MSK,
@@ -1292,7 +1251,7 @@ static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = {
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = {
{0x0020,
RTW_PWR_CUT_ALL_MSK,
RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
@@ -1396,7 +1355,7 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = {
+static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = {
{0x0093,
RTW_PWR_CUT_ALL_MSK,
RTW_PWR_INTF_ALL_MSK,
@@ -1454,7 +1413,7 @@ static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = {
+static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = {
{0x0007,
RTW_PWR_CUT_ALL_MSK,
RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK,
@@ -1567,13 +1526,13 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static const struct rtw_pwr_seq_cmd *card_enable_flow_8821c[] = {
+static const struct rtw_pwr_seq_cmd * const card_enable_flow_8821c[] = {
trans_carddis_to_cardemu_8821c,
trans_cardemu_to_act_8821c,
NULL
};
-static const struct rtw_pwr_seq_cmd *card_disable_flow_8821c[] = {
+static const struct rtw_pwr_seq_cmd * const card_disable_flow_8821c[] = {
trans_act_to_cardemu_8821c,
trans_cardemu_to_carddis_8821c,
NULL
@@ -1622,14 +1581,7 @@ static const struct rtw_intf_phy_para_table phy_para_table_8821c = {
.n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8821c),
};
-static const struct rtw_rfe_def rtw8821c_rfe_defs[] = {
- [0] = RTW_DEF_RFE(8821c, 0, 0),
- [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
- [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
- [6] = RTW_DEF_RFE(8821c, 0, 0),
-};
-
-static struct rtw_hw_reg rtw8821c_dig[] = {
+static const struct rtw_hw_reg rtw8821c_dig[] = {
[0] = { .addr = 0xc50, .mask = 0x7f },
};
@@ -1639,7 +1591,7 @@ static const struct rtw_ltecoex_addr rtw8821c_ltecoex_addr = {
.rdata = LTECOEX_READ_DATA,
};
-static struct rtw_page_table page_table_8821c[] = {
+static const struct rtw_page_table page_table_8821c[] = {
/* not sure what [0] stands for */
{16, 16, 16, 14, 1},
{16, 16, 16, 14, 1},
@@ -1648,7 +1600,7 @@ static struct rtw_page_table page_table_8821c[] = {
{16, 16, 16, 14, 1},
};
-static struct rtw_rqpn rqpn_table_8821c[] = {
+static const struct rtw_rqpn rqpn_table_8821c[] = {
/* not sure what [0] stands for */
{RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL,
RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW,
@@ -1667,7 +1619,7 @@ static struct rtw_rqpn rqpn_table_8821c[] = {
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
};
-static struct rtw_prioq_addrs prioq_addrs_8821c = {
+static const struct rtw_prioq_addrs prioq_addrs_8821c = {
.prio[RTW_DMA_MAPPING_EXTRA] = {
.rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2,
},
@@ -1683,10 +1635,12 @@ static struct rtw_prioq_addrs prioq_addrs_8821c = {
.wsize = true,
};
-static struct rtw_chip_ops rtw8821c_ops = {
+static const struct rtw_chip_ops rtw8821c_ops = {
+ .power_on = rtw_power_on,
+ .power_off = rtw_power_off,
.phy_set_param = rtw8821c_phy_set_param,
.read_efuse = rtw8821c_read_efuse,
- .query_rx_desc = rtw8821c_query_rx_desc,
+ .query_phy_status = query_phy_status,
.set_channel = rtw8821c_set_channel,
.mac_init = rtw8821c_mac_init,
.read_rf = rtw_phy_read_rf,
@@ -1938,7 +1892,7 @@ static const u8 rtw8821c_pwrtrk_2g_cck_a_p[] = {
5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9
};
-static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = {
+static const struct rtw_pwr_track_tbl rtw8821c_pwr_track_type0_tbl = {
.pwrtrk_5gb_n[0] = rtw8821c_pwrtrk_5gb_n[0],
.pwrtrk_5gb_n[1] = rtw8821c_pwrtrk_5gb_n[1],
.pwrtrk_5gb_n[2] = rtw8821c_pwrtrk_5gb_n[2],
@@ -1961,6 +1915,13 @@ static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = {
.pwrtrk_2g_ccka_p = rtw8821c_pwrtrk_2g_cck_a_p,
};
+static const struct rtw_rfe_def rtw8821c_rfe_defs[] = {
+ [0] = RTW_DEF_RFE(8821c, 0, 0, 0),
+ [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2),
+ [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2),
+ [6] = RTW_DEF_RFE(8821c, 0, 0, 0),
+};
+
static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = {
{0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32},
@@ -2009,6 +1970,9 @@ const struct rtw_chip_info rtw8821c_hw_spec = {
.page_size = TX_PAGE_SIZE,
.dig_min = 0x1c,
.usb_tx_agg_desc_num = 3,
+ .hw_feature_report = true,
+ .c2h_ra_report_size = 7,
+ .old_datarate_fb_limit = false,
.ht_supported = true,
.vht_supported = true,
.lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK),
@@ -2030,7 +1994,6 @@ const struct rtw_chip_info rtw8821c_hw_spec = {
.rfe_defs = rtw8821c_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8821c_rfe_defs),
.rx_ldpc = false,
- .pwr_track_tbl = &rtw8821c_rtw_pwr_track_tbl,
.iqk_threshold = 8,
.bfer_su_max_num = 2,
.bfer_mu_max_num = 1,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
index 91ed921407bb..7a33ebd612ed 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h
@@ -214,19 +214,10 @@ extern const struct rtw_chip_info rtw8821c_hw_spec;
#define BIT_FEN_EN BIT(26)
#define REG_INIRTS_RATE_SEL 0x0480
#define REG_HTSTFWT 0x800
-#define REG_RXPSEL 0x808
-#define BIT_RX_PSEL_RST (BIT(28) | BIT(29))
-#define REG_TXPSEL 0x80c
#define REG_RXCCAMSK 0x814
-#define REG_CCASEL 0x82c
-#define REG_PDMFTH 0x830
-#define REG_CCA2ND 0x838
#define REG_L1WT 0x83c
#define REG_L1PKWT 0x840
#define REG_MRC 0x850
-#define REG_CLKTRK 0x860
-#define REG_ADCCLK 0x8ac
-#define REG_ADC160 0x8c4
#define REG_ADC40 0x8c8
#define REG_CHFIR 0x8f0
#define REG_CDDTXP 0x93c
@@ -234,14 +225,11 @@ extern const struct rtw_chip_info rtw8821c_hw_spec;
#define REG_ACBB0 0x948
#define REG_ACBBRXFIR 0x94c
#define REG_ACGG2TBL 0x958
-#define REG_FAS 0x9a4
-#define REG_RXSB 0xa00
#define REG_ADCINI 0xa04
#define REG_PWRTH 0xa08
#define REG_CCA_FLTR 0xa20
#define REG_TXSF2 0xa24
#define REG_TXSF6 0xa28
-#define REG_FA_CCK 0xa5c
#define REG_RXDESC 0xa2c
#define REG_ENTXCCK 0xa80
#define BTG_LNA 0xfc84
@@ -252,12 +240,8 @@ extern const struct rtw_chip_info rtw8821c_hw_spec;
#define REG_PWRTH2 0xaa8
#define REG_CSRATIO 0xaaa
#define REG_TXFILTER 0xaac
-#define REG_CNTRST 0xb58
#define REG_AGCTR_A 0xc08
-#define REG_TXSCALE_A 0xc1c
#define REG_TXDFIR 0xc20
-#define REG_RXIGI_A 0xc50
-#define REG_TXAGCIDX 0xc94
#define REG_TRSW 0xca0
#define REG_RFESEL0 0xcb0
#define REG_RFESEL8 0xcb4
@@ -269,14 +253,6 @@ extern const struct rtw_chip_info rtw8821c_hw_spec;
#define B_WLA_SWITCH BIT(23)
#define REG_RFEINV 0xcbc
#define REG_AGCTR_B 0xe08
-#define REG_RXIGI_B 0xe50
-#define REG_CRC_CCK 0xf04
-#define REG_CRC_OFDM 0xf14
-#define REG_CRC_HT 0xf10
-#define REG_CRC_VHT 0xf0c
-#define REG_CCA_OFDM 0xf08
-#define REG_FA_OFDM 0xf48
-#define REG_CCA_CCK 0xfcc
#define REG_DMEM_CTRL 0x1080
#define BIT_WL_RST BIT(16)
#define REG_ANTWT 0x1904
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index 6edb17aea90e..739809f4cab5 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -934,47 +934,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
}
}
-static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
- u8 *phy_status = NULL;
-
- memset(pkt_stat, 0, sizeof(*pkt_stat));
-
- pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
- pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
- pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
- GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
- pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
- pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
- pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
- pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
- pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
- pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
- pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
- pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
-
- /* drv_info_sz is in unit of 8-bytes */
- pkt_stat->drv_info_sz *= 8;
-
- /* c2h cmd pkt's rx/phy status is not interested */
- if (pkt_stat->is_c2h)
- return;
-
- hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
- pkt_stat->drv_info_sz);
- if (pkt_stat->phy_status) {
- phy_status = rx_desc + desc_sz + pkt_stat->shift;
- query_phy_status(rtwdev, phy_status, pkt_stat);
- }
-
- rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
-}
-
static void
rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs)
{
@@ -1978,13 +1937,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static const struct rtw_pwr_seq_cmd *card_enable_flow_8822b[] = {
+static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822b[] = {
trans_carddis_to_cardemu_8822b,
trans_cardemu_to_act_8822b,
NULL
};
-static const struct rtw_pwr_seq_cmd *card_disable_flow_8822b[] = {
+static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822b[] = {
trans_act_to_cardemu_8822b,
trans_cardemu_to_carddis_8822b,
NULL
@@ -2113,12 +2072,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822b = {
.n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822b),
};
-static const struct rtw_rfe_def rtw8822b_rfe_defs[] = {
- [2] = RTW_DEF_RFE(8822b, 2, 2),
- [3] = RTW_DEF_RFE(8822b, 3, 0),
- [5] = RTW_DEF_RFE(8822b, 5, 5),
-};
-
static const struct rtw_hw_reg rtw8822b_dig[] = {
[0] = { .addr = 0xc50, .mask = 0x7f },
[1] = { .addr = 0xe50, .mask = 0x7f },
@@ -2156,7 +2109,7 @@ static const struct rtw_rqpn rqpn_table_8822b[] = {
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
};
-static struct rtw_prioq_addrs prioq_addrs_8822b = {
+static const struct rtw_prioq_addrs prioq_addrs_8822b = {
.prio[RTW_DMA_MAPPING_EXTRA] = {
.rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2,
},
@@ -2172,10 +2125,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822b = {
.wsize = true,
};
-static struct rtw_chip_ops rtw8822b_ops = {
+static const struct rtw_chip_ops rtw8822b_ops = {
+ .power_on = rtw_power_on,
+ .power_off = rtw_power_off,
.phy_set_param = rtw8822b_phy_set_param,
.read_efuse = rtw8822b_read_efuse,
- .query_rx_desc = rtw8822b_query_rx_desc,
+ .query_phy_status = query_phy_status,
.set_channel = rtw8822b_set_channel,
.mac_init = rtw8822b_mac_init,
.read_rf = rtw_phy_read_rf,
@@ -2471,7 +2426,7 @@ static const u8 rtw8822b_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = {
10, 11, 11, 12, 12, 13, 13, 14, 14, 15
};
-static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = {
+static const struct rtw_pwr_track_tbl rtw8822b_pwr_track_type0_tbl = {
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1],
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2],
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3],
@@ -2494,6 +2449,12 @@ static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = {
.pwrtrk_2g_ccka_p = rtw8822b_pwrtrk_2g_cck_a_p,
};
+static const struct rtw_rfe_def rtw8822b_rfe_defs[] = {
+ [2] = RTW_DEF_RFE(8822b, 2, 2, 0),
+ [3] = RTW_DEF_RFE(8822b, 3, 0, 0),
+ [5] = RTW_DEF_RFE(8822b, 5, 5, 0),
+};
+
static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = {
{0xcb0, MASKDWORD, RTW_REG_DOMAIN_MAC32},
{0xcb4, MASKDWORD, RTW_REG_DOMAIN_MAC32},
@@ -2521,7 +2482,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = {
{0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
};
-static struct rtw_hw_reg_offset rtw8822b_edcca_th[] = {
+static const struct rtw_hw_reg_offset rtw8822b_edcca_th[] = {
[EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0},
[EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
};
@@ -2550,6 +2511,9 @@ const struct rtw_chip_info rtw8822b_hw_spec = {
.page_size = TX_PAGE_SIZE,
.dig_min = 0x1c,
.usb_tx_agg_desc_num = 3,
+ .hw_feature_report = true,
+ .c2h_ra_report_size = 7,
+ .old_datarate_fb_limit = false,
.ht_supported = true,
.vht_supported = true,
.lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK),
@@ -2571,7 +2535,6 @@ const struct rtw_chip_info rtw8822b_hw_spec = {
.rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl},
.rfe_defs = rtw8822b_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs),
- .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl,
.iqk_threshold = 8,
.bfer_su_max_num = 2,
.bfer_mu_max_num = 1,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
index cf85e63966a1..0514958fb57c 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h
@@ -151,21 +151,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
#define RTW8822B_EDCCA_MAX 0x7f
#define RTW8822B_EDCCA_SRC_DEF 1
#define REG_HTSTFWT 0x800
-#define REG_RXPSEL 0x808
-#define BIT_RX_PSEL_RST (BIT(28) | BIT(29))
-#define REG_TXPSEL 0x80c
#define REG_RXCCAMSK 0x814
-#define REG_CCASEL 0x82c
-#define REG_PDMFTH 0x830
-#define REG_CCA2ND 0x838
#define REG_L1WT 0x83c
#define REG_L1PKWT 0x840
#define REG_MRC 0x850
-#define REG_CLKTRK 0x860
#define REG_EDCCA_POW_MA 0x8a0
#define BIT_MA_LEVEL GENMASK(1, 0)
-#define REG_ADCCLK 0x8ac
-#define REG_ADC160 0x8c4
#define REG_ADC40 0x8c8
#define REG_EDCCA_DECISION 0x8dc
#define BIT_EDCCA_OPTION BIT(5)
@@ -176,7 +167,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
#define REG_ACBB0 0x948
#define REG_ACBBRXFIR 0x94c
#define REG_ACGG2TBL 0x958
-#define REG_RXSB 0xa00
#define REG_ADCINI 0xa04
#define REG_TXSF2 0xa24
#define REG_TXSF6 0xa28
@@ -184,14 +174,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
#define REG_ENTXCCK 0xa80
#define REG_AGCTR_A 0xc08
#define REG_TXDFIR 0xc20
-#define REG_RXIGI_A 0xc50
#define REG_TRSW 0xca0
#define REG_RFESEL0 0xcb0
#define REG_RFESEL8 0xcb4
#define REG_RFECTL 0xcb8
#define REG_RFEINV 0xcbc
#define REG_AGCTR_B 0xe08
-#define REG_RXIGI_B 0xe50
#define REG_ANTWT 0x1904
#define REG_IQKFAILMSK 0x1bf0
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 1dbe1cdbc3fd..af6b76937f1d 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -2690,48 +2690,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
}
}
-static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_rx_status *rx_status)
-{
- struct ieee80211_hdr *hdr;
- u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
- u8 *phy_status = NULL;
-
- memset(pkt_stat, 0, sizeof(*pkt_stat));
-
- pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
- pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
- pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
- GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
- pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
- pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
- pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
- pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc);
- pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc);
- pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc);
- pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc);
- pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc);
-
- /* drv_info_sz is in unit of 8-bytes */
- pkt_stat->drv_info_sz *= 8;
-
- /* c2h cmd pkt's rx/phy status is not interested */
- if (pkt_stat->is_c2h)
- return;
-
- hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
- pkt_stat->drv_info_sz);
- pkt_stat->hdr = hdr;
- if (pkt_stat->phy_status) {
- phy_status = rx_desc + desc_sz + pkt_stat->shift;
- query_phy_status(rtwdev, phy_status, pkt_stat);
- }
-
- rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status);
-}
-
static void
rtw8822c_set_write_tx_power_ref(struct rtw_dev *rtwdev, u8 *tx_pwr_ref_cck,
u8 *tx_pwr_ref_ofdm)
@@ -4874,13 +4832,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822c[] = {
RTW_PWR_CMD_END, 0, 0},
};
-static const struct rtw_pwr_seq_cmd *card_enable_flow_8822c[] = {
+static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822c[] = {
trans_carddis_to_cardemu_8822c,
trans_cardemu_to_act_8822c,
NULL
};
-static const struct rtw_pwr_seq_cmd *card_disable_flow_8822c[] = {
+static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822c[] = {
trans_act_to_cardemu_8822c,
trans_cardemu_to_carddis_8822c,
NULL
@@ -4925,16 +4883,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822c = {
.n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822c),
};
-static const struct rtw_rfe_def rtw8822c_rfe_defs[] = {
- [0] = RTW_DEF_RFE(8822c, 0, 0),
- [1] = RTW_DEF_RFE(8822c, 0, 0),
- [2] = RTW_DEF_RFE(8822c, 0, 0),
- [3] = RTW_DEF_RFE(8822c, 0, 0),
- [4] = RTW_DEF_RFE(8822c, 0, 0),
- [5] = RTW_DEF_RFE(8822c, 0, 5),
- [6] = RTW_DEF_RFE(8822c, 0, 0),
-};
-
static const struct rtw_hw_reg rtw8822c_dig[] = {
[0] = { .addr = 0x1d70, .mask = 0x7f },
[1] = { .addr = 0x1d70, .mask = 0x7f00 },
@@ -4972,7 +4920,7 @@ static const struct rtw_rqpn rqpn_table_8822c[] = {
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
};
-static struct rtw_prioq_addrs prioq_addrs_8822c = {
+static const struct rtw_prioq_addrs prioq_addrs_8822c = {
.prio[RTW_DMA_MAPPING_EXTRA] = {
.rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2,
},
@@ -4988,10 +4936,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822c = {
.wsize = true,
};
-static struct rtw_chip_ops rtw8822c_ops = {
+static const struct rtw_chip_ops rtw8822c_ops = {
+ .power_on = rtw_power_on,
+ .power_off = rtw_power_off,
.phy_set_param = rtw8822c_phy_set_param,
.read_efuse = rtw8822c_read_efuse,
- .query_rx_desc = rtw8822c_query_rx_desc,
+ .query_phy_status = query_phy_status,
.set_channel = rtw8822c_set_channel,
.mac_init = rtw8822c_mac_init,
.dump_fw_crash = rtw8822c_dump_fw_crash,
@@ -5278,7 +5228,7 @@ static const u8 rtw8822c_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = {
18, 18, 19, 20, 21, 22, 23, 24, 24, 25
};
-static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = {
+static const struct rtw_pwr_track_tbl rtw8822c_pwr_track_type0_tbl = {
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1],
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2],
.pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3],
@@ -5301,7 +5251,17 @@ static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = {
.pwrtrk_2g_ccka_p = rtw8822c_pwrtrk_2g_cck_a_p,
};
-static struct rtw_hw_reg_offset rtw8822c_edcca_th[] = {
+static const struct rtw_rfe_def rtw8822c_rfe_defs[] = {
+ [0] = RTW_DEF_RFE(8822c, 0, 0, 0),
+ [1] = RTW_DEF_RFE(8822c, 0, 0, 0),
+ [2] = RTW_DEF_RFE(8822c, 0, 0, 0),
+ [3] = RTW_DEF_RFE(8822c, 0, 0, 0),
+ [4] = RTW_DEF_RFE(8822c, 0, 0, 0),
+ [5] = RTW_DEF_RFE(8822c, 0, 5, 0),
+ [6] = RTW_DEF_RFE(8822c, 0, 0, 0),
+};
+
+static const struct rtw_hw_reg_offset rtw8822c_edcca_th[] = {
[EDCCA_TH_L2H_IDX] = {
{.addr = 0x84c, .mask = MASKBYTE2}, .offset = 0x80
},
@@ -5371,6 +5331,9 @@ const struct rtw_chip_info rtw8822c_hw_spec = {
.page_size = TX_PAGE_SIZE,
.dig_min = 0x20,
.usb_tx_agg_desc_num = 3,
+ .hw_feature_report = true,
+ .c2h_ra_report_size = 7,
+ .old_datarate_fb_limit = false,
.default_1ss_tx_path = BB_PATH_A,
.path_div_supported = true,
.ht_supported = true,
@@ -5397,7 +5360,6 @@ const struct rtw_chip_info rtw8822c_hw_spec = {
.rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs),
.en_dis_dpd = true,
.dpd_ratemask = DIS_DPD_RATEALL,
- .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl,
.iqk_threshold = 8,
.lck_threshold = 8,
.bfer_su_max_num = 2,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
new file mode 100644
index 000000000000..71e61b9c0bec
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c
@@ -0,0 +1,1989 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#include <linux/usb.h>
+#include "main.h"
+#include "coex.h"
+#include "phy.h"
+#include "rtw88xxa.h"
+#include "mac.h"
+#include "reg.h"
+#include "sec.h"
+#include "debug.h"
+#include "bf.h"
+#include "efuse.h"
+#include "usb.h"
+
+void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on)
+{
+ if (on) {
+ rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
+
+ rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_ELDR);
+ rtw_write16_set(rtwdev, REG_SYS_CLKR,
+ BIT_LOADER_CLK_EN | BIT_ANA8M);
+ } else {
+ rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
+ }
+}
+EXPORT_SYMBOL(rtw88xxa_efuse_grant);
+
+static void rtw8812a_read_amplifier_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+
+ efuse->ext_pa_2g = (efuse->pa_type_2g & BIT(5)) &&
+ (efuse->pa_type_2g & BIT(4));
+ efuse->ext_lna_2g = (efuse->lna_type_2g & BIT(7)) &&
+ (efuse->lna_type_2g & BIT(3));
+
+ efuse->ext_pa_5g = (efuse->pa_type_5g & BIT(1)) &&
+ (efuse->pa_type_5g & BIT(0));
+ efuse->ext_lna_5g = (efuse->lna_type_5g & BIT(7)) &&
+ (efuse->lna_type_5g & BIT(3));
+
+ /* For rtw_phy_cond2: */
+ if (efuse->ext_pa_2g) {
+ u8 ext_type_pa_2g_a = u8_get_bits(efuse->lna_type_2g, BIT(2));
+ u8 ext_type_pa_2g_b = u8_get_bits(efuse->lna_type_2g, BIT(6));
+
+ efuse->gpa_type = (ext_type_pa_2g_b << 2) | ext_type_pa_2g_a;
+ }
+
+ if (efuse->ext_pa_5g) {
+ u8 ext_type_pa_5g_a = u8_get_bits(efuse->lna_type_5g, BIT(2));
+ u8 ext_type_pa_5g_b = u8_get_bits(efuse->lna_type_5g, BIT(6));
+
+ efuse->apa_type = (ext_type_pa_5g_b << 2) | ext_type_pa_5g_a;
+ }
+
+ if (efuse->ext_lna_2g) {
+ u8 ext_type_lna_2g_a = u8_get_bits(efuse->lna_type_2g,
+ BIT(1) | BIT(0));
+ u8 ext_type_lna_2g_b = u8_get_bits(efuse->lna_type_2g,
+ BIT(5) | BIT(4));
+
+ efuse->glna_type = (ext_type_lna_2g_b << 2) | ext_type_lna_2g_a;
+ }
+
+ if (efuse->ext_lna_5g) {
+ u8 ext_type_lna_5g_a = u8_get_bits(efuse->lna_type_5g,
+ BIT(1) | BIT(0));
+ u8 ext_type_lna_5g_b = u8_get_bits(efuse->lna_type_5g,
+ BIT(5) | BIT(4));
+
+ efuse->alna_type = (ext_type_lna_5g_b << 2) | ext_type_lna_5g_a;
+ }
+}
+
+static void rtw8812a_read_rfe_type(struct rtw_dev *rtwdev,
+ struct rtw88xxa_efuse *map)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+
+ if (map->rfe_option == 0xff) {
+ if (rtwdev->hci.type == RTW_HCI_TYPE_USB)
+ efuse->rfe_option = 0;
+ else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
+ efuse->rfe_option = 2;
+ else
+ efuse->rfe_option = 4;
+ } else if (map->rfe_option & BIT(7)) {
+ if (efuse->ext_lna_5g) {
+ if (efuse->ext_pa_5g) {
+ if (efuse->ext_lna_2g && efuse->ext_pa_2g)
+ efuse->rfe_option = 3;
+ else
+ efuse->rfe_option = 0;
+ } else {
+ efuse->rfe_option = 2;
+ }
+ } else {
+ efuse->rfe_option = 4;
+ }
+ } else {
+ efuse->rfe_option = map->rfe_option & 0x3f;
+
+ /* Due to other customer already use incorrect EFUSE map for
+ * their product. We need to add workaround to prevent to
+ * modify spec and notify all customer to revise the IC 0xca
+ * content.
+ */
+ if (efuse->rfe_option == 4 &&
+ (efuse->ext_pa_5g || efuse->ext_pa_2g ||
+ efuse->ext_lna_5g || efuse->ext_lna_2g)) {
+ if (rtwdev->hci.type == RTW_HCI_TYPE_USB)
+ efuse->rfe_option = 0;
+ else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE)
+ efuse->rfe_option = 2;
+ }
+ }
+}
+
+static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 antenna = 0;
+ u8 wmode = 0;
+ u8 val8, i;
+
+ efuse->hw_cap.bw = BIT(RTW_CHANNEL_WIDTH_20) |
+ BIT(RTW_CHANNEL_WIDTH_40) |
+ BIT(RTW_CHANNEL_WIDTH_80);
+ efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT;
+
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
+ efuse->hw_cap.nss = 1;
+ else
+ efuse->hw_cap.nss = 2;
+
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
+ goto print_hw_cap;
+
+ for (i = 0; i < 2; i++) {
+ rtw_read8_physical_efuse(rtwdev, 1019 - i, &val8);
+
+ antenna = u8_get_bits(val8, GENMASK(7, 5));
+ if (antenna)
+ break;
+ antenna = u8_get_bits(val8, GENMASK(3, 1));
+ if (antenna)
+ break;
+ }
+
+ for (i = 0; i < 2; i++) {
+ rtw_read8_physical_efuse(rtwdev, 1021 - i, &val8);
+
+ wmode = u8_get_bits(val8, GENMASK(3, 2));
+ if (wmode)
+ break;
+ }
+
+ if (antenna == 1) {
+ rtw_info(rtwdev, "This RTL8812AU says it is 1T1R.\n");
+
+ efuse->hw_cap.nss = 1;
+ hal->rf_type = RF_1T1R;
+ hal->rf_path_num = 1;
+ hal->rf_phy_num = 1;
+ hal->antenna_tx = BB_PATH_A;
+ hal->antenna_rx = BB_PATH_A;
+ } else {
+ /* Override rtw_chip_parameter_setup(). It detects 8812au as 1T1R. */
+ efuse->hw_cap.nss = 2;
+ hal->rf_type = RF_2T2R;
+ hal->rf_path_num = 2;
+ hal->rf_phy_num = 2;
+ hal->antenna_tx = BB_PATH_AB;
+ hal->antenna_rx = BB_PATH_AB;
+
+ if (antenna == 2 && wmode == 2) {
+ rtw_info(rtwdev, "This RTL8812AU says it can't do VHT.\n");
+
+ /* Can't be EFUSE_HW_CAP_IGNORE and can't be
+ * EFUSE_HW_CAP_PTCL_VHT, so make it 1.
+ */
+ efuse->hw_cap.ptcl = 1;
+ efuse->hw_cap.bw &= ~BIT(RTW_CHANNEL_WIDTH_80);
+ }
+ }
+
+print_hw_cap:
+ rtw_dbg(rtwdev, RTW_DBG_EFUSE,
+ "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n",
+ efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl,
+ efuse->hw_cap.ant_num, efuse->hw_cap.nss);
+}
+
+int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw88xxa_efuse *map;
+ int i;
+
+ if (chip->id == RTW_CHIP_TYPE_8812A)
+ rtwdev->hal.cut_version += 1;
+
+ if (rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE))
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+ log_map, chip->log_efuse_size, true);
+
+ map = (struct rtw88xxa_efuse *)log_map;
+
+ efuse->rf_board_option = map->rf_board_option;
+ efuse->crystal_cap = map->xtal_k;
+ if (efuse->crystal_cap == 0xff)
+ efuse->crystal_cap = 0x20;
+ efuse->pa_type_2g = map->pa_type;
+ efuse->pa_type_5g = map->pa_type;
+ efuse->lna_type_2g = map->lna_type_2g;
+ efuse->lna_type_5g = map->lna_type_5g;
+ if (chip->id == RTW_CHIP_TYPE_8812A) {
+ rtw8812a_read_amplifier_type(rtwdev);
+ rtw8812a_read_rfe_type(rtwdev, map);
+
+ efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(1));
+ }
+ efuse->channel_plan = map->channel_plan;
+ efuse->country_code[0] = map->country_code[0];
+ efuse->country_code[1] = map->country_code[1];
+ efuse->bt_setting = map->rf_bt_setting;
+ efuse->regd = map->rf_board_option & 0x7;
+ efuse->thermal_meter[0] = map->thermal_meter;
+ efuse->thermal_meter[1] = map->thermal_meter;
+ efuse->thermal_meter_k = map->thermal_meter;
+ efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g;
+ efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g;
+
+ rtw88xxa_read_usb_type(rtwdev);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL,
+ BIT_BT_FUNC_EN);
+ else
+ efuse->btcoex = (map->rf_board_option & 0xe0) == 0x20;
+ efuse->share_ant = !!(efuse->bt_setting & BIT(0));
+
+ /* No antenna diversity because it's disabled in the vendor driver */
+ efuse->ant_div_cfg = 0;
+
+ efuse->ant_div_type = map->rf_antenna_option;
+ if (efuse->ant_div_type == 0xff)
+ efuse->ant_div_type = 0x3;
+
+ for (i = 0; i < 4; i++)
+ efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i];
+
+ switch (rtw_hci_type(rtwdev)) {
+ case RTW_HCI_TYPE_USB:
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ ether_addr_copy(efuse->addr, map->rtw8821au.mac_addr);
+ else
+ ether_addr_copy(efuse->addr, map->rtw8812au.mac_addr);
+ break;
+ case RTW_HCI_TYPE_PCIE:
+ case RTW_HCI_TYPE_SDIO:
+ default:
+ /* unsupported now */
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(rtw88xxa_read_efuse);
+
+static void rtw88xxa_reset_8051(struct rtw_dev *rtwdev)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ u8 val8;
+
+ /* Reset MCU IO Wrapper */
+ rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1));
+ if (chip->id == RTW_CHIP_TYPE_8812A)
+ rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(3));
+ else
+ rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(0));
+
+ val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN + 1);
+ rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 & ~BIT(2));
+
+ /* Enable MCU IO Wrapper */
+ rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1));
+ if (chip->id == RTW_CHIP_TYPE_8812A)
+ rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(3));
+ else
+ rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(0));
+
+ rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 | BIT(2));
+}
+
+/* A lightweight deinit function */
+static void rtw88xxau_hw_reset(struct rtw_dev *rtwdev)
+{
+ u8 val8;
+
+ if (!(rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL))
+ return;
+
+ rtw88xxa_reset_8051(rtwdev);
+ rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00);
+
+ /* before BB reset should do clock gated */
+ rtw_write32_set(rtwdev, REG_FPGA0_XCD_RF_PARA, BIT(6));
+
+ /* reset BB */
+ rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1));
+
+ /* reset RF */
+ rtw_write8(rtwdev, REG_RF_CTRL, 0);
+
+ /* reset TRX path */
+ rtw_write16(rtwdev, REG_CR, 0);
+
+ /* reset MAC, reg0x5[1], auto FSM off */
+ rtw_write8_set(rtwdev, REG_APS_FSMCO + 1, APS_FSMCO_MAC_OFF >> 8);
+
+ /* check if reg0x5[1] auto cleared */
+ if (read_poll_timeout_atomic(rtw_read8, val8,
+ !(val8 & (APS_FSMCO_MAC_OFF >> 8)),
+ 1, 5000, false,
+ rtwdev, REG_APS_FSMCO + 1))
+ rtw_err(rtwdev, "%s: timed out waiting for 0x5[1]\n", __func__);
+
+ /* reg0x5[0], auto FSM on */
+ val8 |= APS_FSMCO_MAC_ENABLE >> 8;
+ rtw_write8(rtwdev, REG_APS_FSMCO + 1, val8);
+
+ rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7));
+ rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7));
+}
+
+static int rtw88xxau_init_power_on(struct rtw_dev *rtwdev)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ u16 val16;
+ int ret;
+
+ ret = rtw_pwr_seq_parser(rtwdev, chip->pwr_on_seq);
+ if (ret) {
+ rtw_err(rtwdev, "power on flow failed\n");
+ return ret;
+ }
+
+ rtw_write16(rtwdev, REG_CR, 0);
+ val16 = BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN |
+ BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN |
+ BIT_MAC_SEC_EN | BIT_32K_CAL_TMR_EN;
+ rtw_write16_set(rtwdev, REG_CR, val16);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A) {
+ if (rtw_read8(rtwdev, REG_SYS_CFG1 + 3) & BIT(0))
+ rtw_write8_set(rtwdev, REG_LDO_SWR_CTRL, BIT(6));
+ }
+
+ return ret;
+}
+
+static int rtw88xxa_llt_write(struct rtw_dev *rtwdev, u32 address, u32 data)
+{
+ u32 value = BIT_LLT_WRITE_ACCESS | (address << 8) | data;
+ int count = 0;
+
+ rtw_write32(rtwdev, REG_LLT_INIT, value);
+
+ do {
+ if (!rtw_read32_mask(rtwdev, REG_LLT_INIT, BIT(31) | BIT(30)))
+ break;
+
+ if (count > 20) {
+ rtw_err(rtwdev, "Failed to poll write LLT done at %d!\n",
+ address);
+ return -EBUSY;
+ }
+ } while (++count);
+
+ return 0;
+}
+
+static int rtw88xxa_llt_init(struct rtw_dev *rtwdev, u32 boundary)
+{
+ u32 last_entry = 255;
+ int status = 0;
+ u32 i;
+
+ for (i = 0; i < boundary - 1; i++) {
+ status = rtw88xxa_llt_write(rtwdev, i, i + 1);
+ if (status)
+ return status;
+ }
+
+ status = rtw88xxa_llt_write(rtwdev, boundary - 1, 0xFF);
+ if (status)
+ return status;
+
+ for (i = boundary; i < last_entry; i++) {
+ status = rtw88xxa_llt_write(rtwdev, i, i + 1);
+ if (status)
+ return status;
+ }
+
+ status = rtw88xxa_llt_write(rtwdev, last_entry, boundary);
+
+ return status;
+}
+
+static void rtw88xxau_init_queue_reserved_page(struct rtw_dev *rtwdev)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_fifo_conf *fifo = &rtwdev->fifo;
+ const struct rtw_page_table *pg_tbl = NULL;
+ u16 pubq_num;
+ u32 val32;
+
+ switch (rtw_hci_type(rtwdev)) {
+ case RTW_HCI_TYPE_PCIE:
+ pg_tbl = &chip->page_table[1];
+ break;
+ case RTW_HCI_TYPE_USB:
+ if (rtwdev->hci.bulkout_num == 2)
+ pg_tbl = &chip->page_table[2];
+ else if (rtwdev->hci.bulkout_num == 3)
+ pg_tbl = &chip->page_table[3];
+ else if (rtwdev->hci.bulkout_num == 4)
+ pg_tbl = &chip->page_table[4];
+ break;
+ case RTW_HCI_TYPE_SDIO:
+ pg_tbl = &chip->page_table[0];
+ break;
+ default:
+ break;
+ }
+
+ pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num -
+ pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num;
+
+ val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num);
+ rtw_write32(rtwdev, REG_RQPN_NPQ, val32);
+
+ val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num);
+ rtw_write32(rtwdev, REG_RQPN, val32);
+}
+
+static void rtw88xxau_init_tx_buffer_boundary(struct rtw_dev *rtwdev)
+{
+ struct rtw_fifo_conf *fifo = &rtwdev->fifo;
+
+ rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary);
+ rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary);
+ rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary);
+ rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary);
+ rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary);
+}
+
+static int rtw88xxau_init_queue_priority(struct rtw_dev *rtwdev)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ u8 bulkout_num = rtwdev->hci.bulkout_num;
+ const struct rtw_rqpn *rqpn = NULL;
+ u16 txdma_pq_map;
+
+ switch (rtw_hci_type(rtwdev)) {
+ case RTW_HCI_TYPE_PCIE:
+ rqpn = &chip->rqpn_table[1];
+ break;
+ case RTW_HCI_TYPE_USB:
+ if (bulkout_num == 2)
+ rqpn = &chip->rqpn_table[2];
+ else if (bulkout_num == 3)
+ rqpn = &chip->rqpn_table[3];
+ else if (bulkout_num == 4)
+ rqpn = &chip->rqpn_table[4];
+ else
+ return -EINVAL;
+ break;
+ case RTW_HCI_TYPE_SDIO:
+ rqpn = &chip->rqpn_table[0];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rtwdev->fifo.rqpn = rqpn;
+
+ txdma_pq_map = rtw_read16(rtwdev, REG_TXDMA_PQ_MAP) & 0x7;
+ txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi);
+ txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg);
+ txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk);
+ txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be);
+ txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi);
+ txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo);
+ rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map);
+
+ /* Packet in Hi Queue Tx immediately (No constraint for ATIM Period). */
+ if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && bulkout_num == 4)
+ rtw_write8(rtwdev, REG_HIQ_NO_LMT_EN, 0xff);
+
+ return 0;
+}
+
+static void rtw88xxa_init_wmac_setting(struct rtw_dev *rtwdev)
+{
+ rtw_write16(rtwdev, REG_RXFLTMAP0, 0xffff);
+ rtw_write16(rtwdev, REG_RXFLTMAP1, 0x0400);
+ rtw_write16(rtwdev, REG_RXFLTMAP2, 0xffff);
+
+ rtw_write32(rtwdev, REG_MAR, 0xffffffff);
+ rtw_write32(rtwdev, REG_MAR + 4, 0xffffffff);
+}
+
+static void rtw88xxa_init_adaptive_ctrl(struct rtw_dev *rtwdev)
+{
+ rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, 0xffff1);
+ rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x3030);
+}
+
+static void rtw88xxa_init_edca(struct rtw_dev *rtwdev)
+{
+ rtw_write16(rtwdev, REG_SPEC_SIFS, 0x100a);
+ rtw_write16(rtwdev, REG_MAC_SPEC_SIFS, 0x100a);
+
+ rtw_write16(rtwdev, REG_SIFS, 0x100a);
+ rtw_write16(rtwdev, REG_SIFS + 2, 0x100a);
+
+ rtw_write32(rtwdev, REG_EDCA_BE_PARAM, 0x005EA42B);
+ rtw_write32(rtwdev, REG_EDCA_BK_PARAM, 0x0000A44F);
+ rtw_write32(rtwdev, REG_EDCA_VI_PARAM, 0x005EA324);
+ rtw_write32(rtwdev, REG_EDCA_VO_PARAM, 0x002FA226);
+
+ rtw_write8(rtwdev, REG_USTIME_TSF, 0x50);
+ rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50);
+}
+
+static void rtw88xxau_tx_aggregation(struct rtw_dev *rtwdev)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+
+ rtw_write32_mask(rtwdev, REG_DWBCN0_CTRL, 0xf0,
+ chip->usb_tx_agg_desc_num);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ rtw_write8(rtwdev, REG_DWBCN1_CTRL,
+ chip->usb_tx_agg_desc_num << 1);
+}
+
+static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev)
+{
+ u16 val16;
+
+ val16 = (BIT_DIS_TSF_UDT << 8) | BIT_DIS_TSF_UDT;
+ if (rtwdev->efuse.btcoex)
+ val16 |= BIT_EN_BCN_FUNCTION;
+ rtw_write16(rtwdev, REG_BCN_CTRL, val16);
+
+ rtw_write32_mask(rtwdev, REG_TBTT_PROHIBIT, 0xfffff, WLAN_TBTT_TIME);
+ rtw_write8(rtwdev, REG_DRVERLYINT, 0x05);
+ rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME);
+ rtw_write16(rtwdev, REG_BCNTCFG, 0x4413);
+}
+
+static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev)
+{
+ u8 val8, crystal_cap;
+
+ /* power on BB/RF domain */
+ val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN);
+ val8 |= BIT_FEN_USBA;
+ rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8);
+
+ /* toggle BB reset */
+ val8 |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST;
+ rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8);
+
+ rtw_write8(rtwdev, REG_RF_CTRL,
+ BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB);
+ rtw_write8(rtwdev, REG_RF_B_CTRL,
+ BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB);
+
+ rtw_load_table(rtwdev, rtwdev->chip->bb_tbl);
+ rtw_load_table(rtwdev, rtwdev->chip->agc_tbl);
+
+ crystal_cap = rtwdev->efuse.crystal_cap & 0x3F;
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+ rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000,
+ crystal_cap | (crystal_cap << 6));
+ else
+ rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000,
+ crystal_cap | (crystal_cap << 6));
+}
+
+static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev)
+{
+ u8 rf_path;
+
+ for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++)
+ rtw_load_table(rtwdev, rtwdev->chip->rf_tbl[rf_path]);
+}
+
+static void rtw8812a_config_1t(struct rtw_dev *rtwdev)
+{
+ /* BB OFDM RX Path_A */
+ rtw_write32_mask(rtwdev, REG_RXPSEL, 0xff, 0x11);
+
+ /* BB OFDM TX Path_A */
+ rtw_write32_mask(rtwdev, REG_TXPSEL, MASKLWORD, 0x1111);
+
+ /* BB CCK R/Rx Path_A */
+ rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0c000000, 0x0);
+
+ /* MCS support */
+ rtw_write32_mask(rtwdev, REG_RX_MCS_LIMIT, 0xc0000060, 0x4);
+
+ /* RF Path_B HSSI OFF */
+ rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4);
+
+ /* RF Path_B Power Down */
+ rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, MASKDWORD, 0);
+
+ /* ADDA Path_B OFF */
+ rtw_write32_mask(rtwdev, REG_AFE_PWR1_B, MASKDWORD, 0);
+ rtw_write32_mask(rtwdev, REG_AFE_PWR2_B, MASKDWORD, 0);
+}
+
+static const u32 rtw88xxa_txscale_tbl[] = {
+ 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8,
+ 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180,
+ 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab,
+ 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe
+};
+
+static u32 rtw88xxa_get_bb_swing(struct rtw_dev *rtwdev, u8 band, u8 path)
+{
+ static const u32 swing2setting[4] = {0x200, 0x16a, 0x101, 0x0b6};
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ u8 tx_bb_swing;
+
+ if (band == RTW_BAND_2G)
+ tx_bb_swing = efuse->tx_bb_swing_setting_2g;
+ else
+ tx_bb_swing = efuse->tx_bb_swing_setting_5g;
+
+ if (path == RF_PATH_B)
+ tx_bb_swing >>= 2;
+ tx_bb_swing &= 0x3;
+
+ return swing2setting[tx_bb_swing];
+}
+
+static u8 rtw88xxa_get_swing_index(struct rtw_dev *rtwdev)
+{
+ u32 swing, table_value;
+ u8 i;
+
+ swing = rtw88xxa_get_bb_swing(rtwdev, rtwdev->hal.current_band_type,
+ RF_PATH_A);
+
+ for (i = 0; i < ARRAY_SIZE(rtw88xxa_txscale_tbl); i++) {
+ table_value = rtw88xxa_txscale_tbl[i];
+ if (swing == table_value)
+ return i;
+ }
+
+ return 24;
+}
+
+static void rtw88xxa_pwrtrack_init(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u8 path;
+
+ dm_info->default_ofdm_index = rtw88xxa_get_swing_index(rtwdev);
+
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
+ dm_info->default_cck_index = 0;
+ else
+ dm_info->default_cck_index = 24;
+
+ for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
+ ewma_thermal_init(&dm_info->avg_thermal[path]);
+ dm_info->delta_power_index[path] = 0;
+ dm_info->delta_power_index_last[path] = 0;
+ }
+
+ dm_info->pwr_trk_triggered = false;
+ dm_info->pwr_trk_init_trigger = true;
+ dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k;
+}
+
+void rtw88xxa_power_off(struct rtw_dev *rtwdev,
+ const struct rtw_pwr_seq_cmd *const *enter_lps_flow)
+{
+ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+ enum usb_device_speed speed = rtwusb->udev->speed;
+ u16 ori_fsmc0;
+ u8 reg_cr;
+
+ reg_cr = rtw_read8(rtwdev, REG_CR);
+
+ /* Already powered off */
+ if (reg_cr == 0 || reg_cr == 0xEA)
+ return;
+
+ rtw_hci_stop(rtwdev);
+
+ if (!rtwdev->efuse.btcoex)
+ rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC);
+
+ /* set Reg 0xf008[3:4] to 2'11 to enable U1/U2 Mode in USB3.0. */
+ if (speed == USB_SPEED_SUPER)
+ rtw_write8_set(rtwdev, REG_USB_MOD, 0x18);
+
+ rtw_write32(rtwdev, REG_HISR0, 0xffffffff);
+ rtw_write32(rtwdev, REG_HISR1, 0xffffffff);
+ rtw_write32(rtwdev, REG_HIMR0, 0);
+ rtw_write32(rtwdev, REG_HIMR1, 0);
+
+ if (rtwdev->efuse.btcoex)
+ rtw_coex_power_off_setting(rtwdev);
+
+ ori_fsmc0 = rtw_read16(rtwdev, REG_APS_FSMCO);
+ rtw_write16(rtwdev, REG_APS_FSMCO, ori_fsmc0 & ~APS_FSMCO_HW_POWERDOWN);
+
+ /* Stop Tx Report Timer. */
+ rtw_write8_clr(rtwdev, REG_TX_RPT_CTRL, BIT(1));
+
+ /* Stop Rx */
+ rtw_write8(rtwdev, REG_CR, 0);
+
+ rtw_pwr_seq_parser(rtwdev, enter_lps_flow);
+
+ if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL)
+ rtw88xxa_reset_8051(rtwdev);
+
+ rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(2));
+ rtw_write8(rtwdev, REG_MCUFW_CTRL, 0);
+
+ rtw_pwr_seq_parser(rtwdev, rtwdev->chip->pwr_off_seq);
+
+ if (ori_fsmc0 & APS_FSMCO_HW_POWERDOWN)
+ rtw_write16_set(rtwdev, REG_APS_FSMCO, APS_FSMCO_HW_POWERDOWN);
+
+ clear_bit(RTW_FLAG_POWERON, rtwdev->flags);
+}
+EXPORT_SYMBOL(rtw88xxa_power_off);
+
+static void rtw88xxa_set_channel_bb_swing(struct rtw_dev *rtwdev, u8 band)
+{
+ rtw_write32_mask(rtwdev, REG_TXSCALE_A, BB_SWING_MASK,
+ rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_A));
+ rtw_write32_mask(rtwdev, REG_TXSCALE_B, BB_SWING_MASK,
+ rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_B));
+ rtw88xxa_pwrtrack_init(rtwdev);
+}
+
+static void rtw8821a_set_ext_band_switch(struct rtw_dev *rtwdev, u8 band)
+{
+ rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN, 0);
+ rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL, 1);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf, 7);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf0, 7);
+
+ if (band == RTW_BAND_2G)
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 1);
+ else
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 2);
+}
+
+static void rtw8821a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev)
+{
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+
+ /* Turn off RF PA and LNA */
+
+ /* 0xCB0[15:12] = 0x7 (LNA_On)*/
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x7);
+ /* 0xCB0[7:4] = 0x7 (PAPE_A)*/
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x7);
+
+ if (efuse->ext_lna_2g) {
+ /* Turn on 2.4G External LNA */
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 1);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x2);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x2);
+ } else {
+ /* Bypass 2.4G External LNA */
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7);
+ }
+}
+
+static void rtw8821a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev)
+{
+ /* Turn ON RF PA and LNA */
+
+ /* 0xCB0[15:12] = 0x7 (LNA_On)*/
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x5);
+ /* 0xCB0[7:4] = 0x7 (PAPE_A)*/
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x4);
+
+ /* Bypass 2.4G External LNA */
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7);
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7);
+}
+
+static void rtw8812a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev)
+{
+ switch (rtwdev->efuse.rfe_option) {
+ case 0:
+ case 2:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ break;
+ case 1:
+ if (rtwdev->efuse.btcoex) {
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x777777);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ } else {
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ }
+ break;
+ case 3:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337770);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337770);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1);
+ break;
+ case 4:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x001);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x001);
+ break;
+ case 5:
+ rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x77);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777);
+ rtw_write8_clr(rtwdev, REG_RFE_INV_A + 3, BIT(0));
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ break;
+ case 6:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07772770);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07772770);
+ rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077);
+ rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rtw8812a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev)
+{
+ switch (rtwdev->efuse.rfe_option) {
+ case 0:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010);
+ break;
+ case 1:
+ if (rtwdev->efuse.btcoex) {
+ rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x337717);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ } else {
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000);
+ }
+ break;
+ case 2:
+ case 4:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337777);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010);
+ break;
+ case 3:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337717);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337717);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010);
+ rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1);
+ break;
+ case 5:
+ rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x33);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777);
+ rtw_write8_set(rtwdev, REG_RFE_INV_A + 3, BIT(0));
+ rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010);
+ break;
+ case 6:
+ rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07737717);
+ rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07737717);
+ rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077);
+ rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rtw88xxa_switch_band(struct rtw_dev *rtwdev, u8 new_band, u8 bw)
+{
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ u16 basic_rates, reg_41a;
+
+ /* 8811au one antenna module doesn't support antenna div, so driver must
+ * control antenna band, otherwise one of the band will have issue
+ */
+ if (chip->id == RTW_CHIP_TYPE_8821A && !rtwdev->efuse.btcoex &&
+ rtwdev->efuse.ant_div_cfg == 0)
+ rtw8821a_set_ext_band_switch(rtwdev, new_band);
+
+ if (new_band == RTW_BAND_2G) {
+ rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A) {
+ rtw8821a_phy_set_rfe_reg_24g(rtwdev);
+
+ rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0);
+ } else {
+ rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x1);
+ rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x17);
+
+ if (bw == RTW_CHANNEL_WIDTH_20 &&
+ rtwdev->hal.rf_type == RF_1T1R &&
+ !rtwdev->efuse.ext_lna_2g)
+ rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x02);
+ else
+ rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04);
+
+ rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 0);
+
+ rtw8812a_phy_set_rfe_reg_24g(rtwdev);
+ }
+
+ rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0x1);
+ rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0x1);
+
+ basic_rates = BIT(DESC_RATE1M) | BIT(DESC_RATE2M) |
+ BIT(DESC_RATE5_5M) | BIT(DESC_RATE11M) |
+ BIT(DESC_RATE6M) | BIT(DESC_RATE12M) |
+ BIT(DESC_RATE24M);
+ rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates);
+
+ rtw_write8_clr(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN);
+ } else { /* RTW_BAND_5G */
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ rtw8821a_phy_set_rfe_reg_5g(rtwdev);
+
+ rtw_write8_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN);
+
+ read_poll_timeout_atomic(rtw_read16, reg_41a, (reg_41a & 0x30) == 0x30,
+ 50, 2500, false, rtwdev, REG_TXPKT_EMPTY);
+
+ rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A) {
+ rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 1);
+ } else {
+ rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x2);
+ rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x15);
+ rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04);
+
+ rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 1);
+
+ rtw8812a_phy_set_rfe_reg_5g(rtwdev);
+ }
+
+ rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0);
+ rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0xf);
+
+ basic_rates = BIT(DESC_RATE6M) | BIT(DESC_RATE12M) |
+ BIT(DESC_RATE24M);
+ rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates);
+ }
+
+ rtw88xxa_set_channel_bb_swing(rtwdev, new_band);
+}
+
+int rtw88xxa_power_on(struct rtw_dev *rtwdev)
+{
+ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ struct rtw_efuse *efuse = &rtwdev->efuse;
+ struct rtw_hal *hal = &rtwdev->hal;
+ int ret;
+
+ if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
+ return 0;
+
+ /* Override rtw_chip_efuse_info_setup() */
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL,
+ BIT_BT_FUNC_EN);
+
+ /* Override rtw_chip_efuse_info_setup() */
+ if (chip->id == RTW_CHIP_TYPE_8812A)
+ rtw8812a_read_amplifier_type(rtwdev);
+
+ ret = rtw_hci_setup(rtwdev);
+ if (ret) {
+ rtw_err(rtwdev, "failed to setup hci\n");
+ goto err;
+ }
+
+ /* Revise for U2/U3 switch we can not update RF-A/B reset.
+ * Reset after MAC power on to prevent RF R/W error.
+ * Is it a right method?
+ */
+ if (chip->id == RTW_CHIP_TYPE_8812A) {
+ rtw_write8(rtwdev, REG_RF_CTRL, 5);
+ rtw_write8(rtwdev, REG_RF_CTRL, 7);
+ rtw_write8(rtwdev, REG_RF_B_CTRL, 5);
+ rtw_write8(rtwdev, REG_RF_B_CTRL, 7);
+ }
+
+ /* If HW didn't go through a complete de-initial procedure,
+ * it probably occurs some problem for double initial
+ * procedure.
+ */
+ rtw88xxau_hw_reset(rtwdev);
+
+ ret = rtw88xxau_init_power_on(rtwdev);
+ if (ret) {
+ rtw_err(rtwdev, "failed to power on\n");
+ goto err;
+ }
+
+ ret = rtw_set_trx_fifo_info(rtwdev);
+ if (ret) {
+ rtw_err(rtwdev, "failed to set trx fifo info\n");
+ goto err;
+ }
+
+ ret = rtw88xxa_llt_init(rtwdev, rtwdev->fifo.rsvd_boundary);
+ if (ret) {
+ rtw_err(rtwdev, "failed to init llt\n");
+ goto err;
+ }
+
+ rtw_write32_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN);
+
+ ret = rtw_wait_firmware_completion(rtwdev);
+ if (ret) {
+ rtw_err(rtwdev, "failed to wait firmware completion\n");
+ goto err_off;
+ }
+
+ ret = rtw_download_firmware(rtwdev, &rtwdev->fw);
+ if (ret) {
+ rtw_err(rtwdev, "failed to download firmware\n");
+ goto err_off;
+ }
+
+ rtw_write8(rtwdev, REG_HMETFR, 0xf);
+
+ rtw_load_table(rtwdev, chip->mac_tbl);
+
+ rtw88xxau_init_queue_reserved_page(rtwdev);
+ rtw88xxau_init_tx_buffer_boundary(rtwdev);
+ rtw88xxau_init_queue_priority(rtwdev);
+
+ rtw_write16(rtwdev, REG_TRXFF_BNDY + 2,
+ chip->rxff_size - REPORT_BUF - 1);
+
+ if (chip->id == RTW_CHIP_TYPE_8812A)
+ rtw_write8(rtwdev, REG_PBP,
+ u8_encode_bits(PBP_512, PBP_TX_MASK) |
+ u8_encode_bits(PBP_64, PBP_RX_MASK));
+
+ rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE);
+
+ rtw_write32(rtwdev, REG_HIMR0, 0);
+ rtw_write32(rtwdev, REG_HIMR1, 0);
+
+ rtw_write32_mask(rtwdev, REG_CR, 0x30000, 0x2);
+
+ rtw88xxa_init_wmac_setting(rtwdev);
+ rtw88xxa_init_adaptive_ctrl(rtwdev);
+ rtw88xxa_init_edca(rtwdev);
+
+ rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7));
+ rtw_write8(rtwdev, REG_ACKTO, 0x80);
+
+ rtw88xxau_tx_aggregation(rtwdev);
+
+ rtw88xxa_init_beacon_parameters(rtwdev);
+ rtw_write8(rtwdev, REG_BCN_MAX_ERR, 0xff);
+
+ rtw_hci_interface_cfg(rtwdev);
+
+ /* usb3 rx interval */
+ rtw_write8(rtwdev, REG_USB3_RXITV, 0x01);
+
+ /* burst length=4, set 0x3400 for burst length=2 */
+ rtw_write16(rtwdev, REG_RXDMA_STATUS, 0x7400);
+ rtw_write8(rtwdev, REG_RXDMA_STATUS + 1, 0xf5);
+
+ /* 0x456 = 0x70, sugguested by Zhilin */
+ if (chip->id == RTW_CHIP_TYPE_8821A)
+ rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x5e);
+ else
+ rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x70);
+
+ rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, 0xffffffff);
+ rtw_write8(rtwdev, REG_USTIME_TSF, 0x50);
+ rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50);
+
+ if (rtwusb->udev->speed == USB_SPEED_SUPER)
+ /* Disable U1/U2 Mode to avoid 2.5G spur in USB3.0. */
+ rtw_write8_clr(rtwdev, REG_USB_MOD, BIT(4) | BIT(3));
+
+ rtw_write8_set(rtwdev, REG_SINGLE_AMPDU_CTRL, BIT_EN_SINGLE_APMDU);
+
+ /* for VHT packet length 11K */
+ rtw_write8(rtwdev, REG_RX_PKT_LIMIT, 0x18);
+
+ rtw_write8(rtwdev, REG_PIFS, 0x00);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A) {
+ /* 0x0a0a too small, it can't pass AC logo. change to 0x1f1f */
+ rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f);
+ rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL, 0x80);
+ rtw_write32(rtwdev, REG_FAST_EDCA_CTRL, 0x03087777);
+ } else {
+ rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f);
+ rtw_write8_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7));
+ }
+
+ /* to prevent mac is reseted by bus. */
+ rtw_write8_set(rtwdev, REG_RSV_CTRL, BIT(5) | BIT(6));
+
+ /* ARFB table 9 for 11ac 5G 2SS */
+ rtw_write32(rtwdev, REG_ARFR0, 0x00000010);
+ rtw_write32(rtwdev, REG_ARFRH0, 0xfffff000);
+
+ /* ARFB table 10 for 11ac 5G 1SS */
+ rtw_write32(rtwdev, REG_ARFR1_V1, 0x00000010);
+ rtw_write32(rtwdev, REG_ARFRH1_V1, 0x003ff000);
+
+ /* ARFB table 11 for 11ac 24G 1SS */
+ rtw_write32(rtwdev, REG_ARFR2_V1, 0x00000015);
+ rtw_write32(rtwdev, REG_ARFRH2_V1, 0x003ff000);
+
+ /* ARFB table 12 for 11ac 24G 2SS */
+ rtw_write32(rtwdev, REG_ARFR3_V1, 0x00000015);
+ rtw_write32(rtwdev, REG_ARFRH3_V1, 0xffcff000);
+
+ rtw_write8_set(rtwdev, REG_CR, BIT_MACTXEN | BIT_MACRXEN);
+
+ rtw88xxa_phy_bb_config(rtwdev);
+ rtw88xxa_phy_rf_config(rtwdev);
+
+ if (chip->id == RTW_CHIP_TYPE_8812A && hal->rf_path_num == 1)
+ rtw8812a_config_1t(rtwdev);
+
+ rtw88xxa_switch_band(rtwdev, RTW_BAND_2G, RTW_CHANNEL_WIDTH_20);
+
+ rtw_write32(rtwdev, RTW_SEC_CMD_REG, BIT(31) | BIT(30));
+
+ rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0xff);
+ rtw_write32(rtwdev, REG_BAR_MODE_CTRL, 0x0201ffff);
+ rtw_write8(rtwdev, REG_NAV_CTRL + 2, 0);
+
+ rtw_write8_clr(rtwdev, REG_GPIO_MUXCFG, BIT(5));
+
+ rtw_phy_init(rtwdev);
+
+ rtw88xxa_pwrtrack_init(rtwdev);
+
+ /* 0x4c6[3] 1: RTS BW = Data BW
+ * 0: RTS BW depends on CCA / secondary CCA result.
+ */
+ rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT(3));
+
+ /* enable Tx report. */
+ rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, 0x0f);
+
+ /* Pretx_en, for WEP/TKIP SEC */
+ rtw_write8(rtwdev, REG_EARLY_MODE_CONTROL + 3, 0x01);
+
+ rtw_write16(rtwdev, REG_TX_RPT_TIME, 0x3df0);
+
+ /* Reset USB mode switch setting */
+ rtw_write8(rtwdev, REG_SYS_SDIO_CTRL, 0x0);
+ rtw_write8(rtwdev, REG_ACLK_MON, 0x0);
+
+ rtw_write8(rtwdev, REG_USB_HRPWM, 0);
+
+ /* ack for xmit mgmt frames. */
+ rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(12));
+
+ hal->cck_high_power = rtw_read32_mask(rtwdev, REG_CCK_RPT_FORMAT,
+ BIT_CCK_RPT_FORMAT);
+
+ ret = rtw_hci_start(rtwdev);
+ if (ret) {
+ rtw_err(rtwdev, "failed to start hci\n");
+ goto err_off;
+ }
+
+ if (efuse->btcoex) {
+ rtw_coex_power_on_setting(rtwdev);
+ rtw_coex_init_hw_config(rtwdev, false);
+ }
+
+ set_bit(RTW_FLAG_POWERON, rtwdev->flags);
+
+ return 0;
+
+err_off:
+ chip->ops->power_off(rtwdev);
+
+err:
+ return ret;
+}
+EXPORT_SYMBOL(rtw88xxa_power_on);
+
+u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev,
+ enum rtw_rf_path rf_path, u32 addr, u32 mask)
+{
+ static const u32 pi_addr[2] = { REG_3WIRE_SWA, REG_3WIRE_SWB };
+ static const u32 read_addr[2][2] = {
+ { REG_SI_READ_A, REG_SI_READ_B },
+ { REG_PI_READ_A, REG_PI_READ_B }
+ };
+ const struct rtw_chip_info *chip = rtwdev->chip;
+ const struct rtw_hal *hal = &rtwdev->hal;
+ bool set_cca, pi_mode;
+ u32 val;
+
+ if (rf_path >= hal->rf_phy_num) {
+ rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
+ return INV_RF_DATA;
+ }
+
+ /* CCA off to avoid reading the wrong value.
+ * Toggling CCA would affect RF 0x0, skip it.
+ */
+ set_cca = addr != 0x0 && chip->id == RTW_CHIP_TYPE_8812A &&
+ hal->cut_version != RTW_CHIP_VER_CUT_C;
+
+ if (set_cca)
+ rtw_write32_set(rtwdev, REG_CCA2ND, BIT(3));
+
+ addr &= 0xff;
+
+ pi_mode = rtw_read32_mask(rtwdev, pi_addr[rf_path], 0x4);
+
+ rtw_write32_mask(rtwdev, REG_HSSI_READ, MASKBYTE0, addr);
+
+ if (chip->id == RTW_CHIP_TYPE_8821A ||
+ hal->cut_version == RTW_CHIP_VER_CUT_C)
+ udelay(20);
+
+ val = rtw_read32_mask(rtwdev, read_addr[pi_mode][rf_path], mask);
+
+ /* CCA on */
+ if (set_cca)
+ rtw_write32_clr(rtwdev, REG_CCA2ND, BIT(3));
+
+ return val;
+}
+EXPORT_SYMBOL(rtw88xxa_phy_read_rf);
+
+static void rtw8812a_phy_fix_spur(struct rtw_dev *rtwdev, u8 channel, u8 bw)
+{
+ /* C cut Item12 ADC FIFO CLOCK */
+ if (rtwdev->hal.cut_version == RTW_CHIP_VER_CUT_C) {
+ if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11)
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x3);
+ else
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x2);
+
+ /* A workaround to resolve 2480Mhz spur by setting ADC clock
+ * as 160M.
+ */
+ if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) {
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3);
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1);
+ } else if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11) {
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1);
+ } else if (bw != RTW_CHANNEL_WIDTH_80) {
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2);
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0);
+ }
+ } else {
+ /* A workaround to resolve 2480Mhz spur by setting ADC clock
+ * as 160M.
+ */
+ if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14))
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3);
+ else if (channel <= 14) /* 2.4G only */
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2);
+ }
+}
+
+static void rtw88xxa_switch_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u32 fc_area, rf_mod_ag;
+ u8 path;
+
+ switch (channel) {
+ case 36 ... 48:
+ fc_area = 0x494;
+ break;
+ case 50 ... 64:
+ fc_area = 0x453;
+ break;
+ case 100 ... 116:
+ fc_area = 0x452;
+ break;
+ default:
+ if (channel >= 118)
+ fc_area = 0x412;
+ else
+ fc_area = 0x96a;
+ break;
+ }
+
+ rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, fc_area);
+
+ for (path = 0; path < hal->rf_path_num; path++) {
+ switch (channel) {
+ case 36 ... 64:
+ rf_mod_ag = 0x101;
+ break;
+ case 100 ... 140:
+ rf_mod_ag = 0x301;
+ break;
+ default:
+ if (channel > 140)
+ rf_mod_ag = 0x501;
+ else
+ rf_mod_ag = 0x000;
+ break;
+ }
+
+ rtw_write_rf(rtwdev, path, RF_CFGCH,
+ RF18_RFSI_MASK | RF18_BAND_MASK, rf_mod_ag);
+
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+ rtw8812a_phy_fix_spur(rtwdev, channel, bw);
+
+ rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_CHANNEL_MASK, channel);
+ }
+}
+
+static void rtw88xxa_set_reg_bw(struct rtw_dev *rtwdev, u8 bw)
+{
+ u16 val16 = rtw_read16(rtwdev, REG_WMAC_TRXPTCL_CTL);
+
+ val16 &= ~BIT_RFMOD;
+ if (bw == RTW_CHANNEL_WIDTH_80)
+ val16 |= BIT_RFMOD_80M;
+ else if (bw == RTW_CHANNEL_WIDTH_40)
+ val16 |= BIT_RFMOD_40M;
+
+ rtw_write16(rtwdev, REG_WMAC_TRXPTCL_CTL, val16);
+}
+
+static void rtw88xxa_post_set_bw_mode(struct rtw_dev *rtwdev, u8 channel,
+ u8 bw, u8 primary_chan_idx)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u8 txsc40 = 0, txsc20, txsc;
+ u8 reg_837, l1pkval;
+
+ rtw88xxa_set_reg_bw(rtwdev, bw);
+
+ txsc20 = primary_chan_idx;
+ if (bw == RTW_CHANNEL_WIDTH_80) {
+ if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST)
+ txsc40 = RTW_SC_40_UPPER;
+ else
+ txsc40 = RTW_SC_40_LOWER;
+ }
+
+ txsc = BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40);
+ rtw_write8(rtwdev, REG_DATA_SC, txsc);
+
+ reg_837 = rtw_read8(rtwdev, REG_BWINDICATION + 3);
+
+ switch (bw) {
+ default:
+ case RTW_CHANNEL_WIDTH_20:
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300200);
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0);
+
+ if (hal->rf_type == RF_2T2R)
+ rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 7);
+ else
+ rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 8);
+
+ break;
+ case RTW_CHANNEL_WIDTH_40:
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300201);
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0);
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc);
+ rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc);
+
+ if (reg_837 & BIT(2)) {
+ l1pkval = 6;
+ } else {
+ if (hal->rf_type == RF_2T2R)
+ l1pkval = 7;
+ else
+ l1pkval = 8;
+ }
+
+ rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval);
+
+ if (txsc == RTW_SC_20_UPPER)
+ rtw_write32_set(rtwdev, REG_RXSB, BIT(4));
+ else
+ rtw_write32_clr(rtwdev, REG_RXSB, BIT(4));
+
+ break;
+ case RTW_CHANNEL_WIDTH_80:
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300202);
+ rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1);
+ rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc);
+ rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc);
+
+ if (reg_837 & BIT(2)) {
+ l1pkval = 5;
+ } else {
+ if (hal->rf_type == RF_2T2R)
+ l1pkval = 6;
+ else
+ l1pkval = 7;
+ }
+
+ rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval);
+
+ break;
+ }
+}
+
+static void rtw88xxa_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) {
+ switch (bw) {
+ case RTW_CHANNEL_WIDTH_5:
+ case RTW_CHANNEL_WIDTH_10:
+ case RTW_CHANNEL_WIDTH_20:
+ default:
+ rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 3);
+ break;
+ case RTW_CHANNEL_WIDTH_40:
+ rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 1);
+ break;
+ case RTW_CHANNEL_WIDTH_80:
+ rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 0);
+ break;
+ }
+ }
+}
+
+void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
+ u8 primary_chan_idx)
+{
+ u8 old_band, new_band;
+
+ if (rtw_read8(rtwdev, REG_CCK_CHECK) & BIT_CHECK_CCK_EN)
+ old_band = RTW_BAND_5G;
+ else
+ old_band = RTW_BAND_2G;
+
+ if (channel > 14)
+ new_band = RTW_BAND_5G;
+ else
+ new_band = RTW_BAND_2G;
+
+ if (new_band != old_band)
+ rtw88xxa_switch_band(rtwdev, new_band, bw);
+
+ rtw88xxa_switch_channel(rtwdev, channel, bw);
+
+ rtw88xxa_post_set_bw_mode(rtwdev, channel, bw, primary_chan_idx);
+
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A)
+ rtw8812a_phy_fix_spur(rtwdev, channel, bw);
+
+ rtw88xxa_set_channel_rf(rtwdev, channel, bw);
+}
+EXPORT_SYMBOL(rtw88xxa_set_channel);
+
+void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx))
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_jaguar_phy_status_rpt *rpt;
+ u8 gain[RTW_RF_PATH_MAX], rssi, i;
+ s8 rx_pwr_db, power_a, power_b;
+ const s8 min_rx_power = -120;
+ u8 lna_idx, vga_idx;
+
+ rpt = (struct rtw_jaguar_phy_status_rpt *)phy_status;
+
+ if (pkt_stat->rate <= DESC_RATE11M) {
+ lna_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_LNA_IDX);
+ vga_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_VGA_IDX);
+
+ rx_pwr_db = cck_rx_pwr(lna_idx, vga_idx);
+
+ pkt_stat->rx_power[RF_PATH_A] = rx_pwr_db;
+ pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
+ dm_info->rssi[RF_PATH_A] = pkt_stat->rssi;
+ pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
+ pkt_stat->signal_power = rx_pwr_db;
+ } else { /* OFDM rate */
+ gain[RF_PATH_A] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_A);
+ gain[RF_PATH_B] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_B);
+
+ for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++) {
+ pkt_stat->rx_power[i] = gain[i] - 110;
+ rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[i], 1);
+ dm_info->rssi[i] = rssi;
+ }
+
+ pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power,
+ rtwdev->hal.rf_path_num);
+
+ power_a = pkt_stat->rx_power[RF_PATH_A];
+ power_b = pkt_stat->rx_power[RF_PATH_B];
+ if (rtwdev->hal.rf_path_num == 1)
+ power_b = power_a;
+
+ pkt_stat->signal_power = max3(power_a, power_b, min_rx_power);
+ }
+}
+EXPORT_SYMBOL(rtw88xxa_query_phy_status);
+
+static void
+rtw88xxa_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path,
+ u8 rs, u32 *phy_pwr_idx)
+{
+ static const u32 offset_txagc[2] = {
+ REG_TX_AGC_A_CCK_11_CCK_1, REG_TX_AGC_B_CCK_11_CCK_1
+ };
+ u8 rate, rate_idx, pwr_index, shift;
+ struct rtw_hal *hal = &rtwdev->hal;
+ bool write_1ss_mcs9;
+ u32 mask;
+ int j;
+
+ for (j = 0; j < rtw_rate_size[rs]; j++) {
+ rate = rtw_rate_section[rs][j];
+
+ pwr_index = hal->tx_pwr_tbl[path][rate];
+
+ shift = rate & 0x3;
+ *phy_pwr_idx |= ((u32)pwr_index << (shift * 8));
+
+ write_1ss_mcs9 = rate == DESC_RATEVHT1SS_MCS9 &&
+ hal->rf_path_num == 1;
+
+ if (write_1ss_mcs9)
+ mask = MASKLWORD;
+ else
+ mask = MASKDWORD;
+
+ if (shift == 0x3 || write_1ss_mcs9) {
+ rate_idx = rate & 0xfc;
+ if (rate >= DESC_RATEVHT1SS_MCS0)
+ rate_idx -= 0x10;
+
+ rtw_write32_mask(rtwdev, offset_txagc[path] + rate_idx,
+ mask, *phy_pwr_idx);
+
+ *phy_pwr_idx = 0;
+ }
+ }
+}
+
+static void rtw88xxa_tx_power_training(struct rtw_dev *rtwdev, u8 bw,
+ u8 channel, u8 path)
+{
+ static const u32 write_offset[] = {
+ REG_TX_PWR_TRAINING_A, REG_TX_PWR_TRAINING_B,
+ };
+ u32 power_level, write_data;
+ u8 i;
+
+ power_level = rtwdev->hal.tx_pwr_tbl[path][DESC_RATEMCS7];
+ write_data = 0;
+
+ for (i = 0; i < 3; i++) {
+ if (i == 0)
+ power_level -= 10;
+ else if (i == 1)
+ power_level -= 8;
+ else
+ power_level -= 6;
+
+ write_data |= max_t(u32, power_level, 2) << (i * 8);
+ }
+
+ rtw_write32_mask(rtwdev, write_offset[path], 0xffffff, write_data);
+}
+
+void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev)
+{
+ struct rtw_hal *hal = &rtwdev->hal;
+ u32 phy_pwr_idx = 0;
+ int rs, path;
+
+ for (path = 0; path < hal->rf_path_num; path++) {
+ for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) {
+ if (hal->rf_path_num == 1 &&
+ (rs == RTW_RATE_SECTION_HT_2S ||
+ rs == RTW_RATE_SECTION_VHT_2S))
+ continue;
+
+ if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags) &&
+ rs > RTW_RATE_SECTION_OFDM)
+ continue;
+
+ if (hal->current_band_type == RTW_BAND_5G &&
+ rs == RTW_RATE_SECTION_CCK)
+ continue;
+
+ rtw88xxa_set_tx_power_index_by_rate(rtwdev, path, rs,
+ &phy_pwr_idx);
+ }
+
+ rtw88xxa_tx_power_training(rtwdev, hal->current_band_width,
+ hal->current_channel, path);
+ }
+}
+EXPORT_SYMBOL(rtw88xxa_set_tx_power_index);
+
+void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u32 cck_fa_cnt, ofdm_fa_cnt;
+ u32 crc32_cnt, cca32_cnt;
+ u32 cck_enable;
+
+ cck_enable = rtw_read32(rtwdev, REG_RXPSEL) & BIT(28);
+ cck_fa_cnt = rtw_read16(rtwdev, REG_FA_CCK);
+ ofdm_fa_cnt = rtw_read16(rtwdev, REG_FA_OFDM);
+
+ dm_info->cck_fa_cnt = cck_fa_cnt;
+ dm_info->ofdm_fa_cnt = ofdm_fa_cnt;
+ dm_info->total_fa_cnt = ofdm_fa_cnt;
+ if (cck_enable)
+ dm_info->total_fa_cnt += cck_fa_cnt;
+
+ crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK);
+ dm_info->cck_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
+ dm_info->cck_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
+
+ crc32_cnt = rtw_read32(rtwdev, REG_CRC_OFDM);
+ dm_info->ofdm_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
+ dm_info->ofdm_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
+
+ crc32_cnt = rtw_read32(rtwdev, REG_CRC_HT);
+ dm_info->ht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
+ dm_info->ht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
+
+ crc32_cnt = rtw_read32(rtwdev, REG_CRC_VHT);
+ dm_info->vht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD);
+ dm_info->vht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD);
+
+ cca32_cnt = rtw_read32(rtwdev, REG_CCA_OFDM);
+ dm_info->ofdm_cca_cnt = u32_get_bits(cca32_cnt, MASKHWORD);
+ dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt;
+ if (cck_enable) {
+ cca32_cnt = rtw_read32(rtwdev, REG_CCA_CCK);
+ dm_info->cck_cca_cnt = u32_get_bits(cca32_cnt, MASKLWORD);
+ dm_info->total_cca_cnt += dm_info->cck_cca_cnt;
+ }
+
+ rtw_write32_set(rtwdev, REG_FAS, BIT(17));
+ rtw_write32_clr(rtwdev, REG_FAS, BIT(17));
+ rtw_write32_clr(rtwdev, REG_CCK0_FAREPORT, BIT(15));
+ rtw_write32_set(rtwdev, REG_CCK0_FAREPORT, BIT(15));
+ rtw_write32_set(rtwdev, REG_CNTRST, BIT(0));
+ rtw_write32_clr(rtwdev, REG_CNTRST, BIT(0));
+}
+EXPORT_SYMBOL(rtw88xxa_false_alarm_statistics);
+
+void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev,
+ u32 *macbb_backup,
+ const u32 *backup_macbb_reg,
+ u32 macbb_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* save MACBB default value */
+ for (i = 0; i < macbb_num; i++)
+ macbb_backup[i] = rtw_read32(rtwdev, backup_macbb_reg[i]);
+}
+EXPORT_SYMBOL(rtw88xxa_iqk_backup_mac_bb);
+
+void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
+ const u32 *backup_afe_reg, u32 afe_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Save AFE Parameters */
+ for (i = 0; i < afe_num; i++)
+ afe_backup[i] = rtw_read32(rtwdev, backup_afe_reg[i]);
+}
+EXPORT_SYMBOL(rtw88xxa_iqk_backup_afe);
+
+void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev,
+ u32 *macbb_backup,
+ const u32 *backup_macbb_reg,
+ u32 macbb_num)
+{
+ u32 i;
+
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ /* Reload MacBB Parameters */
+ for (i = 0; i < macbb_num; i++)
+ rtw_write32(rtwdev, backup_macbb_reg[i], macbb_backup[i]);
+}
+EXPORT_SYMBOL(rtw88xxa_iqk_restore_mac_bb);
+
+void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev)
+{
+ /* [31] = 0 --> Page C */
+ rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0);
+
+ rtw_write8(rtwdev, REG_TXPAUSE, 0x3f);
+ rtw_write32_mask(rtwdev, REG_BCN_CTRL,
+ (BIT_EN_BCN_FUNCTION << 8) | BIT_EN_BCN_FUNCTION, 0x0);
+
+ /* RX ante off */
+ rtw_write8(rtwdev, REG_RXPSEL, 0x00);
+
+ /* CCA off */
+ rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf, 0xc);
+
+ /* CCK RX path off */
+ rtw_write8(rtwdev, REG_CCK_RX + 3, 0xf);
+}
+EXPORT_SYMBOL(rtw88xxa_iqk_configure_mac);
+
+bool rtw88xxa_iqk_finish(int average, int threshold,
+ int *x_temp, int *y_temp, int *x, int *y,
+ bool break_inner, bool break_outer)
+{
+ bool finish = false;
+ int i, ii, dx, dy;
+
+ for (i = 0; i < average; i++) {
+ for (ii = i + 1; ii < average; ii++) {
+ dx = abs_diff(x_temp[i] >> 21, x_temp[ii] >> 21);
+ dy = abs_diff(y_temp[i] >> 21, y_temp[ii] >> 21);
+
+ if (dx < threshold && dy < threshold) {
+ *x = ((x_temp[i] >> 21) + (x_temp[ii] >> 21));
+ *y = ((y_temp[i] >> 21) + (y_temp[ii] >> 21));
+
+ *x /= 2;
+ *y /= 2;
+
+ finish = true;
+
+ if (break_inner)
+ break;
+ }
+ }
+
+ if (finish && break_outer)
+ break;
+ }
+
+ return finish;
+}
+EXPORT_SYMBOL(rtw88xxa_iqk_finish);
+
+static void rtw88xxa_pwrtrack_set(struct rtw_dev *rtwdev, u8 tx_rate, u8 path)
+{
+ static const u32 reg_txscale[2] = { REG_TXSCALE_A, REG_TXSCALE_B };
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ u8 cck_swing_idx, ofdm_swing_idx;
+ u8 pwr_tracking_limit;
+
+ switch (tx_rate) {
+ case DESC_RATE1M ... DESC_RATE11M:
+ pwr_tracking_limit = 32;
+ break;
+ case DESC_RATE6M ... DESC_RATE48M:
+ case DESC_RATEMCS3 ... DESC_RATEMCS4:
+ case DESC_RATEMCS11 ... DESC_RATEMCS12:
+ case DESC_RATEVHT1SS_MCS3 ... DESC_RATEVHT1SS_MCS4:
+ case DESC_RATEVHT2SS_MCS3 ... DESC_RATEVHT2SS_MCS4:
+ pwr_tracking_limit = 30;
+ break;
+ case DESC_RATE54M:
+ case DESC_RATEMCS5 ... DESC_RATEMCS7:
+ case DESC_RATEMCS13 ... DESC_RATEMCS15:
+ case DESC_RATEVHT1SS_MCS5 ... DESC_RATEVHT1SS_MCS6:
+ case DESC_RATEVHT2SS_MCS5 ... DESC_RATEVHT2SS_MCS6:
+ pwr_tracking_limit = 28;
+ break;
+ case DESC_RATEMCS0 ... DESC_RATEMCS2:
+ case DESC_RATEMCS8 ... DESC_RATEMCS10:
+ case DESC_RATEVHT1SS_MCS0 ... DESC_RATEVHT1SS_MCS2:
+ case DESC_RATEVHT2SS_MCS0 ... DESC_RATEVHT2SS_MCS2:
+ pwr_tracking_limit = 34;
+ break;
+ case DESC_RATEVHT1SS_MCS7:
+ case DESC_RATEVHT2SS_MCS7:
+ pwr_tracking_limit = 26;
+ break;
+ default:
+ case DESC_RATEVHT1SS_MCS8:
+ case DESC_RATEVHT2SS_MCS8:
+ pwr_tracking_limit = 24;
+ break;
+ case DESC_RATEVHT1SS_MCS9:
+ case DESC_RATEVHT2SS_MCS9:
+ pwr_tracking_limit = 22;
+ break;
+ }
+
+ cck_swing_idx = dm_info->delta_power_index[path] + dm_info->default_cck_index;
+ ofdm_swing_idx = dm_info->delta_power_index[path] + dm_info->default_ofdm_index;
+
+ if (ofdm_swing_idx > pwr_tracking_limit) {
+ if (path == RF_PATH_A)
+ dm_info->txagc_remnant_cck = cck_swing_idx - pwr_tracking_limit;
+ dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx - pwr_tracking_limit;
+
+ ofdm_swing_idx = pwr_tracking_limit;
+ } else if (ofdm_swing_idx == 0) {
+ if (path == RF_PATH_A)
+ dm_info->txagc_remnant_cck = cck_swing_idx;
+ dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx;
+ } else {
+ if (path == RF_PATH_A)
+ dm_info->txagc_remnant_cck = 0;
+ dm_info->txagc_remnant_ofdm[path] = 0;
+ }
+
+ rtw_write32_mask(rtwdev, reg_txscale[path], GENMASK(31, 21),
+ rtw88xxa_txscale_tbl[ofdm_swing_idx]);
+}
+
+void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
+ void (*do_lck)(struct rtw_dev *rtwdev),
+ void (*do_iqk)(struct rtw_dev *rtwdev))
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_hal *hal = &rtwdev->hal;
+ struct rtw_swing_table swing_table;
+ s8 remnant_pre[RTW_RF_PATH_MAX];
+ u8 thermal_value, delta, path;
+ bool need_iqk;
+
+ rtw_phy_config_swing_table(rtwdev, &swing_table);
+
+ if (rtwdev->efuse.thermal_meter[0] == 0xff) {
+ pr_err_once("efuse thermal meter is 0xff\n");
+ return;
+ }
+
+ thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00);
+
+ rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A);
+
+ need_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev);
+
+ if (need_iqk && do_lck)
+ do_lck(rtwdev);
+
+ if (dm_info->pwr_trk_init_trigger)
+ dm_info->pwr_trk_init_trigger = false;
+ else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value,
+ RF_PATH_A))
+ goto iqk;
+
+ delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A);
+
+ for (path = RF_PATH_A; path < hal->rf_path_num; path++) {
+ remnant_pre[path] = dm_info->txagc_remnant_ofdm[path];
+
+ dm_info->delta_power_index[path] =
+ rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, path,
+ RF_PATH_A, delta);
+
+ if (dm_info->delta_power_index[path] !=
+ dm_info->delta_power_index_last[path]) {
+ dm_info->delta_power_index_last[path] =
+ dm_info->delta_power_index[path];
+
+ rtw88xxa_pwrtrack_set(rtwdev, dm_info->tx_rate, path);
+ }
+ }
+
+ for (path = RF_PATH_A; path < hal->rf_path_num; path++) {
+ if (remnant_pre[path] != dm_info->txagc_remnant_ofdm[path]) {
+ rtw_phy_set_tx_power_level(rtwdev,
+ hal->current_channel);
+ break;
+ }
+ }
+
+iqk:
+ if (need_iqk)
+ do_iqk(rtwdev);
+}
+EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack);
+
+void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
+{
+ static const u8 pd[CCK_PD_LV_MAX] = {0x40, 0x83, 0xcd, 0xdd, 0xed};
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+
+ /* Override rtw_phy_cck_pd_lv_link(). It implements something
+ * like type 2/3/4. We need type 1 here.
+ */
+ if (rtw_is_assoc(rtwdev)) {
+ if (dm_info->min_rssi > 60) {
+ new_lvl = CCK_PD_LV3;
+ } else if (dm_info->min_rssi > 35) {
+ new_lvl = CCK_PD_LV2;
+ } else if (dm_info->min_rssi > 20) {
+ if (dm_info->cck_fa_avg > 500)
+ new_lvl = CCK_PD_LV2;
+ else if (dm_info->cck_fa_avg < 250)
+ new_lvl = CCK_PD_LV1;
+ else
+ return;
+ } else {
+ new_lvl = CCK_PD_LV1;
+ }
+ }
+
+ rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n",
+ dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl);
+
+ if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl)
+ return;
+
+ dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
+ dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl;
+
+ rtw_write8(rtwdev, REG_CCK_PD_TH, pd[new_lvl]);
+}
+EXPORT_SYMBOL(rtw88xxa_phy_cck_pd_set);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
new file mode 100644
index 000000000000..09a45c1a4129
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2024 Realtek Corporation
+ */
+
+#ifndef __RTW88XXA_H__
+#define __RTW88XXA_H__
+
+#include <asm/byteorder.h>
+#include "reg.h"
+
+struct rtw8821au_efuse {
+ u8 res4[48]; /* 0xd0 */
+ u8 vid[2]; /* 0x100 */
+ u8 pid[2];
+ u8 res8[3];
+ u8 mac_addr[ETH_ALEN]; /* 0x107 */
+ u8 res9[243];
+} __packed;
+
+struct rtw8812au_efuse {
+ u8 vid[2]; /* 0xd0 */
+ u8 pid[2]; /* 0xd2 */
+ u8 res0[3];
+ u8 mac_addr[ETH_ALEN]; /* 0xd7 */
+ u8 res1[291];
+} __packed;
+
+struct rtw88xxa_efuse {
+ __le16 rtl_id;
+ u8 res0[6]; /* 0x02 */
+ u8 usb_mode; /* 0x08 */
+ u8 res1[7]; /* 0x09 */
+
+ /* power index for four RF paths */
+ struct rtw_txpwr_idx txpwr_idx_table[4];
+
+ u8 channel_plan; /* 0xb8 */
+ u8 xtal_k;
+ u8 thermal_meter;
+ u8 iqk_lck;
+ u8 pa_type; /* 0xbc */
+ u8 lna_type_2g; /* 0xbd */
+ u8 res2;
+ u8 lna_type_5g; /* 0xbf */
+ u8 res3;
+ u8 rf_board_option; /* 0xc1 */
+ u8 rf_feature_option;
+ u8 rf_bt_setting;
+ u8 eeprom_version;
+ u8 eeprom_customer_id; /* 0xc5 */
+ u8 tx_bb_swing_setting_2g;
+ u8 tx_bb_swing_setting_5g;
+ u8 tx_pwr_calibrate_rate;
+ u8 rf_antenna_option; /* 0xc9 */
+ u8 rfe_option;
+ u8 country_code[2];
+ u8 res4[3];
+ union {
+ struct rtw8821au_efuse rtw8821au;
+ struct rtw8812au_efuse rtw8812au;
+ };
+} __packed;
+
+static_assert(sizeof(struct rtw88xxa_efuse) == 512);
+
+#define WLAN_BCN_DMA_TIME 0x02
+#define WLAN_TBTT_PROHIBIT 0x04
+#define WLAN_TBTT_HOLD_TIME 0x064
+#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\
+ (WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP))
+
+struct rtw_jaguar_phy_status_rpt {
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+ __le32 w4;
+ __le32 w5;
+ __le32 w6;
+} __packed;
+
+#define RTW_JGRPHY_W0_GAIN_A GENMASK(6, 0)
+#define RTW_JGRPHY_W0_TRSW_A BIT(7)
+#define RTW_JGRPHY_W0_GAIN_B GENMASK(14, 8)
+#define RTW_JGRPHY_W0_TRSW_B BIT(15)
+#define RTW_JGRPHY_W0_CHL_NUM GENMASK(25, 16)
+#define RTW_JGRPHY_W0_SUB_CHNL GENMASK(29, 26)
+#define RTW_JGRPHY_W0_R_RFMOD GENMASK(31, 30)
+
+/* CCK: */
+#define RTW_JGRPHY_W1_SIG_QUAL GENMASK(7, 0)
+#define RTW_JGRPHY_W1_AGC_RPT_VGA_IDX GENMASK(12, 8)
+#define RTW_JGRPHY_W1_AGC_RPT_LNA_IDX GENMASK(15, 13)
+#define RTW_JGRPHY_W1_BB_POWER GENMASK(23, 16)
+/* OFDM: */
+#define RTW_JGRPHY_W1_PWDB_ALL GENMASK(7, 0)
+#define RTW_JGRPHY_W1_CFO_SHORT_A GENMASK(15, 8) /* s8 */
+#define RTW_JGRPHY_W1_CFO_SHORT_B GENMASK(23, 16) /* s8 */
+#define RTW_JGRPHY_W1_BT_RF_CH_MSB GENMASK(31, 30)
+
+#define RTW_JGRPHY_W2_ANT_DIV_SW_A BIT(0)
+#define RTW_JGRPHY_W2_ANT_DIV_SW_B BIT(1)
+#define RTW_JGRPHY_W2_BT_RF_CH_LSB GENMASK(7, 2)
+#define RTW_JGRPHY_W2_CFO_TAIL_A GENMASK(15, 8) /* s8 */
+#define RTW_JGRPHY_W2_CFO_TAIL_B GENMASK(23, 16) /* s8 */
+#define RTW_JGRPHY_W2_PCTS_MSK_RPT_0 GENMASK(31, 24)
+
+#define RTW_JGRPHY_W3_PCTS_MSK_RPT_1 GENMASK(7, 0)
+/* Stream 1 and 2 RX EVM: */
+#define RTW_JGRPHY_W3_RXEVM_1 GENMASK(15, 8) /* s8 */
+#define RTW_JGRPHY_W3_RXEVM_2 GENMASK(23, 16) /* s8 */
+#define RTW_JGRPHY_W3_RXSNR_A GENMASK(31, 24) /* s8 */
+
+#define RTW_JGRPHY_W4_RXSNR_B GENMASK(7, 0) /* s8 */
+#define RTW_JGRPHY_W4_PCTS_MSK_RPT_2 GENMASK(21, 8)
+#define RTW_JGRPHY_W4_PCTS_RPT_VALID BIT(22)
+#define RTW_JGRPHY_W4_RXEVM_3 GENMASK(31, 24) /* s8 */
+
+#define RTW_JGRPHY_W5_RXEVM_4 GENMASK(7, 0) /* s8 */
+/* 8812a, stream 1 and 2 CSI: */
+#define RTW_JGRPHY_W5_CSI_CURRENT_1 GENMASK(15, 8)
+#define RTW_JGRPHY_W5_CSI_CURRENT_2 GENMASK(23, 16)
+/* 8814a: */
+#define RTW_JGRPHY_W5_RXSNR_C GENMASK(15, 8) /* s8 */
+#define RTW_JGRPHY_W5_RXSNR_D GENMASK(23, 16) /* s8 */
+#define RTW_JGRPHY_W5_GAIN_C GENMASK(30, 24)
+#define RTW_JGRPHY_W5_TRSW_C BIT(31)
+
+#define RTW_JGRPHY_W6_GAIN_D GENMASK(6, 0)
+#define RTW_JGRPHY_W6_TRSW_D BIT(7)
+#define RTW_JGRPHY_W6_SIGEVM GENMASK(15, 8) /* s8 */
+#define RTW_JGRPHY_W6_ANTIDX_ANTC GENMASK(18, 16)
+#define RTW_JGRPHY_W6_ANTIDX_ANTD GENMASK(21, 19)
+#define RTW_JGRPHY_W6_DPDT_CTRL_KEEP BIT(22)
+#define RTW_JGRPHY_W6_GNT_BT_KEEP BIT(23)
+#define RTW_JGRPHY_W6_ANTIDX_ANTA GENMASK(26, 24)
+#define RTW_JGRPHY_W6_ANTIDX_ANTB GENMASK(29, 27)
+#define RTW_JGRPHY_W6_HW_ANTSW_OCCUR GENMASK(31, 30)
+
+#define RF18_BW_MASK (BIT(11) | BIT(10))
+
+void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on);
+int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map);
+void rtw88xxa_power_off(struct rtw_dev *rtwdev,
+ const struct rtw_pwr_seq_cmd *const *enter_lps_flow);
+int rtw88xxa_power_on(struct rtw_dev *rtwdev);
+u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev,
+ enum rtw_rf_path rf_path, u32 addr, u32 mask);
+void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw,
+ u8 primary_chan_idx);
+void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx));
+void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev);
+void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev);
+void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev,
+ u32 *macbb_backup,
+ const u32 *backup_macbb_reg,
+ u32 macbb_num);
+void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup,
+ const u32 *backup_afe_reg, u32 afe_num);
+void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev,
+ u32 *macbb_backup,
+ const u32 *backup_macbb_reg,
+ u32 macbb_num);
+void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev);
+bool rtw88xxa_iqk_finish(int average, int threshold,
+ int *x_temp, int *y_temp, int *x, int *y,
+ bool break_inner, bool break_outer);
+void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev,
+ void (*do_lck)(struct rtw_dev *rtwdev),
+ void (*do_iqk)(struct rtw_dev *rtwdev));
+void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl);
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c
index 66f9419588cf..90fc8a5fa89e 100644
--- a/drivers/net/wireless/realtek/rtw88/rx.c
+++ b/drivers/net/wireless/realtek/rtw88/rx.c
@@ -187,11 +187,10 @@ fill_rx_status:
}
EXPORT_SYMBOL(rtw_update_rx_freq_from_ie);
-void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_hdr *hdr,
- struct ieee80211_rx_status *rx_status,
- u8 *phy_status)
+static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *rx_status)
{
struct ieee80211_hw *hw = rtwdev->hw;
u8 path;
@@ -235,12 +234,75 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
else
rx_status->bw = RATE_INFO_BW_20;
- rx_status->signal = pkt_stat->signal_power;
- for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
- rx_status->chains |= BIT(path);
- rx_status->chain_signal[path] = pkt_stat->rx_power[path];
+ if (pkt_stat->phy_status) {
+ rx_status->signal = pkt_stat->signal_power;
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ rx_status->chains |= BIT(path);
+ rx_status->chain_signal[path] = pkt_stat->rx_power[path];
+ }
+ } else {
+ rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
}
rtw_rx_addr_match(rtwdev, pkt_stat, hdr);
+
+ /* Rtl8723cs driver checks for size < 14 or size > 8192 and
+ * simply drops the packet.
+ */
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len == 0) {
+ rx_status->flag |= RX_FLAG_NO_PSDU;
+ rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet");
+ }
+}
+
+void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ struct ieee80211_rx_status *rx_status)
+{
+ u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz;
+ struct rtw_rx_desc *rx_desc = rx_desc8;
+ struct ieee80211_hdr *hdr;
+ u32 enc_type, swdec;
+ void *phy_status;
+
+ memset(pkt_stat, 0, sizeof(*pkt_stat));
+
+ pkt_stat->pkt_len = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PKT_LEN);
+ pkt_stat->crc_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_CRC32);
+ pkt_stat->icv_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ICV_ERR);
+ pkt_stat->drv_info_sz = le32_get_bits(rx_desc->w0,
+ RTW_RX_DESC_W0_DRV_INFO_SIZE);
+ enc_type = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ENC_TYPE);
+ pkt_stat->shift = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SHIFT);
+ pkt_stat->phy_status = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PHYST);
+ swdec = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SWDEC);
+ pkt_stat->decrypted = !swdec && enc_type != RX_DESC_ENC_NONE;
+
+ pkt_stat->cam_id = le32_get_bits(rx_desc->w1, RTW_RX_DESC_W1_MACID);
+
+ pkt_stat->is_c2h = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_C2H);
+ pkt_stat->ppdu_cnt = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_PPDU_CNT);
+
+ pkt_stat->rate = le32_get_bits(rx_desc->w3, RTW_RX_DESC_W3_RX_RATE);
+
+ pkt_stat->bw = le32_get_bits(rx_desc->w4, RTW_RX_DESC_W4_BW);
+
+ pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL);
+
+ /* drv_info_sz is in unit of 8-bytes */
+ pkt_stat->drv_info_sz *= 8;
+
+ /* c2h cmd pkt's rx/phy status is not interested */
+ if (pkt_stat->is_c2h)
+ return;
+
+ phy_status = rx_desc8 + desc_sz + pkt_stat->shift;
+ hdr = phy_status + pkt_stat->drv_info_sz;
+ pkt_stat->hdr = hdr;
+
+ if (pkt_stat->phy_status)
+ rtwdev->chip->ops->query_phy_status(rtwdev, phy_status, pkt_stat);
+
+ rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status);
}
-EXPORT_SYMBOL(rtw_rx_fill_rx_status);
+EXPORT_SYMBOL(rtw_rx_query_rx_desc);
diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h
index 9f0019112987..6b7dee245c0a 100644
--- a/drivers/net/wireless/realtek/rtw88/rx.h
+++ b/drivers/net/wireless/realtek/rtw88/rx.h
@@ -14,42 +14,40 @@ enum rtw_rx_desc_enc {
RX_DESC_ENC_WEP104 = 5,
};
-#define GET_RX_DESC_PHYST(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(26))
-#define GET_RX_DESC_ICV_ERR(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(15))
-#define GET_RX_DESC_CRC32(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(14))
-#define GET_RX_DESC_SWDEC(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(27))
-#define GET_RX_DESC_C2H(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x02), BIT(28))
-#define GET_RX_DESC_PKT_LEN(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(13, 0))
-#define GET_RX_DESC_DRV_INFO_SIZE(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(19, 16))
-#define GET_RX_DESC_SHIFT(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(25, 24))
-#define GET_RX_DESC_ENC_TYPE(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(22, 20))
-#define GET_RX_DESC_RX_RATE(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x03), GENMASK(6, 0))
-#define GET_RX_DESC_MACID(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x01), GENMASK(6, 0))
-#define GET_RX_DESC_PPDU_CNT(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x02), GENMASK(30, 29))
-#define GET_RX_DESC_TSFL(rxdesc) \
- le32_get_bits(*((__le32 *)(rxdesc) + 0x05), GENMASK(31, 0))
-#define GET_RX_DESC_BW(rxdesc) \
- (le32_get_bits(*((__le32 *)(rxdesc) + 0x04), GENMASK(5, 4)))
+struct rtw_rx_desc {
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+ __le32 w4;
+ __le32 w5;
+} __packed;
+
+#define RTW_RX_DESC_W0_PKT_LEN GENMASK(13, 0)
+#define RTW_RX_DESC_W0_CRC32 BIT(14)
+#define RTW_RX_DESC_W0_ICV_ERR BIT(15)
+#define RTW_RX_DESC_W0_DRV_INFO_SIZE GENMASK(19, 16)
+#define RTW_RX_DESC_W0_ENC_TYPE GENMASK(22, 20)
+#define RTW_RX_DESC_W0_SHIFT GENMASK(25, 24)
+#define RTW_RX_DESC_W0_PHYST BIT(26)
+#define RTW_RX_DESC_W0_SWDEC BIT(27)
+
+#define RTW_RX_DESC_W1_MACID GENMASK(6, 0)
+
+#define RTW_RX_DESC_W2_C2H BIT(28)
+#define RTW_RX_DESC_W2_PPDU_CNT GENMASK(30, 29)
+
+#define RTW_RX_DESC_W3_RX_RATE GENMASK(6, 0)
+
+#define RTW_RX_DESC_W4_BW GENMASK(5, 4)
+
+#define RTW_RX_DESC_W5_TSFL GENMASK(31, 0)
void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct sk_buff *skb);
-void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
- struct rtw_rx_pkt_stat *pkt_stat,
- struct ieee80211_hdr *hdr,
- struct ieee80211_rx_status *rx_status,
- u8 *phy_status);
+void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
+ struct rtw_rx_pkt_stat *pkt_stat,
+ struct ieee80211_rx_status *rx_status);
void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status,
struct rtw_rx_pkt_stat *pkt_stat);
diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c
index 21d0754dd7f6..799230eb5f16 100644
--- a/drivers/net/wireless/realtek/rtw88/sdio.c
+++ b/drivers/net/wireless/realtek/rtw88/sdio.c
@@ -864,7 +864,7 @@ static void rtw_sdio_tx_skb_prepare(struct rtw_dev *rtwdev,
pkt_info->qsel = rtw_sdio_get_tx_qsel(rtwdev, skb, queue);
- rtw_tx_fill_tx_desc(pkt_info, skb);
+ rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb);
rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, pkt_desc);
}
@@ -981,8 +981,7 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len)
while (true) {
rx_desc = skb->data;
- chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
- &rx_status);
+ rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status);
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
pkt_stat.shift;
@@ -1297,12 +1296,12 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev)
struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;
int i;
- for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++)
- skb_queue_purge(&rtwsdio->tx_queue[i]);
-
flush_workqueue(rtwsdio->txwq);
destroy_workqueue(rtwsdio->txwq);
kfree(rtwsdio->tx_handler_data);
+
+ for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++)
+ ieee80211_purge_tx_queue(rtwdev->hw, &rtwsdio->tx_queue[i]);
}
int rtw_sdio_probe(struct sdio_func *sdio_func,
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index dae7ca148865..6ed470dd6f22 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -32,7 +32,8 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
}
}
-void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
+void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
{
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
bool more_data = false;
@@ -67,6 +68,9 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE);
+ if (rtwdev->chip->old_datarate_fb_limit)
+ tx_desc->w4 |= le32_encode_bits(0x1f, RTW_TX_DESC_W4_DATARATE_FB_LIMIT);
+
tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) |
le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) |
le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) |
diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index 3d544fd7f60f..d34cdeca16f1 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -44,6 +44,7 @@ struct rtw_tx_desc {
#define RTW_TX_DESC_W3_NAVUSEHDR BIT(15)
#define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17)
#define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0)
+#define RTW_TX_DESC_W4_DATARATE_FB_LIMIT GENMASK(12, 8)
#define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24)
#define RTW_TX_DESC_W5_DATA_SHORT BIT(4)
#define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5)
@@ -94,7 +95,8 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
struct sk_buff *skb);
-void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb);
+void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev,
+ struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb);
void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn);
void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src);
void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index e83ab6fb83f5..8d6db68246f1 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -423,10 +423,11 @@ static void rtw_usb_tx_handler(struct work_struct *work)
static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb)
{
+ struct rtw_dev *rtwdev = rtwusb->rtwdev;
int i;
for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
- skb_queue_purge(&rtwusb->tx_queue[i]);
+ ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]);
}
static void rtw_usb_write_port_complete(struct urb *urb)
@@ -457,7 +458,7 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev,
skb_put_data(skb, buf, size);
skb_push(skb, chip->tx_pkt_desc_sz);
memset(skb->data, 0, chip->tx_pkt_desc_sz);
- rtw_tx_fill_tx_desc(pkt_info, skb);
+ rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb);
rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
ret = rtw_usb_write_port(rtwdev, qsel, skb,
@@ -477,6 +478,7 @@ static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
pkt_info.tx_pkt_size = size;
pkt_info.qsel = TX_DESC_QSEL_BEACON;
pkt_info.offset = chip->tx_pkt_desc_sz;
+ pkt_info.ls = true;
return rtw_usb_write_data(rtwdev, &pkt_info, buf);
}
@@ -524,7 +526,7 @@ static int rtw_usb_tx_write(struct rtw_dev *rtwdev,
pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
ep = qsel_to_ep(rtwusb, pkt_info->qsel);
- rtw_tx_fill_tx_desc(pkt_info, skb);
+ rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb);
rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
tx_data = rtw_usb_get_tx_data(skb);
tx_data->sn = pkt_info->sn;
@@ -570,8 +572,8 @@ static void rtw_usb_rx_handler(struct work_struct *work)
do {
rx_desc = skb->data;
- chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
- &rx_status);
+ rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat,
+ &rx_status);
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
pkt_stat.shift;
@@ -771,7 +773,6 @@ static void rtw_usb_dynamic_rx_agg_v1(struct rtw_dev *rtwdev, bool enable)
u8 size, timeout;
u16 val16;
- rtw_write32_set(rtwdev, REG_RXDMA_AGG_PG_TH, BIT_EN_PRE_CALC);
rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_AGG_EN);
rtw_write8_clr(rtwdev, REG_RXDMA_AGG_PG_TH + 3, BIT(7));
@@ -889,9 +890,9 @@ static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
- rtw_usb_tx_queue_purge(rtwusb);
flush_workqueue(rtwusb->txwq);
destroy_workqueue(rtwusb->txwq);
+ rtw_usb_tx_queue_purge(rtwusb);
}
static int rtw_usb_intf_init(struct rtw_dev *rtwdev,
diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c
index 4476fc7e53db..8ef59994c0db 100644
--- a/drivers/net/wireless/realtek/rtw89/cam.c
+++ b/drivers/net/wireless/realtek/rtw89/cam.c
@@ -211,25 +211,17 @@ static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
return 0;
}
-static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- const struct rtw89_sec_cam_entry *sec_cam,
- bool inform_fw)
+static int __rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ const struct rtw89_sec_cam_entry *sec_cam,
+ bool inform_fw)
{
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- struct rtw89_vif *rtwvif;
struct rtw89_addr_cam_entry *addr_cam;
unsigned int i;
int ret = 0;
- if (!vif) {
- rtw89_err(rtwdev, "No iface for deleting sec cam\n");
- return -EINVAL;
- }
-
- rtwvif = (struct rtw89_vif *)vif->drv_priv;
- addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) {
if (addr_cam->sec_ent[i] != sec_cam->sec_cam_idx)
@@ -239,11 +231,11 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
}
if (inform_fw) {
- ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
+ ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link);
if (ret)
rtw89_err(rtwdev,
"failed to update dctl cam del key: %d\n", ret);
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret)
rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
}
@@ -251,25 +243,17 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
return ret;
}
-static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- struct rtw89_sec_cam_entry *sec_cam)
+static int __rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_key_conf *key,
+ struct rtw89_sec_cam_entry *sec_cam)
{
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- struct rtw89_vif *rtwvif;
struct rtw89_addr_cam_entry *addr_cam;
u8 key_idx = 0;
int ret;
- if (!vif) {
- rtw89_err(rtwdev, "No iface for adding sec cam\n");
- return -EINVAL;
- }
-
- rtwvif = (struct rtw89_vif *)vif->drv_priv;
- addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104)
@@ -285,13 +269,13 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
addr_cam->sec_ent_keyid[key_idx] = key->keyidx;
addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx;
set_bit(key_idx, addr_cam->sec_cam_map);
- ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
+ ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link);
if (ret) {
rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n",
ret);
return ret;
}
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret) {
rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n",
ret);
@@ -302,6 +286,92 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
return 0;
}
+static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ const struct rtw89_sec_cam_entry *sec_cam,
+ bool inform_fw)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_vif *rtwvif;
+ unsigned int link_id;
+ int ret;
+
+ if (!vif) {
+ rtw89_err(rtwdev, "No iface for deleting sec cam\n");
+ return -EINVAL;
+ }
+
+ rtwvif = vif_to_rtwvif(vif);
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ rtwsta_link = rtwsta ? rtwsta->links[link_id] : NULL;
+ if (rtwsta && !rtwsta_link)
+ continue;
+
+ ret = __rtw89_cam_detach_sec_cam(rtwdev, rtwvif_link, rtwsta_link,
+ sec_cam, inform_fw);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ struct rtw89_sec_cam_entry *sec_cam)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_vif *rtwvif;
+ unsigned int link_id;
+ int key_link_id;
+ int ret;
+
+ if (!vif) {
+ rtw89_err(rtwdev, "No iface for adding sec cam\n");
+ return -EINVAL;
+ }
+
+ rtwvif = vif_to_rtwvif(vif);
+
+ key_link_id = ieee80211_vif_is_mld(vif) ? key->link_id : 0;
+ if (key_link_id >= 0) {
+ rtwvif_link = rtwvif->links[key_link_id];
+ rtwsta_link = rtwsta ? rtwsta->links[key_link_id] : NULL;
+
+ if (!rtwvif_link || (rtwsta && !rtwsta_link)) {
+ rtw89_err(rtwdev, "No drv link for adding sec cam\n");
+ return -ENOLINK;
+ }
+
+ return __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link,
+ rtwsta_link, key, sec_cam);
+ }
+
+ /* key_link_id < 0: MLD pairwise key */
+ if (!rtwsta) {
+ rtw89_err(rtwdev, "No sta for adding MLD pairwise sec cam\n");
+ return -EINVAL;
+ }
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link,
+ rtwsta_link, key, sec_cam);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -485,10 +555,10 @@ void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev,
clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map);
}
-void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
- struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
rtw89_cam_deinit_addr_cam(rtwdev, addr_cam);
rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam);
@@ -593,7 +663,7 @@ static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev,
}
int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct rtw89_bssid_cam_entry *bssid_cam,
const u8 *bssid)
{
@@ -613,7 +683,7 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
}
bssid_cam->bssid_cam_idx = bssid_cam_idx;
- bssid_cam->phy_idx = rtwvif->phy_idx;
+ bssid_cam->phy_idx = rtwvif_link->phy_idx;
bssid_cam->len = BSSID_CAM_ENT_SIZE;
bssid_cam->offset = 0;
bssid_cam->valid = true;
@@ -622,20 +692,21 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
return 0;
}
-void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
- ether_addr_copy(bssid_cam->bssid, rtwvif->bssid);
+ ether_addr_copy(bssid_cam->bssid, rtwvif_link->bssid);
}
-int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam;
- struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam;
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
int ret;
- ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid);
+ ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam,
+ rtwvif_link->bssid);
if (ret) {
rtw89_err(rtwdev, "failed to init bssid cam\n");
return ret;
@@ -651,19 +722,27 @@ int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
}
int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta, u8 *cmd)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link, u8 *cmd)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
- u8 bss_color = vif->bss_conf.he_bss_color.color;
+ struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link,
+ rtwsta_link);
+ struct ieee80211_bss_conf *bss_conf;
+ u8 bss_color;
u8 bss_mask;
- if (vif->bss_conf.nontransmitted)
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ bss_color = bss_conf->he_bss_color.color;
+
+ if (bss_conf->nontransmitted)
bss_mask = RTW89_BSSID_MATCH_5_BYTES;
else
bss_mask = RTW89_BSSID_MATCH_ALL;
+ rcu_read_unlock();
+
FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx);
FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset);
FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len);
@@ -694,19 +773,30 @@ static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr)
}
void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
const u8 *scan_mac_addr,
u8 *cmd)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
- struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta);
- const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_addr_cam_entry *addr_cam =
+ rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
+ struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
+ struct ieee80211_link_sta *link_sta;
+ const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif_link->mac_addr;
u8 sma_hash, tma_hash, addr_msk_start;
u8 sma_start = 0;
u8 tma_start = 0;
- u8 *tma = sta ? sta->addr : rtwvif->bssid;
+ const u8 *tma;
+
+ rcu_read_lock();
+
+ if (sta) {
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ tma = link_sta->addr;
+ } else {
+ tma = rtwvif_link->bssid;
+ }
if (addr_cam->addr_mask != 0) {
addr_msk_start = __ffs(addr_cam->addr_mask);
@@ -723,10 +813,10 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
FWCMD_SET_ADDR_LEN(cmd, addr_cam->len);
FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid);
- FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type);
- FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond);
- FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule);
- FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx);
+ FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif_link->net_type);
+ FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif_link->bcn_hit_cond);
+ FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif_link->hit_rule);
+ FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif_link->phy_idx);
FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask);
FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel);
FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash);
@@ -748,20 +838,21 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
FWCMD_SET_ADDR_TMA4(cmd, tma[4]);
FWCMD_SET_ADDR_TMA5(cmd, tma[5]);
- FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port);
- FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port);
- FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger);
- FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop);
- FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind);
- FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind);
- FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id);
- if (rtwvif->net_type == RTW89_NET_TYPE_INFRA)
+ FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif_link->port);
+ FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif_link->port);
+ FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif_link->trigger);
+ FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif_link->lsig_txop);
+ FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif_link->tgt_ind);
+ FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif_link->frm_tgt_ind);
+ FWCMD_SET_ADDR_MACID(cmd, rtwsta_link ? rtwsta_link->mac_id :
+ rtwvif_link->mac_id);
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA)
FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff);
- else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0);
- FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern);
- FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc);
- FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic);
+ FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif_link->wowlan_pattern);
+ FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif_link->wowlan_uc);
+ FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif_link->wowlan_magic);
FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi);
FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode);
FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]);
@@ -780,18 +871,22 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]);
FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]);
FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]);
+
+ rcu_read_unlock();
}
void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
struct rtw89_h2c_dctlinfo_ud_v1 *h2c)
{
- struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ struct rtw89_addr_cam_entry *addr_cam =
+ rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
- h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
+ h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id :
+ rtwvif_link->mac_id,
DCTLINFO_V1_C0_MACID) |
le32_encode_bits(1, DCTLINFO_V1_C0_OP);
@@ -862,18 +957,28 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
}
void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
struct rtw89_h2c_dctlinfo_ud_v2 *h2c)
{
- struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link->rtwvif);
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct rtw89_addr_cam_entry *addr_cam =
+ rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link);
+ bool is_mld = sta ? sta->mlo : ieee80211_vif_is_mld(vif);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
+ u8 *mld_sma, *mld_tma, *mld_bssid;
- h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
+ h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id :
+ rtwvif_link->mac_id,
DCTLINFO_V2_C0_MACID) |
le32_encode_bits(1, DCTLINFO_V2_C0_OP);
+ h2c->w2 = le32_encode_bits(is_mld, DCTLINFO_V2_W2_IS_MLD);
+ h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_IS_MLD);
+
h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0],
DCTLINFO_V2_W4_SEC_ENT0_KEYID) |
le32_encode_bits(addr_cam->sec_ent_keyid[1],
@@ -939,4 +1044,47 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
DCTLINFO_V2_W4_SEC_KEY_ID);
h2c->m4 |= cpu_to_le32(DCTLINFO_V2_W4_SEC_KEY_ID);
}
+
+ if (!is_mld)
+ return;
+
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) {
+ mld_sma = rtwvif->mac_addr;
+ mld_tma = vif->cfg.ap_addr;
+ mld_bssid = vif->cfg.ap_addr;
+ } else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE && sta) {
+ mld_sma = rtwvif->mac_addr;
+ mld_tma = sta->addr;
+ mld_bssid = rtwvif->mac_addr;
+ } else {
+ return;
+ }
+
+ h2c->w8 = le32_encode_bits(mld_sma[0], DCTLINFO_V2_W8_MLD_SMA_0) |
+ le32_encode_bits(mld_sma[1], DCTLINFO_V2_W8_MLD_SMA_1) |
+ le32_encode_bits(mld_sma[2], DCTLINFO_V2_W8_MLD_SMA_2) |
+ le32_encode_bits(mld_sma[3], DCTLINFO_V2_W8_MLD_SMA_3);
+ h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL);
+
+ h2c->w9 = le32_encode_bits(mld_sma[4], DCTLINFO_V2_W9_MLD_SMA_4) |
+ le32_encode_bits(mld_sma[5], DCTLINFO_V2_W9_MLD_SMA_5) |
+ le32_encode_bits(mld_tma[0], DCTLINFO_V2_W9_MLD_TMA_0) |
+ le32_encode_bits(mld_tma[1], DCTLINFO_V2_W9_MLD_TMA_1);
+ h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL);
+
+ h2c->w10 = le32_encode_bits(mld_tma[2], DCTLINFO_V2_W10_MLD_TMA_2) |
+ le32_encode_bits(mld_tma[3], DCTLINFO_V2_W10_MLD_TMA_3) |
+ le32_encode_bits(mld_tma[4], DCTLINFO_V2_W10_MLD_TMA_4) |
+ le32_encode_bits(mld_tma[5], DCTLINFO_V2_W10_MLD_TMA_5);
+ h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL);
+
+ h2c->w11 = le32_encode_bits(mld_bssid[0], DCTLINFO_V2_W11_MLD_BSSID_0) |
+ le32_encode_bits(mld_bssid[1], DCTLINFO_V2_W11_MLD_BSSID_1) |
+ le32_encode_bits(mld_bssid[2], DCTLINFO_V2_W11_MLD_BSSID_2) |
+ le32_encode_bits(mld_bssid[3], DCTLINFO_V2_W11_MLD_BSSID_3);
+ h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL);
+
+ h2c->w12 = le32_encode_bits(mld_bssid[4], DCTLINFO_V2_W12_MLD_BSSID_4) |
+ le32_encode_bits(mld_bssid[5], DCTLINFO_V2_W12_MLD_BSSID_5);
+ h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL);
}
diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h
index 5d7b624c2dd4..3134ebf08825 100644
--- a/drivers/net/wireless/realtek/rtw89/cam.h
+++ b/drivers/net/wireless/realtek/rtw89/cam.h
@@ -514,46 +514,58 @@ struct rtw89_h2c_dctlinfo_ud_v2 {
#define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16)
#define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24)
#define DCTLINFO_V2_W7_ALL GENMASK(31, 0)
-#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W8_MLD_SMA_0 GENMASK(7, 0)
+#define DCTLINFO_V2_W8_MLD_SMA_1 GENMASK(15, 8)
+#define DCTLINFO_V2_W8_MLD_SMA_2 GENMASK(23, 16)
+#define DCTLINFO_V2_W8_MLD_SMA_3 GENMASK(31, 24)
#define DCTLINFO_V2_W8_ALL GENMASK(31, 0)
-#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0)
-#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16)
+#define DCTLINFO_V2_W9_MLD_SMA_4 GENMASK(7, 0)
+#define DCTLINFO_V2_W9_MLD_SMA_5 GENMASK(15, 8)
+#define DCTLINFO_V2_W9_MLD_TMA_0 GENMASK(23, 16)
+#define DCTLINFO_V2_W9_MLD_TMA_1 GENMASK(31, 24)
#define DCTLINFO_V2_W9_ALL GENMASK(31, 0)
-#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W10_MLD_TMA_2 GENMASK(7, 0)
+#define DCTLINFO_V2_W10_MLD_TMA_3 GENMASK(15, 8)
+#define DCTLINFO_V2_W10_MLD_TMA_4 GENMASK(23, 16)
+#define DCTLINFO_V2_W10_MLD_TMA_5 GENMASK(31, 24)
#define DCTLINFO_V2_W10_ALL GENMASK(31, 0)
-#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W11_MLD_BSSID_0 GENMASK(7, 0)
+#define DCTLINFO_V2_W11_MLD_BSSID_1 GENMASK(15, 8)
+#define DCTLINFO_V2_W11_MLD_BSSID_2 GENMASK(23, 16)
+#define DCTLINFO_V2_W11_MLD_BSSID_3 GENMASK(31, 24)
#define DCTLINFO_V2_W11_ALL GENMASK(31, 0)
-#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0)
+#define DCTLINFO_V2_W12_MLD_BSSID_4 GENMASK(7, 0)
+#define DCTLINFO_V2_W12_MLD_BSSID_5 GENMASK(15, 8)
#define DCTLINFO_V2_W12_ALL GENMASK(15, 0)
-int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
-void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
+int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif);
+void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif);
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);
void rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev,
struct rtw89_addr_cam_entry *addr_cam);
int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct rtw89_bssid_cam_entry *bssid_cam,
const u8 *bssid);
void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev,
struct rtw89_bssid_cam_entry *bssid_cam);
void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
- struct rtw89_vif *vif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *vif,
+ struct rtw89_sta_link *rtwsta_link,
const u8 *scan_mac_addr, u8 *cmd);
void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
struct rtw89_h2c_dctlinfo_ud_v1 *h2c);
void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
struct rtw89_h2c_dctlinfo_ud_v2 *h2c);
int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta, u8 *cmd);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link, u8 *cmd);
int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -564,6 +576,6 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
struct ieee80211_key_conf *key,
bool inform_fw);
void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
+ struct rtw89_vif_link *rtwvif_link);
void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 7070c85e2c28..fb9449930c40 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -10,6 +10,10 @@
#include "ps.h"
#include "util.h"
+static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_idx idx1,
+ enum rtw89_chanctx_idx idx2);
+
static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
u8 center_chan)
{
@@ -226,14 +230,30 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev)
void rtw89_entity_init(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
hal->entity_pause = false;
bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX);
bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE);
+
+ INIT_LIST_HEAD(&mgnt->active_list);
+
rtw89_config_default_chandef(rtwdev);
}
+static bool rtw89_vif_is_active_role(struct rtw89_vif *rtwvif)
+{
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ if (rtwvif_link->chanctx_assigned)
+ return true;
+
+ return false;
+}
+
static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
struct rtw89_entity_weight *w)
{
@@ -255,11 +275,147 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
}
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- if (rtwvif->chanctx_assigned)
+ if (rtw89_vif_is_active_role(rtwvif))
w->active_roles++;
}
}
+static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct rtw89_vif_link *cur;
+
+ if (unlikely(!rtwvif_link->chanctx_assigned))
+ return;
+
+ cur = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (!cur || !cur->chanctx_assigned)
+ return;
+
+ if (cur == rtwvif_link)
+ return;
+
+ rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx);
+}
+
+const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
+ const char *caller_message,
+ u8 link_index)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
+ enum rtw89_chanctx_idx chanctx_idx;
+ enum rtw89_chanctx_idx roc_idx;
+ enum rtw89_entity_mode mode;
+ u8 role_index;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) {
+ WARN(1, "link index %u is invalid (max link inst num: %d)\n",
+ link_index, __RTW89_MLD_MAX_LINK_NUM);
+ goto dflt;
+ }
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_SCC_OR_SMLD:
+ case RTW89_ENTITY_MODE_MCC:
+ role_index = 0;
+ break;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ role_index = 1;
+ break;
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
+ goto dflt;
+ }
+
+ chanctx_idx = mgnt->chanctx_tbl[role_index][link_index];
+ if (chanctx_idx == RTW89_CHANCTX_IDLE)
+ goto dflt;
+
+ roc_idx = atomic_read(&hal->roc_chanctx_idx);
+ if (roc_idx != RTW89_CHANCTX_IDLE) {
+ /* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX).
+ * If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get
+ * the ongoing ROC chanctx.
+ */
+ if (link_index == RTW89_ROC_BY_LINK_INDEX)
+ chanctx_idx = roc_idx;
+ }
+
+ return rtw89_chan_get(rtwdev, chanctx_idx);
+
+dflt:
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "%s (%s): prefetch NULL on link index %u\n",
+ __func__, caller_message ?: "", link_index);
+
+ return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+}
+EXPORT_SYMBOL(__rtw89_mgnt_chan_get);
+
+static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
+ struct rtw89_vif_link *link;
+ struct rtw89_vif *role;
+ u8 pos = 0;
+ int i, j;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++)
+ mgnt->active_roles[i] = NULL;
+
+ for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) {
+ for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++)
+ mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE;
+ }
+
+ /* To be consistent with legacy behavior, expect the first active role
+ * which uses RTW89_CHANCTX_0 to put at position 0, and make its first
+ * link instance take RTW89_CHANCTX_0. (normalizing)
+ */
+ list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
+ for (i = 0; i < role->links_inst_valid_num; i++) {
+ link = rtw89_vif_get_link_inst(role, i);
+ if (!link || !link->chanctx_assigned)
+ continue;
+
+ if (link->chanctx_idx == RTW89_CHANCTX_0) {
+ rtw89_normalize_link_chanctx(rtwdev, link);
+
+ list_del(&role->mgnt_entry);
+ list_add(&role->mgnt_entry, &mgnt->active_list);
+ break;
+ }
+ }
+ }
+
+ list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
+ if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) {
+ rtw89_warn(rtwdev,
+ "%s: active roles are over max iface num\n",
+ __func__);
+ break;
+ }
+
+ for (i = 0; i < role->links_inst_valid_num; i++) {
+ link = rtw89_vif_get_link_inst(role, i);
+ if (!link || !link->chanctx_assigned)
+ continue;
+
+ mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
+ }
+
+ mgnt->active_roles[pos++] = role;
+ }
+}
+
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
{
DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {};
@@ -286,9 +442,14 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
set_bit(RTW89_CHANCTX_0, recalc_map);
fallthrough;
case 1:
- mode = RTW89_ENTITY_MODE_SCC;
+ mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
break;
case 2 ... NUM_OF_RTW89_CHANCTX:
+ if (w.active_roles == 1) {
+ mode = RTW89_ENTITY_MODE_SCC_OR_SMLD;
+ break;
+ }
+
if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"unhandled ent: %d chanctxs %d roles\n",
@@ -315,6 +476,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
rtw89_assign_entity_chan(rtwdev, idx, &chan);
}
+ rtw89_entity_recalc_mgnt_roles(rtwdev);
+
if (hal->entity_pause)
return rtw89_get_entity_mode(rtwdev);
@@ -387,9 +550,9 @@ int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev,
static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *role, u64 tsf)
{
- struct rtw89_vif *rtwvif = role->rtwvif;
+ struct rtw89_vif_link *rtwvif_link = role->rtwvif_link;
u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval);
- u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf);
+ u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);
u32 remainder;
if (tsf < sync_tsf) {
@@ -413,8 +576,8 @@ static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux
int ret;
req.group = mcc->group;
- req.macid_x = ref->rtwvif->mac_id;
- req.macid_y = aux->rtwvif->mac_id;
+ req.macid_x = ref->rtwvif_link->mac_id;
+ req.macid_y = aux->rtwvif_link->mac_id;
ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
@@ -440,10 +603,10 @@ static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux
BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
arg.num = 2;
- arg.infos[0].band = ref->rtwvif->mac_idx;
- arg.infos[0].port = ref->rtwvif->port;
- arg.infos[1].band = aux->rtwvif->mac_idx;
- arg.infos[1].port = aux->rtwvif->port;
+ arg.infos[0].band = ref->rtwvif_link->mac_idx;
+ arg.infos[0].port = ref->rtwvif_link->port;
+ arg.infos[1].band = aux->rtwvif_link->mac_idx;
+ arg.infos[1].port = aux->rtwvif_link->port;
ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt);
if (ret) {
@@ -522,23 +685,31 @@ out:
static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_mcc_role *mcc_role = data;
- struct rtw89_vif *target = mcc_role->rtwvif;
+ struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_sta_link *rtwsta_link;
if (rtwvif != target)
return;
- rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta->mac_id);
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link)) {
+ rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n");
+ return;
+ }
+
+ rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id);
}
static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *mcc_role)
{
- struct rtw89_vif *rtwvif = mcc_role->rtwvif;
+ struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
- rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif->mac_id);
+ rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif_link->mac_id);
ieee80211_iterate_stations_atomic(rtwdev->hw,
rtw89_mcc_role_macid_sta_iter,
mcc_role);
@@ -564,8 +735,9 @@ static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev,
static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *mcc_role)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(mcc_role->rtwvif);
+ struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link;
struct ieee80211_p2p_noa_desc *noa_desc;
+ struct ieee80211_bss_conf *bss_conf;
u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval);
u32 max_toa_us, max_tob_us, max_dur_us;
u32 start_time, interval, duration;
@@ -576,13 +748,18 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
if (!mcc_role->is_go && !mcc_role->is_gc)
return;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+
/* find the first periodic NoA */
for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
- noa_desc = &vif->bss_conf.p2p_noa_attr.desc[i];
+ noa_desc = &bss_conf->p2p_noa_attr.desc[i];
if (noa_desc->count == 255)
goto fill;
}
+ rcu_read_unlock();
return;
fill:
@@ -590,6 +767,8 @@ fill:
interval = le32_to_cpu(noa_desc->interval);
duration = le32_to_cpu(noa_desc->duration);
+ rcu_read_unlock();
+
if (interval != bcn_intvl_us) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC role limit: mismatch interval: %d vs. %d\n",
@@ -597,7 +776,7 @@ fill:
return;
}
- ret = rtw89_mac_port_get_tsf(rtwdev, mcc_role->rtwvif, &tsf);
+ ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
return;
@@ -632,15 +811,21 @@ fill:
}
static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct rtw89_mcc_role *role)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_bss_conf *bss_conf;
const struct rtw89_chan *chan;
memset(role, 0, sizeof(*role));
- role->rtwvif = rtwvif;
- role->beacon_interval = vif->bss_conf.beacon_int;
+ role->rtwvif_link = rtwvif_link;
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ role->beacon_interval = bss_conf->beacon_int;
+
+ rcu_read_unlock();
if (!role->beacon_interval) {
rtw89_warn(rtwdev,
@@ -650,10 +835,10 @@ static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
role->duration = role->beacon_interval / 2;
- chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
role->is_2ghz = chan->band_type == RTW89_BAND_2G;
- role->is_go = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
- role->is_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
+ role->is_go = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
+ role->is_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
rtw89_mcc_fill_role_macid_bitmap(rtwdev, role);
rtw89_mcc_fill_role_policy(rtwdev, role);
@@ -678,10 +863,11 @@ static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev)
}
struct rtw89_mcc_fill_role_selector {
- struct rtw89_vif *bind_vif[NUM_OF_RTW89_CHANCTX];
+ struct rtw89_vif_link *bind_vif[NUM_OF_RTW89_CHANCTX];
};
static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES);
+static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES);
static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *mcc_role,
@@ -689,7 +875,7 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
void *data)
{
struct rtw89_mcc_fill_role_selector *sel = data;
- struct rtw89_vif *role_vif = sel->bind_vif[ordered_idx];
+ struct rtw89_vif_link *role_vif = sel->bind_vif[ordered_idx];
int ret;
if (!role_vif) {
@@ -711,22 +897,26 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
struct rtw89_mcc_fill_role_selector sel = {};
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
int ret;
+ int i;
- rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- if (!rtwvif->chanctx_assigned)
- continue;
+ for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) {
+ rtwvif = mgnt->active_roles[i];
+ if (!rtwvif)
+ break;
- if (sel.bind_vif[rtwvif->chanctx_idx]) {
- rtw89_warn(rtwdev,
- "MCC skip extra vif <macid %d> on chanctx[%d]\n",
- rtwvif->mac_id, rtwvif->chanctx_idx);
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "mcc fill roles: find no link on HW-0\n");
continue;
}
- sel.bind_vif[rtwvif->chanctx_idx] = rtwvif;
+ sel.bind_vif[i] = rtwvif_link;
}
ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel);
@@ -754,13 +944,13 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) {
- pattern->courtesy.macid_tgt = aux->rtwvif->mac_id;
- pattern->courtesy.macid_src = ref->rtwvif->mac_id;
+ pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id;
+ pattern->courtesy.macid_src = ref->rtwvif_link->mac_id;
pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
pattern->courtesy.enable = true;
} else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) {
- pattern->courtesy.macid_tgt = ref->rtwvif->mac_id;
- pattern->courtesy.macid_src = aux->rtwvif->mac_id;
+ pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id;
+ pattern->courtesy.macid_src = aux->rtwvif_link->mac_id;
pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
pattern->courtesy.enable = true;
}
@@ -1263,7 +1453,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
u64 tsf_src;
int ret;
- ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif, &tsf_src);
+ ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src);
if (ret) {
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
return;
@@ -1280,12 +1470,12 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder);
tsf_ofst_tgt = bcn_intvl_src_us - remainder;
- config->sync.macid_tgt = tgt->rtwvif->mac_id;
- config->sync.band_tgt = tgt->rtwvif->mac_idx;
- config->sync.port_tgt = tgt->rtwvif->port;
- config->sync.macid_src = src->rtwvif->mac_id;
- config->sync.band_src = src->rtwvif->mac_idx;
- config->sync.port_src = src->rtwvif->port;
+ config->sync.macid_tgt = tgt->rtwvif_link->mac_id;
+ config->sync.band_tgt = tgt->rtwvif_link->mac_idx;
+ config->sync.port_tgt = tgt->rtwvif_link->port;
+ config->sync.macid_src = src->rtwvif_link->mac_id;
+ config->sync.band_src = src->rtwvif_link->mac_idx;
+ config->sync.port_src = src->rtwvif_link->port;
config->sync.offset = tsf_ofst_tgt / 1024;
config->sync.enable = true;
@@ -1294,7 +1484,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
config->sync.macid_tgt, config->sync.macid_src,
config->sync.offset);
- rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif, src->rtwvif,
+ rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link,
config->sync.offset);
}
@@ -1305,13 +1495,13 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
struct rtw89_mcc_config *config = &mcc->config;
u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
- struct rtw89_vif *rtwvif = ref->rtwvif;
+ struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link;
u64 tsf, start_tsf;
u32 cur_tbtt_ofst;
u64 min_time;
int ret;
- ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf);
+ ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
return ret;
@@ -1390,13 +1580,13 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro
const struct rtw89_chan *chan;
int ret;
- chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx);
+ chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
req.central_ch_seg0 = chan->channel;
req.primary_ch = chan->primary_channel;
req.bandwidth = chan->band_width;
req.ch_band_type = chan->band_type;
- req.macid = role->rtwvif->mac_id;
+ req.macid = role->rtwvif_link->mac_id;
req.group = mcc->group;
req.c2h_rpt = policy->c2h_rpt;
req.tx_null_early = policy->tx_null_early;
@@ -1421,7 +1611,7 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro
}
ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
- role->rtwvif->mac_id,
+ role->rtwvif_link->mac_id,
role->macid_bitmap);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
@@ -1448,7 +1638,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
slot_arg->duration = role->duration;
slot_arg->role_num = 1;
- chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx);
+ chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx);
slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
slot_arg->roles[0].is_master = role == ref;
@@ -1458,7 +1648,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
slot_arg->roles[0].primary_ch = chan->primary_channel;
slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
slot_arg->roles[0].null_early = policy->tx_null_early;
- slot_arg->roles[0].macid = role->rtwvif->mac_id;
+ slot_arg->roles[0].macid = role->rtwvif_link->mac_id;
slot_arg->roles[0].macid_main_bitmap =
rtw89_mcc_role_fw_macid_bitmap_to_u32(role);
}
@@ -1569,7 +1759,7 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
}
}
- req.macid = ref->rtwvif->mac_id;
+ req.macid = ref->rtwvif_link->mac_id;
req.tsf_high = config->start_tsf >> 32;
req.tsf_low = config->start_tsf;
@@ -1598,7 +1788,7 @@ static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
if (!courtesy->enable)
return;
- if (courtesy->macid_src == ref->rtwvif->mac_id) {
+ if (courtesy->macid_src == ref->rtwvif_link->mac_id) {
slot_arg_src = &arg->slots[ref->slot_idx];
slot_idx_tgt = aux->slot_idx;
} else {
@@ -1717,9 +1907,9 @@ static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_chang
struct rtw89_fw_mcc_duration req = {
.group = mcc->group,
.btc_in_group = false,
- .start_macid = ref->rtwvif->mac_id,
- .macid_x = ref->rtwvif->mac_id,
- .macid_y = aux->rtwvif->mac_id,
+ .start_macid = ref->rtwvif_link->mac_id,
+ .macid_x = ref->rtwvif_link->mac_id,
+ .macid_y = aux->rtwvif_link->mac_id,
.duration_x = ref->duration,
.duration_y = aux->duration,
.start_tsf_high = config->start_tsf >> 32,
@@ -1813,18 +2003,18 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
struct ieee80211_p2p_noa_desc noa_desc = {};
u64 start_time = config->start_tsf;
u32 interval = config->mcc_interval;
- struct rtw89_vif *rtwvif_go;
+ struct rtw89_vif_link *rtwvif_go;
u32 duration;
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
return;
if (ref->is_go) {
- rtwvif_go = ref->rtwvif;
+ rtwvif_go = ref->rtwvif_link;
start_time += ieee80211_tu_to_usec(ref->duration);
duration = config->mcc_interval - ref->duration;
} else if (aux->is_go) {
- rtwvif_go = aux->rtwvif;
+ rtwvif_go = aux->rtwvif_link;
start_time += ieee80211_tu_to_usec(pattern->tob_ref) +
ieee80211_tu_to_usec(config->beacon_offset) +
ieee80211_tu_to_usec(pattern->toa_aux);
@@ -1865,9 +2055,9 @@ static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev)
return;
if (ref->is_go)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, true);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, true);
else if (aux->is_go)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, true);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, true);
rtw89_mcc_handle_beacon_noa(rtwdev, true);
}
@@ -1882,9 +2072,9 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)
return;
if (ref->is_go)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, false);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, false);
else if (aux->is_go)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, false);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, false);
rtw89_mcc_handle_beacon_noa(rtwdev, false);
}
@@ -1942,7 +2132,7 @@ struct rtw89_mcc_stop_sel {
static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel,
const struct rtw89_mcc_role *mcc_role)
{
- sel->mac_id = mcc_role->rtwvif->mac_id;
+ sel->mac_id = mcc_role->rtwvif_link->mac_id;
sel->slot_idx = mcc_role->slot_idx;
}
@@ -1953,7 +2143,7 @@ static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,
{
struct rtw89_mcc_stop_sel *sel = data;
- if (!mcc_role->rtwvif->chanctx_assigned)
+ if (!mcc_role->rtwvif_link->chanctx_assigned)
return 0;
rtw89_mcc_stop_sel_fill(sel, mcc_role);
@@ -2081,7 +2271,7 @@ static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
int ret;
ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
- upd->rtwvif->mac_id,
+ upd->rtwvif_link->mac_id,
upd->macid_bitmap);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
@@ -2106,7 +2296,7 @@ static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
int i;
arg.sch_idx = mcc->group;
- arg.macid = upd->rtwvif->mac_id;
+ arg.macid = upd->rtwvif_link->mac_id;
for (i = 0; i < 32; i++) {
if (add & BIT(i)) {
@@ -2144,7 +2334,7 @@ static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
void *data)
{
struct rtw89_mcc_role upd = {
- .rtwvif = mcc_role->rtwvif,
+ .rtwvif_link = mcc_role->rtwvif_link,
};
int ret;
@@ -2370,6 +2560,24 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev)
rtw89_queue_chanctx_work(rtwdev);
}
+static void __rtw89_swap_chanctx(struct rtw89_vif *rtwvif,
+ enum rtw89_chanctx_idx idx1,
+ enum rtw89_chanctx_idx idx2)
+{
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ if (!rtwvif_link->chanctx_assigned)
+ continue;
+
+ if (rtwvif_link->chanctx_idx == idx1)
+ rtwvif_link->chanctx_idx = idx2;
+ else if (rtwvif_link->chanctx_idx == idx2)
+ rtwvif_link->chanctx_idx = idx1;
+ }
+}
+
static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_idx idx1,
enum rtw89_chanctx_idx idx2)
@@ -2386,14 +2594,8 @@ static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev,
swap(hal->chanctx[idx1], hal->chanctx[idx2]);
- rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- if (!rtwvif->chanctx_assigned)
- continue;
- if (rtwvif->chanctx_idx == idx1)
- rtwvif->chanctx_idx = idx2;
- else if (rtwvif->chanctx_idx == idx2)
- rtwvif->chanctx_idx = idx1;
- }
+ rtw89_for_each_rtwvif(rtwdev, rtwvif)
+ __rtw89_swap_chanctx(rtwvif, idx1, idx2);
cur = atomic_read(&hal->roc_chanctx_idx);
if (cur == idx1)
@@ -2444,16 +2646,22 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
}
int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct ieee80211_chanctx_conf *ctx)
{
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
struct rtw89_entity_weight w = {};
- rtwvif->chanctx_idx = cfg->idx;
- rtwvif->chanctx_assigned = true;
+ rtwvif_link->chanctx_idx = cfg->idx;
+ rtwvif_link->chanctx_assigned = true;
cfg->ref_count++;
+ if (list_empty(&rtwvif->mgnt_entry))
+ list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list);
+
if (cfg->idx == RTW89_CHANCTX_0)
goto out;
@@ -2469,20 +2677,24 @@ out:
}
void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct ieee80211_chanctx_conf *ctx)
{
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_hal *hal = &rtwdev->hal;
enum rtw89_chanctx_idx roll;
enum rtw89_entity_mode cur;
enum rtw89_entity_mode new;
int ret;
- rtwvif->chanctx_idx = RTW89_CHANCTX_0;
- rtwvif->chanctx_assigned = false;
+ rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;
+ rtwvif_link->chanctx_assigned = false;
cfg->ref_count--;
+ if (!rtw89_vif_is_active_role(rtwvif))
+ list_del_init(&rtwvif->mgnt_entry);
+
if (cfg->ref_count != 0)
goto out;
diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h
index c6d31984e575..2eb31dff2083 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.h
+++ b/drivers/net/wireless/realtek/rtw89/chan.h
@@ -43,18 +43,21 @@ struct rtw89_entity_weight {
unsigned int active_roles;
};
-static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev)
+static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
struct rtw89_hal *hal = &rtwdev->hal;
- return READ_ONCE(hal->entity_active);
+ return READ_ONCE(hal->entity_active[phy_idx]);
}
-static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev, bool active)
+static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ bool active)
{
struct rtw89_hal *hal = &rtwdev->hal;
- WRITE_ONCE(hal->entity_active, active);
+ WRITE_ONCE(hal->entity_active[phy_idx], active);
}
static inline
@@ -98,6 +101,14 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev);
void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_pause_reasons rsn);
void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev);
+
+const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
+ const char *caller_message,
+ u8 link_index);
+
+#define rtw89_mgnt_chan_get(rtwdev, link_index) \
+ __rtw89_mgnt_chan_get(rtwdev, __func__, link_index)
+
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx);
void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
@@ -106,10 +117,10 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx,
u32 changed);
int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct ieee80211_chanctx_conf *ctx);
void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct ieee80211_chanctx_conf *ctx);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index df51b29142aa..68316d44b204 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -125,6 +125,9 @@ static const u32 cxtbl[] = {
0xfafaaafa, /* 23 */
0xfafffaff, /* 24 */
0xea6a5a5a, /* 25 */
+ 0xfaff5aff, /* 26 */
+ 0xffffdfff, /* 27 */
+ 0xe6555555, /* 28 */
};
static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
@@ -134,77 +137,88 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7,
.fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7,
.fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7,
- .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6,
+ .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
+ .max_role_num = 6,
},
{RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0),
.fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7,
.fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7,
.fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7,
.fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7,
- .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6,
+ .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800,
+ .max_role_num = 6,
},
{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
.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 = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
+ .max_role_num = 6,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
+ .max_role_num = 5,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
+ .max_role_num = 5,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
+ .max_role_num = 5,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0),
.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 = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
+ .max_role_num = 6,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
.fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
+ .max_role_num = 6,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
+ .max_role_num = 5,
},
{RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
.fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280,
+ .max_role_num = 5,
},
{RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0),
.fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2,
.fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
.fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024,
+ .max_role_num = 5,
},
/* keep it to be the last as default entry */
@@ -213,7 +227,8 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
.fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0,
- .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024,
+ .max_role_num = 5,
},
};
@@ -224,7 +239,7 @@ static const union rtw89_btc_wl_state_map btc_scanning_map = {
.scan = 1,
.connecting = 1,
.roaming = 1,
- .transacting = 1,
+ .dbccing = 1,
._4way = 1,
},
};
@@ -2492,6 +2507,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
if (ver->fcxmreg == 7) {
sz = struct_size(v7, regs, n);
v7 = kmalloc(sz, GFP_KERNEL);
+ if (!v7)
+ return;
v7->type = RPT_EN_MREG;
v7->fver = ver->fcxmreg;
v7->len = n;
@@ -2506,6 +2523,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
} else {
sz = struct_size(v1, regs, n);
v1 = kmalloc(sz, GFP_KERNEL);
+ if (!v1)
+ return;
v1->fver = ver->fcxmreg;
v1->reg_num = n;
memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n));
@@ -3017,7 +3036,7 @@ static void _update_btc_state_map(struct rtw89_dev *rtwdev)
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
if (wl->status.map.connecting || wl->status.map._4way ||
- wl->status.map.roaming) {
+ wl->status.map.roaming || wl->status.map.dbccing) {
cx->state_map = BTC_WLINKING;
} else if (wl->status.map.scan) { /* wl scan */
if (bt_linfo->status.map.inq_pag)
@@ -3680,6 +3699,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1;
+ struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc;
struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc;
struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
@@ -3721,8 +3741,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
tbl_w1 = cxtbl[16];
}
- btc->bt_req_en = false;
-
switch (type) {
case BTC_CXP_USERDEF0:
btc->update_policy_force = true;
@@ -3744,6 +3762,10 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
case BTC_CXP_OFF_WL:
_slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
break;
+ case BTC_CXP_OFF_WL2:
+ _slot_set_tbl(btc, CXST_OFF, cxtbl[1]);
+ _slot_set_type(btc, CXST_OFF, SLOT_ISO);
+ break;
case BTC_CXP_OFF_EQ0:
_slot_set_tbl(btc, CXST_OFF, cxtbl[0]);
_slot_set_type(btc, CXST_OFF, SLOT_ISO);
@@ -3757,6 +3779,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
case BTC_CXP_OFF_EQ3:
_slot_set_tbl(btc, CXST_OFF, cxtbl[24]);
break;
+ case BTC_CXP_OFF_EQ4:
+ _slot_set_tbl(btc, CXST_OFF, cxtbl[26]);
+ break;
+ case BTC_CXP_OFF_EQ5:
+ _slot_set_tbl(btc, CXST_OFF, cxtbl[27]);
+ break;
case BTC_CXP_OFF_BWB0:
_slot_set_tbl(btc, CXST_OFF, cxtbl[5]);
break;
@@ -3788,7 +3816,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
}
break;
case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */
- btc->bt_req_en = true;
_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
*t = t_def[CXTD_OFF_EXT];
@@ -3831,9 +3858,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
break;
case BTC_CXP_OFFE_2GBWMIXB:
- _slot_set(btc, CXST_E2G, 0, 0x55555555, SLOT_MIX);
+ if (a2dp->exist)
+ _slot_set(btc, CXST_E2G, 0, cxtbl[2], SLOT_MIX);
+ else
+ _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_MIX);
_slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
- cpu_to_le32(0x55555555), s_def[CXST_EBT].cxtype);
+ s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
break;
case BTC_CXP_OFFE_WL: /* for 4-way */
_slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX);
@@ -3842,6 +3872,8 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
default:
break;
}
+ _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
+ s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
_slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
break;
@@ -4246,6 +4278,7 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
_set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE);
break;
case BTC_ANT_WRFK:
+ case BTC_ANT_WRFK2:
rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL);
_set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO);
_set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE);
@@ -4623,12 +4656,21 @@ static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev)
static void _action_bt_pan(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_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
+ struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
switch (btc->cx.state_map) {
case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */
- _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
+ if (a2dp.active || !pan.exist) {
+ btc->dm.slot_dur[CXST_W1] = 80;
+ btc->dm.slot_dur[CXST_B1] = 20;
+ _set_policy(rtwdev, BTC_CXP_PFIX_TDW1B1, BTC_ACT_BT_PAN);
+ } else {
+ _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN);
+ }
break;
case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */
_set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN);
@@ -4814,8 +4856,16 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev)
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n",
__func__, rfk.band);
- _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
- _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
+ btc->dm.tdma_instant_excute = 1;
+
+ if (rfk.state == BTC_WRFK_ONESHOT_START ||
+ btc->ant_type == BTC_ANT_SHARED) {
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK2);
+ _set_policy(rtwdev, BTC_CXP_OFF_WL2, BTC_ACT_WL_RFK);
+ } else {
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK);
+ _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK);
+ }
}
static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
@@ -4855,6 +4905,8 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
if (rtwdev->dbcc_en) {
if (ver->fwlrole == 0) {
+ wl_rinfo.dbcc_2g_phy = RTW89_PHY_MAX;
+
for (i = 0; i < RTW89_PHY_MAX; i++) {
if (wl_dinfo->real_band[i] == RTW89_BAND_2G)
wl_rinfo.dbcc_2g_phy = i;
@@ -4989,18 +5041,16 @@ struct rtw89_txtime_data {
bool reenable;
};
-static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
+static void __rtw89_tx_time_iter(struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct rtw89_txtime_data *iter_data)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_txtime_data *iter_data =
- (struct rtw89_txtime_data *)data;
struct rtw89_dev *rtwdev = iter_data->rtwdev;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &cx->wl;
struct rtw89_btc_wl_link_info *plink = NULL;
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
u32 tx_time = iter_data->tx_time;
u8 tx_retry = iter_data->tx_retry;
u16 enable = iter_data->enable;
@@ -5023,8 +5073,8 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
/* backup the original tx time before tx-limit on */
if (reenable) {
- rtw89_mac_get_tx_time(rtwdev, rtwsta, &plink->tx_time);
- rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta, &plink->tx_retry);
+ rtw89_mac_get_tx_time(rtwdev, rtwsta_link, &plink->tx_time);
+ rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, &plink->tx_retry);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n",
__func__, plink->tx_time, plink->tx_retry);
@@ -5032,22 +5082,37 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
/* restore the original tx time if no tx-limit */
if (!enable) {
- rtw89_mac_set_tx_time(rtwdev, rtwsta, true, plink->tx_time);
- rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, true,
+ rtw89_mac_set_tx_time(rtwdev, rtwsta_link, true, plink->tx_time);
+ rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, true,
plink->tx_retry);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): restore, tx_time=%d tx_retry= %d\n",
__func__, plink->tx_time, plink->tx_retry);
} else {
- rtw89_mac_set_tx_time(rtwdev, rtwsta, false, tx_time);
- rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, false, tx_retry);
+ rtw89_mac_set_tx_time(rtwdev, rtwsta_link, false, tx_time);
+ rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, tx_retry);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): set, tx_time=%d tx_retry= %d\n",
__func__, tx_time, tx_retry);
}
}
+static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_txtime_data *iter_data =
+ (struct rtw89_txtime_data *)data;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ __rtw89_tx_time_iter(rtwvif_link, rtwsta_link, iter_data);
+ }
+}
+
static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -5231,8 +5296,14 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc;
struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc;
struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc;
+ struct rtw89_btc_dm *dm = &btc->dm;
u8 profile_map = 0;
+ if (dm->freerun_chk) {
+ _action_freerun(rtwdev);
+ return;
+ }
+
if (bt_linfo->hfp_desc.exist)
profile_map |= BTC_BT_HFP;
@@ -5247,30 +5318,20 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
switch (profile_map) {
case BTC_BT_NOPROFILE:
- if (_check_freerun(rtwdev))
- _action_freerun(rtwdev);
- else if (pan.active)
+ if (pan.active)
_action_bt_pan(rtwdev);
else
_action_bt_idle(rtwdev);
break;
case BTC_BT_HFP:
- if (_check_freerun(rtwdev))
- _action_freerun(rtwdev);
- else
- _action_bt_hfp(rtwdev);
+ _action_bt_hfp(rtwdev);
break;
case BTC_BT_HFP | BTC_BT_HID:
case BTC_BT_HID:
- if (_check_freerun(rtwdev))
- _action_freerun(rtwdev);
- else
- _action_bt_hid(rtwdev);
+ _action_bt_hid(rtwdev);
break;
case BTC_BT_A2DP:
- if (_check_freerun(rtwdev))
- _action_freerun(rtwdev);
- else if (a2dp.sink)
+ if (a2dp.sink)
_action_bt_a2dpsink(rtwdev);
else if (bt_linfo->multi_link.now && !hid.pair_cnt)
_action_bt_a2dp_pan(rtwdev);
@@ -5283,13 +5344,18 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
case BTC_BT_A2DP | BTC_BT_HFP:
case BTC_BT_A2DP | BTC_BT_HID:
case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID:
- if (_check_freerun(rtwdev))
- _action_freerun(rtwdev);
+ if (a2dp.sink)
+ _action_bt_a2dpsink(rtwdev);
+ else if (pan.active)
+ _action_bt_a2dp_pan_hid(rtwdev);
else
_action_bt_a2dp_hid(rtwdev);
break;
case BTC_BT_A2DP | BTC_BT_PAN:
- _action_bt_a2dp_pan(rtwdev);
+ if (a2dp.sink)
+ _action_bt_a2dpsink(rtwdev);
+ else
+ _action_bt_a2dp_pan(rtwdev);
break;
case BTC_BT_PAN | BTC_BT_HFP:
case BTC_BT_PAN | BTC_BT_HID:
@@ -5299,7 +5365,10 @@ static void _action_by_bt(struct rtw89_dev *rtwdev)
case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID:
case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP:
default:
- _action_bt_a2dp_pan_hid(rtwdev);
+ if (a2dp.sink)
+ _action_bt_a2dpsink(rtwdev);
+ else
+ _action_bt_a2dp_pan_hid(rtwdev);
break;
}
}
@@ -5319,7 +5388,7 @@ static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
policy_type = BTC_CXP_OFFE_WL;
else if (btc->cx.wl.status.val & btc_scanning_map.val)
policy_type = BTC_CXP_OFFE_2GBWMIXB;
- else if (btc->cx.bt.link_info.profile_cnt.now == 0)
+ else if (btc->cx.bt.link_info.status.map.connect == 0)
policy_type = BTC_CXP_OFFE_2GISOB;
else
policy_type = BTC_CXP_OFFE_2GBWISOB;
@@ -6445,6 +6514,8 @@ static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid)
/* todo DBCC related event */
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] wl_info phy_now=%d\n", phy_now);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC] rlink cnt_2g=%d cnt_5g=%d\n", cnt_2g, cnt_5g);
if (wl_rinfo->dbcc_en != rtwdev->dbcc_en) {
wl_rinfo->dbcc_chg = 1;
@@ -6891,6 +6962,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
bt->scan_rx_low_pri = false;
igno_bt = false;
+ dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */
+
if (always_freerun) {
_action_freerun(rtwdev);
igno_bt = true;
@@ -6929,18 +7002,9 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
goto exit;
}
- if (cx->state_map == BTC_WLINKING) {
- 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) {
+ if (wl->status.val & btc_scanning_map.val) {
_action_wl_scan(rtwdev);
- bt->scan_rx_low_pri = false;
+ bt->scan_rx_low_pri = true;
goto exit;
}
@@ -7176,10 +7240,6 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
- wl->scan_info.band[phy_idx] = band;
- wl->scan_info.phy_map |= BIT(phy_idx);
- _fw_set_drv_info(rtwdev, CXDRVINFO_SCAN);
-
if (rtwdev->dbcc_en) {
wl->dbcc_info.scan_band[phy_idx] = band;
_update_dbcc_band(rtwdev, phy_idx);
@@ -7374,13 +7434,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
"[BTC], %s(): bt_info[2]=0x%02x\n",
__func__, bt->raw_info[2]);
- /* reset to mo-connect before update */
- b->status.val = BTC_BLINK_NOCONNECT;
b->profile_cnt.last = b->profile_cnt.now;
- b->relink.last = b->relink.now;
- a2dp->exist_last = a2dp->exist;
- b->multi_link.last = b->multi_link.now;
- bt->inq_pag.last = bt->inq_pag.now;
b->profile_cnt.now = 0;
hid->type = 0;
@@ -7399,7 +7453,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
b->profile_cnt.now += (u8)hid->exist;
a2dp->exist = btinfo.lb2.a2dp;
b->profile_cnt.now += (u8)a2dp->exist;
- pan->active = btinfo.lb2.pan;
+ pan->exist = btinfo.lb2.pan;
+ b->profile_cnt.now += (u8)pan->exist;
btc->dm.trx_info.bt_profile = u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK);
/* parse raw info low-Byte3 */
@@ -7423,8 +7478,14 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
/* parse raw info high-Byte1 */
btinfo.val = bt->raw_info[BTC_BTINFO_H1];
b->status.map.ble_connect = btinfo.hb1.ble_connect;
- if (btinfo.hb1.ble_connect)
- hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU);
+ if (btinfo.hb1.ble_connect) {
+ if (hid->exist)
+ hid->type |= BTC_HID_BLE;
+ else if (btinfo.hb1.voice)
+ hid->type |= BTC_HID_RCU_VOICE;
+ else
+ hid->type |= BTC_HID_RCU;
+ }
cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit);
bt->reinit = btinfo.hb1.reinit;
@@ -7436,7 +7497,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
if (bt->igno_wl && !cx->wl.status.map.rf_off)
_set_bt_ignore_wlan_act(rtwdev, false);
- hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0);
bt->ble_scan_en = btinfo.hb1.ble_scan;
cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw);
@@ -7446,8 +7506,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
/* parse raw info high-Byte2 */
btinfo.val = bt->raw_info[BTC_BTINFO_H2];
- pan->exist = btinfo.hb2.pan_active;
- b->profile_cnt.now += (u8)pan->exist;
+ pan->active = !!btinfo.hb2.pan_active;
cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update);
b->afh_update = btinfo.hb2.afh_update;
@@ -7455,8 +7514,9 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
b->slave_role = btinfo.hb2.slave;
hid->slot_info = btinfo.hb2.hid_slot;
hid->pair_cnt = btinfo.hb2.hid_cnt;
- hid->type |= (hid->slot_info == BTC_HID_218 ?
- BTC_HID_218 : BTC_HID_418);
+ if (!b->status.map.ble_connect || hid->pair_cnt > 1)
+ hid->type |= (hid->slot_info == BTC_HID_218 ?
+ BTC_HID_218 : BTC_HID_418);
/* parse raw info high-Byte3 */
btinfo.val = bt->raw_info[BTC_BTINFO_H3];
a2dp->bitpool = btinfo.hb3.a2dp_bitpool;
@@ -7479,13 +7539,16 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
}
-void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta, enum btc_role_state state)
+void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ enum btc_role_state state)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
+ rtwvif_link->chanctx_idx);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct ieee80211_bss_conf *bss_conf;
+ struct ieee80211_link_sta *link_sta;
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
@@ -7493,51 +7556,59 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
struct rtw89_btc_wl_link_info *wlinfo = NULL;
u8 mode = 0, rlink_id, link_mode_ori, pta_req_mac_ori, wa_type;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], role is STA=%d\n",
vif->type == NL80211_IFTYPE_STATION);
- rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif_link->port);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n",
chan->band_type, chan->channel, chan->band_width);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n",
state == BTC_ROLE_MSTS_STA_CONN_END);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], bcn_period=%d dtim_period=%d\n",
- vif->bss_conf.beacon_int, vif->bss_conf.dtim_period);
+ bss_conf->beacon_int, bss_conf->dtim_period);
+
+ if (rtwsta_link) {
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
- if (rtwsta) {
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n",
- rtwsta->mac_id);
+ rtwsta_link->mac_id);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], STA support HE=%d VHT=%d HT=%d\n",
- sta->deflink.he_cap.has_he,
- sta->deflink.vht_cap.vht_supported,
- sta->deflink.ht_cap.ht_supported);
- if (sta->deflink.he_cap.has_he)
+ link_sta->he_cap.has_he,
+ link_sta->vht_cap.vht_supported,
+ link_sta->ht_cap.ht_supported);
+ if (link_sta->he_cap.has_he)
mode |= BIT(BTC_WL_MODE_HE);
- if (sta->deflink.vht_cap.vht_supported)
+ if (link_sta->vht_cap.vht_supported)
mode |= BIT(BTC_WL_MODE_VHT);
- if (sta->deflink.ht_cap.ht_supported)
+ if (link_sta->ht_cap.ht_supported)
mode |= BIT(BTC_WL_MODE_HT);
r.mode = mode;
}
- if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX)
+ if (rtwvif_link->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) {
+ rcu_read_unlock();
return;
+ }
rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], wifi_role=%d\n", rtwvif->wifi_role);
+ "[BTC], wifi_role=%d\n", rtwvif_link->wifi_role);
- r.role = rtwvif->wifi_role;
- r.phy = rtwvif->phy_idx;
- r.pid = rtwvif->port;
+ r.role = rtwvif_link->wifi_role;
+ r.phy = rtwvif_link->phy_idx;
+ r.pid = rtwvif_link->port;
r.active = true;
r.connected = MLME_LINKED;
- r.bcn_period = vif->bss_conf.beacon_int;
- r.dtim_period = vif->bss_conf.dtim_period;
+ r.bcn_period = bss_conf->beacon_int;
+ r.dtim_period = bss_conf->dtim_period;
r.band = chan->band_type;
r.ch = chan->channel;
r.bw = chan->band_width;
@@ -7545,10 +7616,12 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
r.chdef.center_ch = chan->channel;
r.chdef.bw = chan->band_width;
r.chdef.chan = chan->primary_channel;
- ether_addr_copy(r.mac_addr, rtwvif->mac_addr);
+ ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr);
+
+ rcu_read_unlock();
- if (rtwsta && vif->type == NL80211_IFTYPE_STATION)
- r.mac_id = rtwsta->mac_id;
+ if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION)
+ r.mac_id = rtwsta_link->mac_id;
btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++;
@@ -7779,26 +7852,26 @@ struct rtw89_btc_wl_sta_iter_data {
bool is_traffic_change;
};
-static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
+static
+void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct rtw89_btc_wl_sta_iter_data *iter_data)
{
- struct rtw89_btc_wl_sta_iter_data *iter_data =
- (struct rtw89_btc_wl_sta_iter_data *)data;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_dev *rtwdev = iter_data->rtwdev;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_wl_link_info *link_info = NULL;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
struct rtw89_traffic_stats *link_info_t = NULL;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_traffic_stats *stats = &rtwvif->stats;
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc_wl_role_info *r;
struct rtw89_btc_wl_role_info_v1 *r1;
u32 last_tx_rate, last_rx_rate;
u16 last_tx_lvl, last_rx_lvl;
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
u8 rssi;
u8 busy = 0;
u8 dir = 0;
@@ -7806,11 +7879,11 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
u8 i = 0;
bool is_sta_change = false, is_traffic_change = false;
- rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
+ rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi);
link_info = &wl->link_info[port];
- link_info->stat.traffic = rtwvif->stats;
+ link_info->stat.traffic = *stats;
link_info_t = &link_info->stat.traffic;
if (link_info->connected == MLME_NO_LINK) {
@@ -7858,19 +7931,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
iter_data->busy_all |= busy;
iter_data->dir_all |= BIT(dir);
- if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
+ if (rtwsta_link->rx_hw_rate <= RTW89_HW_RATE_CCK2 &&
last_rx_rate > RTW89_HW_RATE_CCK2 &&
link_info_t->rx_tfc_lv > RTW89_TFC_IDLE)
link_info->rx_rate_drop_cnt++;
- if (last_tx_rate != rtwsta->ra_report.hw_rate ||
- last_rx_rate != rtwsta->rx_hw_rate ||
+ if (last_tx_rate != rtwsta_link->ra_report.hw_rate ||
+ last_rx_rate != rtwsta_link->rx_hw_rate ||
last_tx_lvl != link_info_t->tx_tfc_lv ||
last_rx_lvl != link_info_t->rx_tfc_lv)
is_traffic_change = true;
- link_info_t->tx_rate = rtwsta->ra_report.hw_rate;
- link_info_t->rx_rate = rtwsta->rx_hw_rate;
+ link_info_t->tx_rate = rtwsta_link->ra_report.hw_rate;
+ link_info_t->rx_rate = rtwsta_link->rx_hw_rate;
if (link_info->role == RTW89_WIFI_ROLE_STATION ||
link_info->role == RTW89_WIFI_ROLE_P2P_CLIENT) {
@@ -7882,19 +7955,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
r = &wl->role_info;
r->active_role[port].tx_lvl = stats->tx_tfc_lv;
r->active_role[port].rx_lvl = stats->rx_tfc_lv;
- r->active_role[port].tx_rate = rtwsta->ra_report.hw_rate;
- r->active_role[port].rx_rate = rtwsta->rx_hw_rate;
+ r->active_role[port].tx_rate = rtwsta_link->ra_report.hw_rate;
+ r->active_role[port].rx_rate = rtwsta_link->rx_hw_rate;
} else if (ver->fwlrole == 1) {
r1 = &wl->role_info_v1;
r1->active_role_v1[port].tx_lvl = stats->tx_tfc_lv;
r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv;
- r1->active_role_v1[port].tx_rate = rtwsta->ra_report.hw_rate;
- r1->active_role_v1[port].rx_rate = rtwsta->rx_hw_rate;
+ r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate;
+ r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate;
} else if (ver->fwlrole == 2) {
dm->trx_info.tx_lvl = stats->tx_tfc_lv;
dm->trx_info.rx_lvl = stats->rx_tfc_lv;
- dm->trx_info.tx_rate = rtwsta->ra_report.hw_rate;
- dm->trx_info.rx_rate = rtwsta->rx_hw_rate;
+ dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate;
+ dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate;
}
dm->trx_info.tx_tp = link_info_t->tx_throughput;
@@ -7914,6 +7987,21 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
iter_data->is_traffic_change = true;
}
+static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_btc_wl_sta_iter_data *iter_data =
+ (struct rtw89_btc_wl_sta_iter_data *)data;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ __rtw89_btc_ntfy_wl_sta_iter(rtwvif_link, rtwsta_link, iter_data);
+ }
+}
+
#define BTC_NHM_CHK_INTVL 20
void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
@@ -7963,6 +8051,53 @@ void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev)
}
}
+static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
+
+ switch (func) {
+ case BTF_EVNT_RPT:
+ case BTF_EVNT_BT_INFO:
+ case BTF_EVNT_BT_SCBD:
+ case BTF_EVNT_BT_REG:
+ case BTF_EVNT_CX_RUNINFO:
+ case BTF_EVNT_BT_PSD:
+ return func;
+ case BTF_EVNT_BT_DEV_INFO:
+ if (ver->fwc2hfunc == 0)
+ return BTF_EVNT_BUF_OVERFLOW;
+ else
+ return BTF_EVNT_BT_DEV_INFO;
+ case BTF_EVNT_BT_LEAUDIO_INFO:
+ if (ver->fwc2hfunc == 0)
+ return BTF_EVNT_C2H_LOOPBACK;
+ else if (ver->fwc2hfunc == 1)
+ return BTF_EVNT_BUF_OVERFLOW;
+ else if (ver->fwc2hfunc == 2)
+ return func;
+ else
+ return BTF_EVNT_MAX;
+ case BTF_EVNT_BUF_OVERFLOW:
+ if (ver->fwc2hfunc == 0)
+ return BTF_EVNT_MAX;
+ else if (ver->fwc2hfunc == 1)
+ return BTF_EVNT_C2H_LOOPBACK;
+ else if (ver->fwc2hfunc == 2)
+ return func;
+ else
+ return BTF_EVNT_MAX;
+ case BTF_EVNT_C2H_LOOPBACK:
+ if (ver->fwc2hfunc == 2)
+ return func;
+ else
+ return BTF_EVNT_MAX;
+ case BTF_EVNT_MAX:
+ default:
+ return BTF_EVNT_MAX;
+ }
+}
+
void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func)
{
@@ -7979,10 +8114,14 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (class != BTFC_FW_EVENT)
return;
+ func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func);
+
switch (func) {
- case BTF_EVNT_RPT:
case BTF_EVNT_BUF_OVERFLOW:
pfwinfo->event[func]++;
+ break;
+ case BTF_EVNT_RPT:
+ pfwinfo->event[func]++;
/* Don't need rtw89_leave_ps_mode() */
btc_fw_event(rtwdev, func, buf, len);
break;
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index de53b56632f7..dbdb56e063ef 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -271,8 +271,10 @@ void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work);
void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work);
void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work);
void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work);
-void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta, enum btc_role_state state);
+void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ enum btc_role_state state);
void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state);
void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map,
enum btc_wl_rfk_type type,
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 4553810634c6..e5b2968c1431 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -192,13 +192,13 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
{
.limits = rtw89_iface_limits,
.n_limits = ARRAY_SIZE(rtw89_iface_limits),
- .max_interfaces = 2,
+ .max_interfaces = RTW89_MAX_INTERFACE_NUM,
.num_different_channels = 1,
},
{
.limits = rtw89_iface_limits_mcc,
.n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc),
- .max_interfaces = 2,
+ .max_interfaces = RTW89_MAX_INTERFACE_NUM,
.num_different_channels = 2,
},
};
@@ -341,83 +341,47 @@ void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
rtw89_chan_create(chan, center_chan, channel->hw_value, band, bandwidth);
}
-void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
+static void __rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
{
- struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_chan *chan;
- enum rtw89_chanctx_idx chanctx_idx;
- enum rtw89_chanctx_idx roc_idx;
- enum rtw89_phy_idx phy_idx;
- enum rtw89_entity_mode mode;
bool entity_active;
- entity_active = rtw89_get_entity_state(rtwdev);
+ entity_active = rtw89_get_entity_state(rtwdev, phy_idx);
if (!entity_active)
return;
- mode = rtw89_get_entity_mode(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_SCC:
- case RTW89_ENTITY_MODE_MCC:
- chanctx_idx = RTW89_CHANCTX_0;
- break;
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- chanctx_idx = RTW89_CHANCTX_1;
- break;
- default:
- WARN(1, "Invalid ent mode: %d\n", mode);
- return;
- }
+ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
+}
- roc_idx = atomic_read(&hal->roc_chanctx_idx);
- if (roc_idx != RTW89_CHANCTX_IDLE)
- chanctx_idx = roc_idx;
+void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan;
- phy_idx = RTW89_PHY_0;
- chan = rtw89_chan_get(rtwdev, chanctx_idx);
- chip->ops->set_txpwr(rtwdev, chan, phy_idx);
+ chan = rtw89_mgnt_chan_get(rtwdev, 0);
+ __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_0);
+
+ if (!rtwdev->support_mlo)
+ return;
+
+ chan = rtw89_mgnt_chan_get(rtwdev, 1);
+ __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1);
}
-int rtw89_set_channel(struct rtw89_dev *rtwdev)
+static void __rtw89_set_channel(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
{
- struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_chan_rcd *chan_rcd;
- const struct rtw89_chan *chan;
- enum rtw89_chanctx_idx chanctx_idx;
- enum rtw89_chanctx_idx roc_idx;
- enum rtw89_mac_idx mac_idx;
- enum rtw89_phy_idx phy_idx;
struct rtw89_channel_help_params bak;
- enum rtw89_entity_mode mode;
bool entity_active;
- entity_active = rtw89_get_entity_state(rtwdev);
-
- mode = rtw89_entity_recalc(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_SCC:
- case RTW89_ENTITY_MODE_MCC:
- chanctx_idx = RTW89_CHANCTX_0;
- break;
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- chanctx_idx = RTW89_CHANCTX_1;
- break;
- default:
- WARN(1, "Invalid ent mode: %d\n", mode);
- return -EINVAL;
- }
-
- roc_idx = atomic_read(&hal->roc_chanctx_idx);
- if (roc_idx != RTW89_CHANCTX_IDLE)
- chanctx_idx = roc_idx;
+ entity_active = rtw89_get_entity_state(rtwdev, phy_idx);
- mac_idx = RTW89_MAC_0;
- phy_idx = RTW89_PHY_0;
-
- chan = rtw89_chan_get(rtwdev, chanctx_idx);
- chan_rcd = rtw89_chan_rcd_get(rtwdev, chanctx_idx);
+ chan_rcd = rtw89_chan_rcd_get_by_chan(chan);
rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx);
@@ -432,17 +396,30 @@ int rtw89_set_channel(struct rtw89_dev *rtwdev)
rtw89_chip_rfk_band_changed(rtwdev, phy_idx, chan);
}
- rtw89_set_entity_state(rtwdev, true);
- return 0;
+ rtw89_set_entity_state(rtwdev, phy_idx, true);
}
-void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_chan *chan)
+int rtw89_set_channel(struct rtw89_dev *rtwdev)
{
- const struct cfg80211_chan_def *chandef;
+ const struct rtw89_chan *chan;
+ enum rtw89_entity_mode mode;
+
+ mode = rtw89_entity_recalc(rtwdev);
+ if (mode < 0 || mode >= NUM_OF_RTW89_ENTITY_MODE) {
+ WARN(1, "Invalid ent mode: %d\n", mode);
+ return -EINVAL;
+ }
+
+ chan = rtw89_mgnt_chan_get(rtwdev, 0);
+ __rtw89_set_channel(rtwdev, chan, RTW89_MAC_0, RTW89_PHY_0);
+
+ if (!rtwdev->support_mlo)
+ return 0;
+
+ chan = rtw89_mgnt_chan_get(rtwdev, 1);
+ __rtw89_set_channel(rtwdev, chan, RTW89_MAC_1, RTW89_PHY_1);
- chandef = rtw89_chandef_get(rtwdev, rtwvif->chanctx_idx);
- rtw89_get_channel_params(chandef, chan);
+ return 0;
}
static enum rtw89_core_tx_type
@@ -463,8 +440,9 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req,
enum btc_pkt_type pkt_type)
{
- struct ieee80211_sta *sta = tx_req->sta;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
+ struct ieee80211_link_sta *link_sta;
struct sk_buff *skb = tx_req->skb;
struct rtw89_sta *rtwsta;
u8 ampdu_num;
@@ -478,21 +456,26 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
if (!(IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU))
return;
- if (!sta) {
+ if (!rtwsta_link) {
rtw89_warn(rtwdev, "cannot set ampdu info without sta\n");
return;
}
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ rtwsta = rtwsta_link->rtwsta;
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
ampdu_num = (u8)((rtwsta->ampdu_params[tid].agg_num ?
rtwsta->ampdu_params[tid].agg_num :
- 4 << sta->deflink.ht_cap.ampdu_factor) - 1);
+ 4 << link_sta->ht_cap.ampdu_factor) - 1);
desc_info->agg_en = true;
- desc_info->ampdu_density = sta->deflink.ht_cap.ampdu_density;
+ desc_info->ampdu_density = link_sta->ht_cap.ampdu_density;
desc_info->ampdu_num = ampdu_num;
+
+ rcu_read_unlock();
}
static void
@@ -569,9 +552,13 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan)
{
struct sk_buff *skb = tx_req->skb;
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = tx_info->control.vif;
+ struct ieee80211_bss_conf *bss_conf;
u16 lowest_rate;
+ u16 rate;
if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE ||
(vif && vif->p2p))
@@ -581,25 +568,35 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
else
lowest_rate = RTW89_HW_RATE_OFDM6;
- if (!vif || !vif->bss_conf.basic_rates || !tx_req->sta)
+ if (!rtwvif_link)
return lowest_rate;
- return __ffs(vif->bss_conf.basic_rates) + lowest_rate;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ if (!bss_conf->basic_rates || !rtwsta_link) {
+ rate = lowest_rate;
+ goto out;
+ }
+
+ rate = __ffs(bss_conf->basic_rates) + lowest_rate;
+
+out:
+ rcu_read_unlock();
+
+ return rate;
}
static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
- struct ieee80211_vif *vif = tx_req->vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct ieee80211_sta *sta = tx_req->sta;
- struct rtw89_sta *rtwsta;
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
- if (!sta)
- return rtwvif->mac_id;
+ if (!rtwsta_link)
+ return rtwvif_link->mac_id;
- rtwsta = (struct rtw89_sta *)sta->drv_priv;
- return rtwsta->mac_id;
+ return rtwsta_link->mac_id;
}
static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev,
@@ -618,11 +615,10 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct ieee80211_vif *vif = tx_req->vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
struct sk_buff *skb = tx_req->skb;
u8 qsel, ch_dma;
@@ -631,7 +627,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
desc_info->qsel = qsel;
desc_info->ch_dma = ch_dma;
- desc_info->port = desc_info->hiq ? rtwvif->port : 0;
+ desc_info->port = desc_info->hiq ? rtwvif_link->port : 0;
desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req);
desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL;
desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE;
@@ -701,18 +697,28 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req,
enum btc_pkt_type pkt_type)
{
- struct ieee80211_sta *sta = tx_req->sta;
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
struct sk_buff *skb = tx_req->skb;
struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_link_sta *link_sta;
__le16 fc = hdr->frame_control;
/* AP IOT issue with EAPoL, ARP and DHCP */
if (pkt_type < PACKET_MAX)
return false;
- if (!sta || !sta->deflink.he_cap.has_he)
+ if (!rtwsta_link)
+ return false;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ if (!link_sta->he_cap.has_he) {
+ rcu_read_unlock();
return false;
+ }
+
+ rcu_read_unlock();
if (!ieee80211_is_data_qos(fc))
return false;
@@ -720,7 +726,7 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev,
if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN)
return false;
- if (rtwsta && rtwsta->ra_report.might_fallback_legacy)
+ if (rtwsta_link && rtwsta_link->ra_report.might_fallback_legacy)
return false;
return true;
@@ -730,8 +736,7 @@ static void
__rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
- struct ieee80211_sta *sta = tx_req->sta;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
struct sk_buff *skb = tx_req->skb;
struct ieee80211_hdr *hdr = (void *)skb->data;
__le16 fc = hdr->frame_control;
@@ -747,7 +752,7 @@ __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev,
hdr = data;
htc = data + hdr_len;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER);
- *htc = rtwsta->htc_template ? rtwsta->htc_template :
+ *htc = rtwsta_link->htc_template ? rtwsta_link->htc_template :
le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) |
le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID);
@@ -761,8 +766,7 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev,
enum btc_pkt_type pkt_type)
{
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
- struct ieee80211_vif *vif = tx_req->vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type))
goto desc_bk;
@@ -773,23 +777,25 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev,
desc_info->a_ctrl_bsr = true;
desc_bk:
- if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr)
+ if (!rtwvif_link || rtwvif_link->last_a_ctrl == desc_info->a_ctrl_bsr)
return;
- rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr;
+ rtwvif_link->last_a_ctrl = desc_info->a_ctrl_bsr;
desc_info->bk = true;
}
static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
- struct ieee80211_vif *vif = tx_req->vif;
- struct ieee80211_sta *sta = tx_req->sta;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
- enum rtw89_chanctx_idx idx = rtwvif->chanctx_idx;
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern;
+ enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, idx);
+ struct ieee80211_link_sta *link_sta;
u16 lowest_rate;
+ u16 rate;
if (rate_pattern->enable)
return rate_pattern->rate;
@@ -801,20 +807,31 @@ static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev,
else
lowest_rate = RTW89_HW_RATE_OFDM6;
- if (!sta || !sta->deflink.supp_rates[chan->band_type])
+ if (!rtwsta_link)
return lowest_rate;
- return __ffs(sta->deflink.supp_rates[chan->band_type]) + lowest_rate;
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ if (!link_sta->supp_rates[chan->band_type]) {
+ rate = lowest_rate;
+ goto out;
+ }
+
+ rate = __ffs(link_sta->supp_rates[chan->band_type]) + lowest_rate;
+
+out:
+ rcu_read_unlock();
+
+ return rate;
}
static void
rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
- struct ieee80211_vif *vif = tx_req->vif;
- struct ieee80211_sta *sta = tx_req->sta;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
struct sk_buff *skb = tx_req->skb;
u8 tid, tid_indicate;
@@ -829,10 +846,10 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
desc_info->tid_indicate = tid_indicate;
desc_info->qsel = qsel;
desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req);
- desc_info->port = desc_info->hiq ? rtwvif->port : 0;
- desc_info->er_cap = rtwsta ? rtwsta->er_cap : false;
- desc_info->stbc = rtwsta ? rtwsta->ra.stbc_cap : false;
- desc_info->ldpc = rtwsta ? rtwsta->ra.ldpc_cap : false;
+ desc_info->port = desc_info->hiq ? rtwvif_link->port : 0;
+ desc_info->er_cap = rtwsta_link ? rtwsta_link->er_cap : false;
+ desc_info->stbc = rtwsta_link ? rtwsta_link->ra.stbc_cap : false;
+ desc_info->ldpc = rtwsta_link ? rtwsta_link->ra.ldpc_cap : false;
/* enable wd_info for AMPDU */
desc_info->en_wd_info = true;
@@ -907,8 +924,10 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
struct sk_buff *skb = tx_req->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct rtw89_addr_cam_entry *addr_cam;
enum rtw89_core_tx_type tx_type;
enum btc_pkt_type pkt_type;
+ bool upd_wlan_hdr = false;
bool is_bmc;
u16 seq;
@@ -916,6 +935,11 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
if (tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD) {
tx_type = rtw89_core_get_tx_type(rtwdev, skb);
tx_req->tx_type = tx_type;
+
+ addr_cam = rtw89_get_addr_cam_of(tx_req->rtwvif_link,
+ tx_req->rtwsta_link);
+ if (addr_cam->valid)
+ upd_wlan_hdr = true;
}
is_bmc = (is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1));
@@ -925,6 +949,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
desc_info->is_bmc = is_bmc;
desc_info->wd_page = true;
desc_info->hiq = info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+ desc_info->upd_wlan_hdr = upd_wlan_hdr;
switch (tx_req->tx_type) {
case RTW89_CORE_TX_TYPE_MGMT:
@@ -1027,13 +1052,34 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_core_tx_request tx_req = {0};
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_sta_link *rtwsta_link = NULL;
+ struct rtw89_vif_link *rtwvif_link;
int ret;
+ /* By default, driver writes tx via the link on HW-0. And then,
+ * according to links' status, HW can change tx to another link.
+ */
+
+ if (rtwsta) {
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link)) {
+ rtw89_err(rtwdev, "tx: find no sta link on HW-0\n");
+ return -ENOLINK;
+ }
+ }
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "tx: find no vif link on HW-0\n");
+ return -ENOLINK;
+ }
+
tx_req.skb = skb;
- tx_req.sta = sta;
- tx_req.vif = vif;
+ tx_req.rtwvif_link = rtwvif_link;
+ tx_req.rtwsta_link = rtwsta_link;
rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
@@ -1302,6 +1348,13 @@ static __le32 rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info *desc_info)
return cpu_to_le32(dword);
}
+static __le32 rtw89_build_txwd_body6_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY6_UPD_WLAN_HDR, desc_info->upd_wlan_hdr);
+
+ return cpu_to_le32(dword);
+}
+
static __le32 rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(BE_TXD_BODY7_USERATE_SEL, desc_info->use_rate) |
@@ -1365,6 +1418,7 @@ void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev,
txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info);
txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info);
}
+ txwd_body->dword6 = rtw89_build_txwd_body6_v2(desc_info);
txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info);
if (!desc_info->en_wd_info)
@@ -1514,16 +1568,24 @@ static u8 rtw89_get_data_rate_nss(struct rtw89_dev *rtwdev, u16 data_rate)
static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_dev *rtwdev = rtwsta->rtwdev;
struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_sta_link *rtwsta_link;
u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
u8 ant_pos = U8_MAX;
u8 evm_pos = 0;
int i;
- if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self)
+ /* FIXME: For single link, taking link on HW-0 here is okay. But, when
+ * enabling multiple active links, we should determine the right link.
+ */
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link))
+ return;
+
+ if (rtwsta_link->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self)
return;
if (hal->ant_diversity && hal->antenna_rx) {
@@ -1531,22 +1593,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
evm_pos = ant_pos;
}
- ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg);
+ ewma_rssi_add(&rtwsta_link->avg_rssi, phy_ppdu->rssi_avg);
if (ant_pos < ant_num) {
- ewma_rssi_add(&rtwsta->rssi[ant_pos], phy_ppdu->rssi[0]);
+ ewma_rssi_add(&rtwsta_link->rssi[ant_pos], phy_ppdu->rssi[0]);
} else {
for (i = 0; i < rtwdev->chip->rf_path_num; i++)
- ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]);
+ ewma_rssi_add(&rtwsta_link->rssi[i], phy_ppdu->rssi[i]);
}
if (phy_ppdu->ofdm.has && (phy_ppdu->has_data || phy_ppdu->has_bcn)) {
- ewma_snr_add(&rtwsta->avg_snr, phy_ppdu->ofdm.avg_snr);
+ ewma_snr_add(&rtwsta_link->avg_snr, phy_ppdu->ofdm.avg_snr);
if (rtw89_get_data_rate_nss(rtwdev, phy_ppdu->rate) == 1) {
- ewma_evm_add(&rtwsta->evm_1ss, phy_ppdu->ofdm.evm_min);
+ ewma_evm_add(&rtwsta_link->evm_1ss, phy_ppdu->ofdm.evm_min);
} else {
- ewma_evm_add(&rtwsta->evm_min[evm_pos], phy_ppdu->ofdm.evm_min);
- ewma_evm_add(&rtwsta->evm_max[evm_pos], phy_ppdu->ofdm.evm_max);
+ ewma_evm_add(&rtwsta_link->evm_min[evm_pos],
+ phy_ppdu->ofdm.evm_min);
+ ewma_evm_add(&rtwsta_link->evm_max[evm_pos],
+ phy_ppdu->ofdm.evm_max);
}
}
}
@@ -1795,32 +1859,58 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev,
phy_ppdu);
}
-static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev,
- u8 desc_info_gi,
- bool rx_status, bool eht)
+static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev,
+ u8 desc_info_gi,
+ bool rx_status)
{
switch (desc_info_gi) {
case RTW89_GILTF_SGI_4XHE08:
case RTW89_GILTF_2XHE08:
case RTW89_GILTF_1XHE08:
- return eht ? NL80211_RATE_INFO_EHT_GI_0_8 :
- NL80211_RATE_INFO_HE_GI_0_8;
+ return NL80211_RATE_INFO_HE_GI_0_8;
case RTW89_GILTF_2XHE16:
case RTW89_GILTF_1XHE16:
- return eht ? NL80211_RATE_INFO_EHT_GI_1_6 :
- NL80211_RATE_INFO_HE_GI_1_6;
+ return NL80211_RATE_INFO_HE_GI_1_6;
case RTW89_GILTF_LGI_4XHE32:
- return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
- NL80211_RATE_INFO_HE_GI_3_2;
+ return NL80211_RATE_INFO_HE_GI_3_2;
default:
rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi);
if (rx_status)
- return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
- NL80211_RATE_INFO_HE_GI_3_2;
+ return NL80211_RATE_INFO_HE_GI_3_2;
return U8_MAX;
}
}
+static u8 rtw89_rxdesc_to_nl_eht_gi(struct rtw89_dev *rtwdev,
+ u8 desc_info_gi,
+ bool rx_status)
+{
+ switch (desc_info_gi) {
+ case RTW89_GILTF_SGI_4XHE08:
+ case RTW89_GILTF_2XHE08:
+ case RTW89_GILTF_1XHE08:
+ return NL80211_RATE_INFO_EHT_GI_0_8;
+ case RTW89_GILTF_2XHE16:
+ case RTW89_GILTF_1XHE16:
+ return NL80211_RATE_INFO_EHT_GI_1_6;
+ case RTW89_GILTF_LGI_4XHE32:
+ return NL80211_RATE_INFO_EHT_GI_3_2;
+ default:
+ rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi);
+ if (rx_status)
+ return NL80211_RATE_INFO_EHT_GI_3_2;
+ return U8_MAX;
+ }
+}
+
+static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev,
+ u8 desc_info_gi,
+ bool rx_status, bool eht)
+{
+ return eht ? rtw89_rxdesc_to_nl_eht_gi(rtwdev, desc_info_gi, rx_status) :
+ rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info_gi, rx_status);
+}
+
static
bool rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status *status, u8 gi_ltf,
bool eht)
@@ -1876,17 +1966,19 @@ struct rtw89_vif_rx_stats_iter_data {
};
static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf,
struct sk_buff *skb)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
u8 *pos, *end, type, tf_bw;
u16 aid, tf_rua;
- if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) ||
- rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION ||
- rtwvif->net_type == RTW89_NET_TYPE_NO_LINK)
+ if (!ether_addr_equal(bss_conf->bssid, tf->ta) ||
+ rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION ||
+ rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK)
return;
type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK);
@@ -1915,7 +2007,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
rtwdev->stats.rx_tf_acc++;
if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ &&
rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106)
- rtwvif->pwr_diff_en = true;
+ rtwvif_link->pwr_diff_en = true;
break;
}
@@ -1986,7 +2078,7 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work);
}
-static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif,
+static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link,
struct ieee80211_hdr *hdr, size_t len)
{
struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr;
@@ -1994,20 +2086,22 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif,
if (len < offsetof(typeof(*mgmt), u.beacon.variable))
return;
- WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp));
+ WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp));
}
static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_vif_rx_stats_iter_data *iter_data = data;
struct rtw89_dev *rtwdev = iter_data->rtwdev;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
struct sk_buff *skb = iter_data->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu;
+ struct ieee80211_bss_conf *bss_conf;
+ struct rtw89_vif_link *rtwvif_link;
const u8 *bssid = iter_data->bssid;
if (rtwdev->scanning &&
@@ -2015,33 +2109,49 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
ieee80211_is_probe_resp(hdr->frame_control)))
rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb);
- if (!vif->bss_conf.bssid)
- return;
+ rcu_read_lock();
+
+ /* FIXME: For single link, taking link on HW-0 here is okay. But, when
+ * enabling multiple active links, we should determine the right link.
+ */
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link))
+ goto out;
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ if (!bss_conf->bssid)
+ goto out;
if (ieee80211_is_trigger(hdr->frame_control)) {
- rtw89_stats_trigger_frame(rtwdev, vif, skb);
- return;
+ rtw89_stats_trigger_frame(rtwdev, rtwvif_link, bss_conf, skb);
+ goto out;
}
- if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
- return;
+ if (!ether_addr_equal(bss_conf->bssid, bssid))
+ goto out;
if (ieee80211_is_beacon(hdr->frame_control)) {
if (vif->type == NL80211_IFTYPE_STATION &&
!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
- rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len);
+ rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len);
rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu);
}
pkt_stat->beacon_nr++;
+
+ if (phy_ppdu)
+ ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg);
}
- if (!ether_addr_equal(vif->addr, hdr->addr1))
- return;
+ if (!ether_addr_equal(bss_conf->addr, hdr->addr1))
+ goto out;
if (desc_info->data_rate < RTW89_HW_RATE_NR)
pkt_stat->rx_rate_cnt[desc_info->data_rate]++;
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false);
+
+out:
+ rcu_read_unlock();
}
static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev,
@@ -2432,15 +2542,23 @@ void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta)
struct rtw89_core_iter_rx_status *iter_data =
(struct rtw89_core_iter_rx_status *)data;
struct ieee80211_rx_status *rx_status = iter_data->rx_status;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
u8 mac_id = iter_data->mac_id;
- if (mac_id != rtwsta->mac_id)
+ /* FIXME: For single link, taking link on HW-0 here is okay. But, when
+ * enabling multiple active links, we should determine the right link.
+ */
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link))
return;
- rtwsta->rx_status = *rx_status;
- rtwsta->rx_hw_rate = desc_info->data_rate;
+ if (mac_id != rtwsta_link->mac_id)
+ return;
+
+ rtwsta_link->rx_status = *rx_status;
+ rtwsta_link->rx_hw_rate = desc_info->data_rate;
}
static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev,
@@ -2546,6 +2664,10 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
+ /* FIXME: Fix __rtw89_enter_ps_mode() to consider MLO cases. */
+ if (rtwdev->support_mlo)
+ return RTW89_PS_MODE_NONE;
+
if (rtw89_disable_ps_mode || !chip->ps_mode_supported ||
RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw))
return RTW89_PS_MODE_NONE;
@@ -2658,7 +2780,7 @@ static void rtw89_core_ba_work(struct work_struct *work)
list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) {
struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
struct ieee80211_sta *sta = txq->sta;
- struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
u8 tid = txq->tid;
if (!sta) {
@@ -2686,8 +2808,8 @@ skip_ba_work:
spin_unlock_bh(&rtwdev->ba_lock);
}
-static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta)
+void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta)
{
struct rtw89_txq *rtwtxq, *tmp;
@@ -2701,8 +2823,8 @@ static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
spin_unlock_bh(&rtwdev->ba_lock);
}
-static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta)
+void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta)
{
struct rtw89_txq *rtwtxq, *tmp;
@@ -2718,10 +2840,10 @@ static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev,
spin_unlock_bh(&rtwdev->ba_lock);
}
-static void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta)
+void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct sk_buff *skb, *tmp;
skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) {
@@ -2762,7 +2884,7 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev,
struct ieee80211_hw *hw = rtwdev->hw;
struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
struct ieee80211_sta *sta = txq->sta;
- struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
if (test_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags))
return;
@@ -2838,10 +2960,19 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev,
bool *sched_txq, bool *reinvoke)
{
struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv;
- struct ieee80211_sta *sta = txq->sta;
- struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(txq->sta);
+ struct rtw89_sta_link *rtwsta_link;
+
+ if (!rtwsta)
+ return false;
+
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link)) {
+ rtw89_err(rtwdev, "agg wait: find no link on HW-0\n");
+ return false;
+ }
- if (!sta || rtwsta->max_agg_wait <= 0)
+ if (rtwsta_link->max_agg_wait <= 0)
return false;
if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID)
@@ -2855,7 +2986,7 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev,
return false;
}
- if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) {
+ if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta_link->max_agg_wait) {
*reinvoke = true;
rtwtxq->wait_cnt++;
return true;
@@ -2879,7 +3010,7 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinv
ieee80211_txq_schedule_start(hw, ac);
while ((txq = ieee80211_next_txq(hw, ac))) {
rtwtxq = (struct rtw89_txq *)txq->drv_priv;
- rtwvif = (struct rtw89_vif *)txq->vif->drv_priv;
+ rtwvif = vif_to_rtwvif(txq->vif);
if (rtwvif->offchan) {
ieee80211_return_txq(hw, txq, true);
@@ -2955,16 +3086,23 @@ static void rtw89_forbid_ba_work(struct work_struct *w)
static void rtw89_core_sta_pending_tx_iter(void *data,
struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_vif *rtwvif_target = data, *rtwvif = rtwsta->rtwvif;
- struct rtw89_dev *rtwdev = rtwvif->rtwdev;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_vif_link *target = data;
+ struct rtw89_vif_link *rtwvif_link;
struct sk_buff *skb, *tmp;
+ unsigned int link_id;
int qsel, ret;
- if (rtwvif->chanctx_idx != rtwvif_target->chanctx_idx)
- return;
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ if (rtwvif_link->chanctx_idx == target->chanctx_idx)
+ goto bottom;
+ return;
+
+bottom:
if (skb_queue_len(&rtwsta->roc_queue) == 0)
return;
@@ -2982,17 +3120,17 @@ static void rtw89_core_sta_pending_tx_iter(void *data,
}
static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
ieee80211_iterate_stations_atomic(rtwdev->hw,
rtw89_core_sta_pending_tx_iter,
- rtwvif);
+ rtwvif_link);
}
static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool qos, bool ps)
+ struct rtw89_vif_link *rtwvif_link, bool qos, bool ps)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
@@ -3002,7 +3140,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
return 0;
rcu_read_lock();
- sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
if (!sta) {
ret = -EINVAL;
goto out;
@@ -3040,31 +3178,49 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_roc *roc = &rtwvif->roc;
+ struct rtw89_vif_link *rtwvif_link;
struct cfg80211_chan_def roc_chan;
- struct rtw89_vif *tmp;
+ struct rtw89_vif *tmp_vif;
+ u32 reg;
int ret;
lockdep_assert_held(&rtwdev->mutex);
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "roc start: find no link on HW-%u\n",
+ RTW89_ROC_BY_LINK_INDEX);
+ return;
+ }
+
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC);
- ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true);
+ ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"roc send null-1 failed: %d\n", ret);
- rtw89_for_each_rtwvif(rtwdev, tmp)
- if (tmp->chanctx_idx == rtwvif->chanctx_idx)
- tmp->offchan = true;
+ rtw89_for_each_rtwvif(rtwdev, tmp_vif) {
+ struct rtw89_vif_link *tmp_link;
+ unsigned int link_id;
+
+ rtw89_vif_for_each_link(tmp_vif, tmp_link, link_id) {
+ if (tmp_link->chanctx_idx == rtwvif_link->chanctx_idx) {
+ tmp_vif->offchan = true;
+ break;
+ }
+ }
+ }
cfg80211_chandef_create(&roc_chan, &roc->chan, NL80211_CHAN_NO_HT);
- rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, &roc_chan);
+ rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, &roc_chan);
rtw89_set_channel(rtwdev);
- rtw89_write32_clr(rtwdev,
- rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
- B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
ieee80211_ready_on_channel(hw);
cancel_delayed_work(&rtwvif->roc.roc_work);
@@ -3077,7 +3233,9 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_roc *roc = &rtwvif->roc;
- struct rtw89_vif *tmp;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_vif *tmp_vif;
+ u32 reg;
int ret;
lockdep_assert_held(&rtwdev->mutex);
@@ -3087,24 +3245,28 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
- 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);
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "roc end: find no link on HW-%u\n",
+ RTW89_ROC_BY_LINK_INDEX);
+ return;
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr);
roc->state = RTW89_ROC_IDLE;
- rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, NULL);
+ rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, NULL);
rtw89_chanctx_proceed(rtwdev);
- ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false);
+ ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"roc send null-0 failed: %d\n", ret);
- rtw89_for_each_rtwvif(rtwdev, tmp)
- if (tmp->chanctx_idx == rtwvif->chanctx_idx)
- tmp->offchan = false;
+ rtw89_for_each_rtwvif(rtwdev, tmp_vif)
+ tmp_vif->offchan = false;
- rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif);
+ rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif_link);
queue_work(rtwdev->txq_wq, &rtwdev->txq_work);
if (hw->conf.flags & IEEE80211_CONF_IDLE)
@@ -3188,39 +3350,52 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
bool tfc_changed;
tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats);
+
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats);
- rtw89_fw_h2c_tp_offload(rtwdev, rtwvif);
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link);
}
return tfc_changed;
}
-static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- if ((rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION &&
- rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) ||
- rtwvif->tdls_peer)
- return;
-
- if (rtwvif->offchan)
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION &&
+ rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
return;
- if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE &&
- rtwvif->stats.rx_tfc_lv == RTW89_TFC_IDLE)
- rtw89_enter_lps(rtwdev, rtwvif, true);
+ rtw89_enter_lps(rtwdev, rtwvif_link, true);
}
static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
- rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_vif_enter_lps(rtwdev, rtwvif);
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ if (rtwvif->tdls_peer)
+ continue;
+ if (rtwvif->offchan)
+ continue;
+
+ if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE ||
+ rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE)
+ continue;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_vif_enter_lps(rtwdev, rtwvif_link);
+ }
}
static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev)
@@ -3234,14 +3409,16 @@ static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev)
rtw89_chip_rfk_track(rtwdev);
}
-void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf)
{
enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
if (mode == RTW89_ENTITY_MODE_MCC)
rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_P2P_PS_CHANGE);
else
- rtw89_process_p2p_ps(rtwdev, vif);
+ rtw89_process_p2p_ps(rtwdev, rtwvif_link, bss_conf);
}
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
@@ -3326,7 +3503,8 @@ void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits)
}
int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx)
+ struct rtw89_sta_link *rtwsta_link, u8 tid,
+ u8 *cam_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
@@ -3363,7 +3541,7 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev,
}
entry->tid = tid;
- list_add_tail(&entry->list, &rtwsta->ba_cam_list);
+ list_add_tail(&entry->list, &rtwsta_link->ba_cam_list);
*cam_idx = idx;
@@ -3371,7 +3549,8 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev,
}
int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx)
+ struct rtw89_sta_link *rtwsta_link, u8 tid,
+ u8 *cam_idx)
{
struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
struct rtw89_ba_cam_entry *entry = NULL, *tmp;
@@ -3379,7 +3558,7 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev,
lockdep_assert_held(&rtwdev->mutex);
- list_for_each_entry_safe(entry, tmp, &rtwsta->ba_cam_list, list) {
+ list_for_each_entry_safe(entry, tmp, &rtwsta_link->ba_cam_list, list) {
if (entry->tid != tid)
continue;
@@ -3396,24 +3575,25 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev,
#define RTW89_TYPE_MAPPING(_type) \
case NL80211_IFTYPE_ ## _type: \
- rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type; \
+ rtwvif_link->wifi_role = RTW89_WIFI_ROLE_ ## _type; \
break
-void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc)
+void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct ieee80211_bss_conf *bss_conf;
switch (vif->type) {
case NL80211_IFTYPE_STATION:
if (vif->p2p)
- rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT;
+ rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT;
else
- rtwvif->wifi_role = RTW89_WIFI_ROLE_STATION;
+ rtwvif_link->wifi_role = RTW89_WIFI_ROLE_STATION;
break;
case NL80211_IFTYPE_AP:
if (vif->p2p)
- rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_GO;
+ rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_GO;
else
- rtwvif->wifi_role = RTW89_WIFI_ROLE_AP;
+ rtwvif_link->wifi_role = RTW89_WIFI_ROLE_AP;
break;
RTW89_TYPE_MAPPING(ADHOC);
RTW89_TYPE_MAPPING(MONITOR);
@@ -3426,23 +3606,27 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc)
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
- rtwvif->net_type = RTW89_NET_TYPE_AP_MODE;
- rtwvif->self_role = RTW89_SELF_ROLE_AP;
+ rtwvif_link->net_type = RTW89_NET_TYPE_AP_MODE;
+ rtwvif_link->self_role = RTW89_SELF_ROLE_AP;
break;
case NL80211_IFTYPE_ADHOC:
- rtwvif->net_type = RTW89_NET_TYPE_AD_HOC;
- rtwvif->self_role = RTW89_SELF_ROLE_CLIENT;
+ rtwvif_link->net_type = RTW89_NET_TYPE_AD_HOC;
+ rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT;
break;
case NL80211_IFTYPE_STATION:
if (assoc) {
- rtwvif->net_type = RTW89_NET_TYPE_INFRA;
- rtwvif->trigger = vif->bss_conf.he_support;
+ rtwvif_link->net_type = RTW89_NET_TYPE_INFRA;
+
+ rcu_read_lock();
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ rtwvif_link->trigger = bss_conf->he_support;
+ rcu_read_unlock();
} else {
- rtwvif->net_type = RTW89_NET_TYPE_NO_LINK;
- rtwvif->trigger = false;
+ rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK;
+ rtwvif_link->trigger = false;
}
- rtwvif->self_role = RTW89_SELF_ROLE_CLIENT;
- rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
+ rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT;
+ rtwvif_link->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
break;
case NL80211_IFTYPE_MONITOR:
break;
@@ -3452,137 +3636,110 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc)
}
}
-int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
struct rtw89_hal *hal = &rtwdev->hal;
u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
int i;
int ret;
- rtwsta->rtwdev = rtwdev;
- rtwsta->rtwvif = rtwvif;
- rtwsta->prev_rssi = 0;
- INIT_LIST_HEAD(&rtwsta->ba_cam_list);
- skb_queue_head_init(&rtwsta->roc_queue);
-
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
- rtw89_core_txq_init(rtwdev, sta->txq[i]);
-
- ewma_rssi_init(&rtwsta->avg_rssi);
- ewma_snr_init(&rtwsta->avg_snr);
- ewma_evm_init(&rtwsta->evm_1ss);
+ rtwsta_link->prev_rssi = 0;
+ INIT_LIST_HEAD(&rtwsta_link->ba_cam_list);
+ ewma_rssi_init(&rtwsta_link->avg_rssi);
+ ewma_snr_init(&rtwsta_link->avg_snr);
+ ewma_evm_init(&rtwsta_link->evm_1ss);
for (i = 0; i < ant_num; i++) {
- ewma_rssi_init(&rtwsta->rssi[i]);
- ewma_evm_init(&rtwsta->evm_min[i]);
- ewma_evm_init(&rtwsta->evm_max[i]);
+ ewma_rssi_init(&rtwsta_link->rssi[i]);
+ ewma_evm_init(&rtwsta_link->evm_min[i]);
+ ewma_evm_init(&rtwsta_link->evm_max[i]);
}
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
- /* for station mode, assign the mac_id from itself */
- rtwsta->mac_id = rtwvif->mac_id;
-
/* must do rtw89_reg_6ghz_recalc() before rfk channel */
- ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true);
+ ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true);
if (ret)
return ret;
- rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link,
BTC_ROLE_MSTS_STA_CONN_START);
- rtw89_chip_rfk_channel(rtwdev, rtwvif);
+ rtw89_chip_rfk_channel(rtwdev, rtwvif_link);
} else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
- rtwsta->mac_id = rtw89_acquire_mac_id(rtwdev);
- if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM)
- return -ENOSPC;
-
- ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false);
+ ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false);
if (ret) {
- rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
rtw89_warn(rtwdev, "failed to send h2c macid pause\n");
return ret;
}
- ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
+ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link,
RTW89_ROLE_CREATE);
if (ret) {
- rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
rtw89_warn(rtwdev, "failed to send h2c role info\n");
return ret;
}
- ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta);
+ ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
if (ret)
return ret;
- ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta);
+ ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
if (ret)
return ret;
-
- rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
}
return 0;
}
-int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
if (vif->type == NL80211_IFTYPE_STATION)
- rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, false);
-
- rtwdev->total_sta_assoc--;
- if (sta->tdls)
- rtwvif->tdls_peer--;
- rtwsta->disassoc = true;
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false);
return 0;
}
-int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
int ret;
- rtw89_mac_bf_monitor_calc(rtwdev, sta, true);
- rtw89_mac_bf_disassoc(rtwdev, vif, sta);
- rtw89_core_free_sta_pending_ba(rtwdev, sta);
- rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta);
- rtw89_core_free_sta_pending_roc_tx(rtwdev, sta);
+ rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, true);
+ rtw89_mac_bf_disassoc(rtwdev, rtwvif_link, rtwsta_link);
if (vif->type == NL80211_IFTYPE_AP || sta->tdls)
- rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam);
+ rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam);
if (sta->tdls)
- rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam);
+ rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam);
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
- rtw89_vif_type_mapping(vif, false);
- rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true);
+ rtw89_vif_type_mapping(rtwvif_link, false);
+ rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link, true);
}
- ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
+ ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
return ret;
}
- ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, true);
+ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, true);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c join info\n");
return ret;
}
/* update cam aid mac_id net_type */
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cam\n");
return ret;
@@ -3591,106 +3748,114 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
return ret;
}
-int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
+ struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link,
+ rtwsta_link);
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
int ret;
if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
if (sta->tdls) {
- ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, sta->addr);
+ struct ieee80211_link_sta *link_sta;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam,
+ link_sta->addr);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c init bssid cam for TDLS\n");
+ rcu_read_unlock();
return ret;
}
+
+ rcu_read_unlock();
}
- ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta->addr_cam, bssid_cam);
+ ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta_link->addr_cam, bssid_cam);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c init addr cam\n");
return ret;
}
}
- ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
+ ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
return ret;
}
- ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, false);
+ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, false);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c join info\n");
return ret;
}
/* update cam aid mac_id net_type */
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cam\n");
return ret;
}
- rtwdev->total_sta_assoc++;
- if (sta->tdls)
- rtwvif->tdls_peer++;
- rtw89_phy_ra_assoc(rtwdev, sta);
- rtw89_mac_bf_assoc(rtwdev, vif, sta);
- rtw89_mac_bf_monitor_calc(rtwdev, sta, false);
+ rtw89_phy_ra_assoc(rtwdev, rtwsta_link);
+ rtw89_mac_bf_assoc(rtwdev, rtwvif_link, rtwsta_link);
+ rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, false);
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ieee80211_bss_conf *bss_conf;
+
+ rcu_read_lock();
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
if (bss_conf->he_support &&
!(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE))
- rtwsta->er_cap = true;
+ rtwsta_link->er_cap = true;
- rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
+ rcu_read_unlock();
+
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link,
BTC_ROLE_MSTS_STA_CONN_END);
- rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan);
- rtw89_phy_ul_tb_assoc(rtwdev, rtwvif);
+ rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan);
+ rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link);
- ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
+ ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c general packet\n");
return ret;
}
- rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
}
return ret;
}
-int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
int ret;
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
- rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false);
- rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
+ rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, false);
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link,
BTC_ROLE_MSTS_STA_DIS_CONN);
} else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
- rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
-
- ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
+ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link,
RTW89_ROLE_REMOVE);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c role info\n");
return ret;
}
-
- rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
}
return 0;
@@ -4152,15 +4317,16 @@ static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev)
void rtw89_core_update_beacon_work(struct work_struct *work)
{
struct rtw89_dev *rtwdev;
- struct rtw89_vif *rtwvif = container_of(work, struct rtw89_vif,
- update_beacon_work);
+ struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link,
+ update_beacon_work);
- if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE)
+ if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE)
return;
- rtwdev = rtwvif->rtwdev;
+ rtwdev = rtwvif_link->rtwvif->rtwdev;
+
mutex_lock(&rtwdev->mutex);
- rtw89_chip_h2c_update_beacon(rtwdev, rtwvif);
+ rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
mutex_unlock(&rtwdev->mutex);
}
@@ -4266,8 +4432,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
rtw89_phy_dm_init(rtwdev);
- rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
- rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
+ rtw89_mac_cfg_ppdu_status_bands(rtwdev, true);
+ rtw89_mac_update_rts_threshold(rtwdev);
rtw89_tas_reset(rtwdev);
@@ -4355,6 +4521,168 @@ void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id)
clear_bit(mac_id, rtwdev->mac_id_map);
}
+void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ u8 mac_id, u8 port)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 support_link_num = chip->support_link_num;
+ u8 support_mld_num = 0;
+ unsigned int link_id;
+ u8 index;
+
+ bitmap_zero(rtwvif->links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
+ rtwvif->links[link_id] = NULL;
+
+ rtwvif->rtwdev = rtwdev;
+
+ if (rtwdev->support_mlo) {
+ rtwvif->links_inst_valid_num = support_link_num;
+ support_mld_num = chip->support_macid_num / support_link_num;
+ } else {
+ rtwvif->links_inst_valid_num = 1;
+ }
+
+ for (index = 0; index < rtwvif->links_inst_valid_num; index++) {
+ struct rtw89_vif_link *inst = &rtwvif->links_inst[index];
+
+ inst->rtwvif = rtwvif;
+ inst->mac_id = mac_id + index * support_mld_num;
+ inst->mac_idx = RTW89_MAC_0 + index;
+ inst->phy_idx = RTW89_PHY_0 + index;
+
+ /* multi-link use the same port id on different HW bands */
+ inst->port = port;
+ }
+}
+
+void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta, u8 mac_id)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 support_link_num = chip->support_link_num;
+ u8 support_mld_num = 0;
+ unsigned int link_id;
+ u8 index;
+
+ bitmap_zero(rtwsta->links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
+ rtwsta->links[link_id] = NULL;
+
+ rtwsta->rtwdev = rtwdev;
+ rtwsta->rtwvif = rtwvif;
+
+ if (rtwdev->support_mlo) {
+ rtwsta->links_inst_valid_num = support_link_num;
+ support_mld_num = chip->support_macid_num / support_link_num;
+ } else {
+ rtwsta->links_inst_valid_num = 1;
+ }
+
+ for (index = 0; index < rtwsta->links_inst_valid_num; index++) {
+ struct rtw89_sta_link *inst = &rtwsta->links_inst[index];
+
+ inst->rtwvif_link = &rtwvif->links_inst[index];
+
+ inst->rtwsta = rtwsta;
+ inst->mac_id = mac_id + index * support_mld_num;
+ }
+}
+
+struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif,
+ unsigned int link_id)
+{
+ struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id];
+ u8 index;
+ int ret;
+
+ if (rtwvif_link)
+ return rtwvif_link;
+
+ index = find_first_zero_bit(rtwvif->links_inst_map,
+ rtwvif->links_inst_valid_num);
+ if (index == rtwvif->links_inst_valid_num) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ rtwvif_link = &rtwvif->links_inst[index];
+ rtwvif_link->link_id = link_id;
+
+ set_bit(index, rtwvif->links_inst_map);
+ rtwvif->links[link_id] = rtwvif_link;
+ return rtwvif_link;
+
+err:
+ rtw89_err(rtwvif->rtwdev, "vif (link_id %u) failed to set link: %d\n",
+ link_id, ret);
+ return NULL;
+}
+
+void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id)
+{
+ struct rtw89_vif_link **container = &rtwvif->links[link_id];
+ struct rtw89_vif_link *link = *container;
+ u8 index;
+
+ if (!link)
+ return;
+
+ index = rtw89_vif_link_inst_get_index(link);
+ clear_bit(index, rtwvif->links_inst_map);
+ *container = NULL;
+}
+
+struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta,
+ unsigned int link_id)
+{
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id];
+ struct rtw89_sta_link *rtwsta_link = rtwsta->links[link_id];
+ u8 index;
+ int ret;
+
+ if (rtwsta_link)
+ return rtwsta_link;
+
+ if (!rtwvif_link) {
+ ret = -ENOLINK;
+ goto err;
+ }
+
+ index = rtw89_vif_link_inst_get_index(rtwvif_link);
+ if (test_bit(index, rtwsta->links_inst_map)) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ rtwsta_link = &rtwsta->links_inst[index];
+ rtwsta_link->link_id = link_id;
+
+ set_bit(index, rtwsta->links_inst_map);
+ rtwsta->links[link_id] = rtwsta_link;
+ return rtwsta_link;
+
+err:
+ rtw89_err(rtwsta->rtwdev, "sta (link_id %u) failed to set link: %d\n",
+ link_id, ret);
+ return NULL;
+}
+
+void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id)
+{
+ struct rtw89_sta_link **container = &rtwsta->links[link_id];
+ struct rtw89_sta_link *link = *container;
+ u8 index;
+
+ if (!link)
+ return;
+
+ index = rtw89_sta_link_inst_get_index(link);
+ clear_bit(index, rtwsta->links_inst_map);
+ *container = NULL;
+}
+
int rtw89_core_init(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -4444,39 +4772,45 @@ void rtw89_core_deinit(struct rtw89_dev *rtwdev)
}
EXPORT_SYMBOL(rtw89_core_deinit);
-void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr, bool hw_scan)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
if (hw_scan)
rtw89_leave_ips_by_hwflags(rtwdev);
- ether_addr_copy(rtwvif->mac_addr, mac_addr);
- rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, chan->band_type);
- rtw89_chip_rfk_scan(rtwdev, rtwvif, true);
+ ether_addr_copy(rtwvif_link->mac_addr, mac_addr);
+ rtw89_btc_ntfy_scan_start(rtwdev, rtwvif_link->phy_idx, chan->band_type);
+ rtw89_chip_rfk_scan(rtwdev, rtwvif_link, true);
rtw89_hci_recalc_int_mit(rtwdev);
rtw89_phy_config_edcca(rtwdev, true);
- rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr);
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, mac_addr);
}
void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif, bool hw_scan)
+ struct rtw89_vif_link *rtwvif_link, bool hw_scan)
{
- struct rtw89_vif *rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
+ struct ieee80211_bss_conf *bss_conf;
- if (!rtwvif)
+ if (!rtwvif_link)
return;
- ether_addr_copy(rtwvif->mac_addr, vif->addr);
- rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr);
+
+ rcu_read_unlock();
+
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
- rtw89_chip_rfk_scan(rtwdev, rtwvif, false);
- rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0);
+ rtw89_chip_rfk_scan(rtwdev, rtwvif_link, false);
+ rtw89_btc_ntfy_scan_finish(rtwdev, rtwvif_link->phy_idx);
rtw89_phy_config_edcca(rtwdev, false);
rtwdev->scanning = false;
@@ -4513,11 +4847,20 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev)
static void rtw89_core_setup_phycap(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
rtwdev->hal.support_cckpd =
!(rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV) &&
!(rtwdev->chip->chip_id == RTL8852B && rtwdev->hal.cv <= CHIP_CAV);
rtwdev->hal.support_igi =
rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV;
+
+ if (test_bit(RTW89_QUIRK_THERMAL_PROT_120C, rtwdev->quirks))
+ rtwdev->hal.thermal_prot_th = chip->thermal_th[1];
+ else if (test_bit(RTW89_QUIRK_THERMAL_PROT_110C, rtwdev->quirks))
+ rtwdev->hal.thermal_prot_th = chip->thermal_th[0];
+ else
+ rtwdev->hal.thermal_prot_th = 0;
}
static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev)
@@ -4688,17 +5031,39 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
}
EXPORT_SYMBOL(rtw89_chip_info_setup);
+void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct ieee80211_bss_conf *bss_conf;
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+ if (!bss_conf->he_support || !vif->cfg.assoc) {
+ rcu_read_unlock();
+ return;
+ }
+
+ rcu_read_unlock();
+
+ if (chip->ops->set_txpwr_ul_tb_offset)
+ chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif_link->mac_idx);
+}
+
static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 n = rtwdev->support_mlo ? chip->support_link_num : 1;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw89_hal *hal = &rtwdev->hal;
int ret;
int tx_headroom = IEEE80211_HT_CTL_LEN;
- hw->vif_data_size = sizeof(struct rtw89_vif);
- hw->sta_data_size = sizeof(struct rtw89_sta);
+ hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n);
+ hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n);
hw->txq_data_size = sizeof(struct rtw89_txq);
hw->chanctx_data_size = sizeof(struct rtw89_chanctx_cfg);
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 4ed9034fdb46..5ad32eacd0d5 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -829,6 +829,8 @@ enum rtw89_phy_idx {
RTW89_PHY_MAX
};
+#define __RTW89_MLD_MAX_LINK_NUM 2
+
enum rtw89_chanctx_idx {
RTW89_CHANCTX_0 = 0,
RTW89_CHANCTX_1 = 1,
@@ -1160,14 +1162,15 @@ struct rtw89_tx_desc_info {
bool er_cap;
bool stbc;
bool ldpc;
+ bool upd_wlan_hdr;
};
struct rtw89_core_tx_request {
enum rtw89_core_tx_type tx_type;
struct sk_buff *skb;
- struct ieee80211_vif *vif;
- struct ieee80211_sta *sta;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
struct rtw89_tx_desc_info desc_info;
};
@@ -1350,7 +1353,6 @@ struct rtw89_btc_wl_smap {
u32 connecting: 1;
u32 roaming: 1;
u32 dbccing: 1;
- u32 transacting: 1;
u32 _4way: 1;
u32 rf_off: 1;
u32 lps: 2;
@@ -2937,6 +2939,7 @@ struct rtw89_btc_dm {
u8 wl_pre_agc: 2;
u8 wl_lna2: 1;
+ u8 freerun_chk: 1;
u8 wl_pre_agc_rb: 2;
u8 bt_select: 2; /* 0:s0, 1:s1, 2:s0 & s1, refer to enum btc_bt_index */
u8 slot_req_more: 1;
@@ -2975,6 +2978,8 @@ enum rtw89_btc_btf_fw_event {
BTF_EVNT_BT_REG = 3,
BTF_EVNT_CX_RUNINFO = 4,
BTF_EVNT_BT_PSD = 5,
+ BTF_EVNT_BT_DEV_INFO = 6, /* fwc2hfunc > 0 */
+ BTF_EVNT_BT_LEAUDIO_INFO = 7, /* fwc2hfunc > 1 */
BTF_EVNT_BUF_OVERFLOW,
BTF_EVNT_C2H_LOOPBACK,
BTF_EVNT_MAX,
@@ -3141,6 +3146,7 @@ struct rtw89_btc_ver {
u8 fcxinit;
u8 fwevntrptl;
+ u8 fwc2hfunc;
u8 drvinfo_type;
u16 info_buf;
u8 max_role_num;
@@ -3354,12 +3360,13 @@ struct rtw89_sec_cam_entry {
u8 key[32];
};
-struct rtw89_sta {
+struct rtw89_sta_link {
+ struct rtw89_sta *rtwsta;
+ unsigned int link_id;
+
u8 mac_id;
- bool disassoc;
bool er_cap;
- struct rtw89_dev *rtwdev;
- struct rtw89_vif *rtwvif;
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_ra_info ra;
struct rtw89_ra_report ra_report;
int max_agg_wait;
@@ -3370,15 +3377,12 @@ struct rtw89_sta {
struct ewma_evm evm_1ss;
struct ewma_evm evm_min[RF_PATH_MAX];
struct ewma_evm evm_max[RF_PATH_MAX];
- struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
- DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS);
struct ieee80211_rx_status rx_status;
u16 rx_hw_rate;
__le32 htc_template;
struct rtw89_addr_cam_entry addr_cam; /* AP mode or TDLS peer only */
struct rtw89_bssid_cam_entry bssid_cam; /* TDLS peer only */
struct list_head ba_cam_list;
- struct sk_buff_head roc_queue;
bool use_cfg_mask;
struct cfg80211_bitrate_mask mask;
@@ -3424,6 +3428,8 @@ enum rtw89_roc_state {
RTW89_ROC_MGMT,
};
+#define RTW89_ROC_BY_LINK_INDEX 0
+
struct rtw89_roc {
struct ieee80211_channel chan;
struct delayed_work roc_work;
@@ -3460,10 +3466,10 @@ struct rtw89_p2p_noa_setter {
u8 noa_index;
};
-struct rtw89_vif {
- struct list_head list;
- struct rtw89_dev *rtwdev;
- struct rtw89_roc roc;
+struct rtw89_vif_link {
+ struct rtw89_vif *rtwvif;
+ unsigned int link_id;
+
bool chanctx_assigned; /* only valid when running with chanctx_ops */
enum rtw89_chanctx_idx chanctx_idx;
enum rtw89_reg_6ghz_power reg_6ghz_power;
@@ -3473,7 +3479,6 @@ struct rtw89_vif {
u8 port;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
- __be32 ip_addr;
u8 phy_idx;
u8 mac_idx;
u8 net_type;
@@ -3484,7 +3489,6 @@ struct rtw89_vif {
u8 hit_rule;
u8 last_noa_nr;
u64 sync_bcn_tsf;
- bool offchan;
bool trigger;
bool lsig_txop;
u8 tgt_ind;
@@ -3498,15 +3502,11 @@ struct rtw89_vif {
bool pre_pwr_diff_en;
bool pwr_diff_en;
u8 def_tri_idx;
- u32 tdls_peer;
struct work_struct update_beacon_work;
struct rtw89_addr_cam_entry addr_cam;
struct rtw89_bssid_cam_entry bssid_cam;
struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS];
- struct rtw89_traffic_stats stats;
struct rtw89_phy_rate_pattern rate_pattern;
- struct cfg80211_scan_request *scan_req;
- struct ieee80211_scan_ies *scan_ies;
struct list_head general_pkt_list;
struct rtw89_p2p_noa_setter p2p_noa;
};
@@ -3599,11 +3599,11 @@ struct rtw89_chip_ops {
void (*rfk_hw_init)(struct rtw89_dev *rtwdev);
void (*rfk_init)(struct rtw89_dev *rtwdev);
void (*rfk_init_late)(struct rtw89_dev *rtwdev);
- void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+ void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
void (*rfk_band_changed)(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx,
const struct rtw89_chan *chan);
- void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool start);
void (*rfk_track)(struct rtw89_dev *rtwdev);
void (*power_trim)(struct rtw89_dev *rtwdev);
@@ -3646,23 +3646,25 @@ struct rtw89_chip_ops {
u32 *tx_en, enum rtw89_sch_tx_sel sel);
int (*resume_sch_tx)(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en);
int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*h2c_update_beacon)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
- int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link);
+ int (*h2c_ba_cam)(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
bool valid, struct ieee80211_ampdu_params *params);
void (*btc_set_rfe)(struct rtw89_dev *rtwdev);
@@ -4245,6 +4247,7 @@ struct rtw89_chip_info {
u8 wde_qempty_acq_grpnum;
u8 wde_qempty_mgq_grpsel;
u32 rf_base_addr[2];
+ u8 thermal_th[2];
u8 support_macid_num;
u8 support_link_num;
u8 support_chanctx_num;
@@ -4445,6 +4448,8 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0,
RTW89_FW_FEATURE_WOW_REASON_V1,
RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0,
+ RTW89_FW_FEATURE_RFK_RXDCK_V0,
+ RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX,
};
struct rtw89_fw_suit {
@@ -4511,11 +4516,14 @@ enum rtw89_fw_mss_dev_type {
};
struct rtw89_fw_secure {
- bool secure_boot;
+ bool secure_boot: 1;
+ bool can_mss_v1: 1;
+ bool can_mss_v0: 1;
u32 sb_sel_mgn;
u8 mss_dev_type;
u8 mss_cust_idx;
u8 mss_key_num;
+ u8 mss_idx; /* v0 */
};
struct rtw89_fw_info {
@@ -4561,7 +4569,7 @@ enum rtw89_sar_subband {
RTW89_SAR_2GHZ_SUBBAND,
RTW89_SAR_5GHZ_SUBBAND_1_2, /* U-NII-1 and U-NII-2 */
RTW89_SAR_5GHZ_SUBBAND_2_E, /* U-NII-2-Extended */
- RTW89_SAR_5GHZ_SUBBAND_3, /* U-NII-3 */
+ RTW89_SAR_5GHZ_SUBBAND_3_4, /* U-NII-3 and U-NII-4 */
RTW89_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */
RTW89_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */
RTW89_SAR_6GHZ_SUBBAND_6, /* U-NII-6 */
@@ -4623,7 +4631,7 @@ enum rtw89_chanctx_changes {
};
enum rtw89_entity_mode {
- RTW89_ENTITY_MODE_SCC,
+ RTW89_ENTITY_MODE_SCC_OR_SMLD,
RTW89_ENTITY_MODE_MCC_PREPARE,
RTW89_ENTITY_MODE_MCC,
@@ -4632,6 +4640,16 @@ enum rtw89_entity_mode {
RTW89_ENTITY_MODE_UNHANDLED = -ESRCH,
};
+#define RTW89_MAX_INTERFACE_NUM 2
+
+/* only valid when running with chanctx_ops */
+struct rtw89_entity_mgnt {
+ struct list_head active_list;
+ struct rtw89_vif *active_roles[RTW89_MAX_INTERFACE_NUM];
+ enum rtw89_chanctx_idx chanctx_tbl[RTW89_MAX_INTERFACE_NUM]
+ [__RTW89_MLD_MAX_LINK_NUM];
+};
+
struct rtw89_chanctx {
struct cfg80211_chan_def chandef;
struct rtw89_chan chan;
@@ -4650,8 +4668,12 @@ struct rtw89_edcca_bak {
enum rtw89_dm_type {
RTW89_DM_DYNAMIC_EDCCA,
+ RTW89_DM_THERMAL_PROTECT,
};
+#define RTW89_THERMAL_PROT_LV_MAX 5
+#define RTW89_THERMAL_PROT_STEP 19 /* -19% for each level */
+
struct rtw89_hal {
u32 rx_fltr;
u8 cv;
@@ -4672,12 +4694,16 @@ struct rtw89_hal {
struct rtw89_chanctx chanctx[NUM_OF_RTW89_CHANCTX];
struct cfg80211_chan_def roc_chandef;
- bool entity_active;
+ bool entity_active[RTW89_PHY_MAX];
bool entity_pause;
enum rtw89_entity_mode entity_mode;
+ struct rtw89_entity_mgnt entity_mgnt;
struct rtw89_edcca_bak edcca_bak;
u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */
+
+ u8 thermal_prot_th;
+ u8 thermal_prot_lv; /* 0 ~ RTW89_THERMAL_PROT_LV_MAX */
};
#define RTW89_MAX_MAC_ID_NUM 128
@@ -4710,10 +4736,22 @@ enum rtw89_flags {
enum rtw89_quirks {
RTW89_QUIRK_PCI_BER,
+ RTW89_QUIRK_THERMAL_PROT_120C,
+ RTW89_QUIRK_THERMAL_PROT_110C,
NUM_OF_RTW89_QUIRKS,
};
+enum rtw89_custid {
+ RTW89_CUSTID_NONE,
+ RTW89_CUSTID_ACER,
+ RTW89_CUSTID_AMD,
+ RTW89_CUSTID_ASUS,
+ RTW89_CUSTID_DELL,
+ RTW89_CUSTID_HP,
+ RTW89_CUSTID_LENOVO,
+};
+
enum rtw89_pkt_drop_sel {
RTW89_PKT_DROP_SEL_MACID_BE_ONCE,
RTW89_PKT_DROP_SEL_MACID_BK_ONCE,
@@ -4750,6 +4788,8 @@ DECLARE_EWMA(thermal, 4, 4);
struct rtw89_phy_stat {
struct ewma_thermal avg_thermal[RF_PATH_MAX];
+ u8 last_thermal_max;
+ struct ewma_rssi bcn_rssi;
struct rtw89_pkt_stat cur_pkt_stat;
struct rtw89_pkt_stat last_pkt_stat;
};
@@ -4791,13 +4831,17 @@ enum rtw89_rfk_chs_nrs {
RTW89_RFK_CHS_NR = __RTW89_RFK_CHS_NR_V1,
};
-struct rtw89_rfk_mcc_info {
+struct rtw89_rfk_mcc_info_data {
u8 ch[RTW89_RFK_CHS_NR];
u8 band[RTW89_RFK_CHS_NR];
u8 bw[RTW89_RFK_CHS_NR];
u8 table_idx;
};
+struct rtw89_rfk_mcc_info {
+ struct rtw89_rfk_mcc_info_data data[2];
+};
+
#define RTW89_IQK_CHS_NR 2
#define RTW89_IQK_PATH_NR 4
@@ -4902,6 +4946,7 @@ struct rtw89_agc_gaincode_set {
#define IGI_RSSI_TH_NUM 5
#define FA_TH_NUM 4
+#define TIA_LNA_OP1DB_NUM 8
#define LNA_GAIN_NUM 7
#define TIA_GAIN_NUM 2
struct rtw89_dig_info {
@@ -5196,7 +5241,7 @@ struct rtw89_early_h2c {
};
struct rtw89_hw_scan_info {
- struct ieee80211_vif *scanning_vif;
+ struct rtw89_vif_link *scanning_vif;
struct list_head pkt_list[NUM_NL80211_BANDS];
struct rtw89_chan op_chan;
bool abort;
@@ -5371,7 +5416,7 @@ struct rtw89_wow_aoac_report {
};
struct rtw89_wow_param {
- struct ieee80211_vif *wow_vif;
+ struct rtw89_vif_link *rtwvif_link;
DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM);
struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM];
struct rtw89_wow_key_info key_info;
@@ -5408,7 +5453,7 @@ struct rtw89_mcc_policy {
};
struct rtw89_mcc_role {
- struct rtw89_vif *rtwvif;
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_mcc_policy policy;
struct rtw89_mcc_limit limit;
@@ -5509,6 +5554,7 @@ struct rtw89_dev {
struct rtw89_efuse efuse;
struct rtw89_traffic_stats stats;
struct rtw89_rfe_data *rfe_data;
+ enum rtw89_custid custid;
/* ensures exclusive access from mac80211 callbacks */
struct mutex mutex;
@@ -5608,6 +5654,122 @@ struct rtw89_dev {
u8 priv[] __aligned(sizeof(void *));
};
+struct rtw89_vif {
+ struct rtw89_dev *rtwdev;
+ struct list_head list;
+ struct list_head mgnt_entry;
+
+ u8 mac_addr[ETH_ALEN];
+ __be32 ip_addr;
+
+ struct rtw89_traffic_stats stats;
+ u32 tdls_peer;
+
+ struct ieee80211_scan_ies *scan_ies;
+ struct cfg80211_scan_request *scan_req;
+
+ struct rtw89_roc roc;
+ bool offchan;
+
+ u8 links_inst_valid_num;
+ DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
+ struct rtw89_vif_link *links[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct rtw89_vif_link links_inst[] __counted_by(links_inst_valid_num);
+};
+
+static inline bool rtw89_vif_assign_link_is_valid(struct rtw89_vif_link **rtwvif_link,
+ const struct rtw89_vif *rtwvif,
+ unsigned int link_id)
+{
+ *rtwvif_link = rtwvif->links[link_id];
+ return !!*rtwvif_link;
+}
+
+#define rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) \
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \
+ if (rtw89_vif_assign_link_is_valid(&(rtwvif_link), rtwvif, link_id))
+
+struct rtw89_sta {
+ struct rtw89_dev *rtwdev;
+ struct rtw89_vif *rtwvif;
+
+ bool disassoc;
+
+ struct sk_buff_head roc_queue;
+
+ struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
+ DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS);
+
+ u8 links_inst_valid_num;
+ DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
+ struct rtw89_sta_link *links[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct rtw89_sta_link links_inst[] __counted_by(links_inst_valid_num);
+};
+
+static inline bool rtw89_sta_assign_link_is_valid(struct rtw89_sta_link **rtwsta_link,
+ const struct rtw89_sta *rtwsta,
+ unsigned int link_id)
+{
+ *rtwsta_link = rtwsta->links[link_id];
+ return !!*rtwsta_link;
+}
+
+#define rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) \
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \
+ if (rtw89_sta_assign_link_is_valid(&(rtwsta_link), rtwsta, link_id))
+
+static inline u8 rtw89_vif_get_main_macid(struct rtw89_vif *rtwvif)
+{
+ /* const after init, so no need to check if active first */
+ return rtwvif->links_inst[0].mac_id;
+}
+
+static inline u8 rtw89_vif_get_main_port(struct rtw89_vif *rtwvif)
+{
+ /* const after init, so no need to check if active first */
+ return rtwvif->links_inst[0].port;
+}
+
+static inline struct rtw89_vif_link *
+rtw89_vif_get_link_inst(struct rtw89_vif *rtwvif, u8 index)
+{
+ if (index >= rtwvif->links_inst_valid_num ||
+ !test_bit(index, rtwvif->links_inst_map))
+ return NULL;
+ return &rtwvif->links_inst[index];
+}
+
+static inline
+u8 rtw89_vif_link_inst_get_index(struct rtw89_vif_link *rtwvif_link)
+{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+
+ return rtwvif_link - rtwvif->links_inst;
+}
+
+static inline u8 rtw89_sta_get_main_macid(struct rtw89_sta *rtwsta)
+{
+ /* const after init, so no need to check if active first */
+ return rtwsta->links_inst[0].mac_id;
+}
+
+static inline struct rtw89_sta_link *
+rtw89_sta_get_link_inst(struct rtw89_sta *rtwsta, u8 index)
+{
+ if (index >= rtwsta->links_inst_valid_num ||
+ !test_bit(index, rtwsta->links_inst_map))
+ return NULL;
+ return &rtwsta->links_inst[index];
+}
+
+static inline
+u8 rtw89_sta_link_inst_get_index(struct rtw89_sta_link *rtwsta_link)
+{
+ struct rtw89_sta *rtwsta = rtwsta_link->rtwsta;
+
+ return rtwsta_link - rtwsta->links_inst;
+}
+
static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
@@ -5972,9 +6134,26 @@ static inline struct ieee80211_vif *rtwvif_to_vif_safe(struct rtw89_vif *rtwvif)
return rtwvif ? rtwvif_to_vif(rtwvif) : NULL;
}
+static inline
+struct ieee80211_vif *rtwvif_link_to_vif(struct rtw89_vif_link *rtwvif_link)
+{
+ return rtwvif_to_vif(rtwvif_link->rtwvif);
+}
+
+static inline
+struct ieee80211_vif *rtwvif_link_to_vif_safe(struct rtw89_vif_link *rtwvif_link)
+{
+ return rtwvif_link ? rtwvif_link_to_vif(rtwvif_link) : NULL;
+}
+
+static inline struct rtw89_vif *vif_to_rtwvif(struct ieee80211_vif *vif)
+{
+ return (struct rtw89_vif *)vif->drv_priv;
+}
+
static inline struct rtw89_vif *vif_to_rtwvif_safe(struct ieee80211_vif *vif)
{
- return vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
+ return vif ? vif_to_rtwvif(vif) : NULL;
}
static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta)
@@ -5989,11 +6168,88 @@ static inline struct ieee80211_sta *rtwsta_to_sta_safe(struct rtw89_sta *rtwsta)
return rtwsta ? rtwsta_to_sta(rtwsta) : NULL;
}
+static inline
+struct ieee80211_sta *rtwsta_link_to_sta(struct rtw89_sta_link *rtwsta_link)
+{
+ return rtwsta_to_sta(rtwsta_link->rtwsta);
+}
+
+static inline
+struct ieee80211_sta *rtwsta_link_to_sta_safe(struct rtw89_sta_link *rtwsta_link)
+{
+ return rtwsta_link ? rtwsta_link_to_sta(rtwsta_link) : NULL;
+}
+
+static inline struct rtw89_sta *sta_to_rtwsta(struct ieee80211_sta *sta)
+{
+ return (struct rtw89_sta *)sta->drv_priv;
+}
+
static inline struct rtw89_sta *sta_to_rtwsta_safe(struct ieee80211_sta *sta)
{
- return sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
+ return sta ? sta_to_rtwsta(sta) : NULL;
+}
+
+static inline struct ieee80211_bss_conf *
+__rtw89_vif_rcu_dereference_link(struct rtw89_vif_link *rtwvif_link, bool *nolink)
+{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct ieee80211_bss_conf *bss_conf;
+
+ bss_conf = rcu_dereference(vif->link_conf[rtwvif_link->link_id]);
+ if (unlikely(!bss_conf)) {
+ *nolink = true;
+ return &vif->bss_conf;
+ }
+
+ *nolink = false;
+ return bss_conf;
+}
+
+#define rtw89_vif_rcu_dereference_link(rtwvif_link, assert) \
+({ \
+ typeof(rtwvif_link) p = rtwvif_link; \
+ struct ieee80211_bss_conf *bss_conf; \
+ bool nolink; \
+ \
+ bss_conf = __rtw89_vif_rcu_dereference_link(p, &nolink); \
+ if (unlikely(nolink) && (assert)) \
+ rtw89_err(p->rtwvif->rtwdev, \
+ "%s: cannot find exact bss_conf for link_id %u\n",\
+ __func__, p->link_id); \
+ bss_conf; \
+})
+
+static inline struct ieee80211_link_sta *
+__rtw89_sta_rcu_dereference_link(struct rtw89_sta_link *rtwsta_link, bool *nolink)
+{
+ struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
+ struct ieee80211_link_sta *link_sta;
+
+ link_sta = rcu_dereference(sta->link[rtwsta_link->link_id]);
+ if (unlikely(!link_sta)) {
+ *nolink = true;
+ return &sta->deflink;
+ }
+
+ *nolink = false;
+ return link_sta;
}
+#define rtw89_sta_rcu_dereference_link(rtwsta_link, assert) \
+({ \
+ typeof(rtwsta_link) p = rtwsta_link; \
+ struct ieee80211_link_sta *link_sta; \
+ bool nolink; \
+ \
+ link_sta = __rtw89_sta_rcu_dereference_link(p, &nolink); \
+ if (unlikely(nolink) && (assert)) \
+ rtw89_err(p->rtwsta->rtwdev, \
+ "%s: cannot find exact link_sta for link_id %u\n",\
+ __func__, p->link_id); \
+ link_sta; \
+})
+
static inline u8 rtw89_hw_to_rate_info_bw(enum rtw89_bandwidth hw_bw)
{
if (hw_bw == RTW89_CHANNEL_WIDTH_160)
@@ -6078,29 +6334,29 @@ enum nl80211_he_ru_alloc rtw89_he_rua_to_ru_alloc(u16 rua)
}
static inline
-struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- if (rtwsta) {
- struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
+ if (rtwsta_link) {
+ struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls)
- return &rtwsta->addr_cam;
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls)
+ return &rtwsta_link->addr_cam;
}
- return &rtwvif->addr_cam;
+ return &rtwvif_link->addr_cam;
}
static inline
-struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- if (rtwsta) {
- struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
+ if (rtwsta_link) {
+ struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link);
if (sta->tdls)
- return &rtwsta->bssid_cam;
+ return &rtwsta_link->bssid_cam;
}
- return &rtwvif->bssid_cam;
+ return &rtwvif_link->bssid_cam;
}
static inline
@@ -6157,13 +6413,21 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev,
}
static inline
+const struct rtw89_chan_rcd *rtw89_chan_rcd_get_by_chan(const struct rtw89_chan *chan)
+{
+ const struct rtw89_chanctx *chanctx =
+ container_of_const(chan, struct rtw89_chanctx, chan);
+
+ return &chanctx->rcd;
+}
+
+static inline
const struct rtw89_chan *rtw89_scan_chan_get(struct rtw89_dev *rtwdev)
{
- struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
+ struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
- if (rtwvif)
- return rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
+ if (rtwvif_link)
+ return rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
else
return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
}
@@ -6240,12 +6504,12 @@ static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev)
}
static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (chip->ops->rfk_channel)
- chip->ops->rfk_channel(rtwdev, rtwvif);
+ chip->ops->rfk_channel(rtwdev, rtwvif_link);
}
static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev,
@@ -6259,12 +6523,12 @@ static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev,
}
static inline void rtw89_chip_rfk_scan(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool start)
+ struct rtw89_vif_link *rtwvif_link, bool start)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (chip->ops->rfk_scan)
- chip->ops->rfk_scan(rtwdev, rtwvif, start);
+ chip->ops->rfk_scan(rtwdev, rtwvif_link, start);
}
static inline void rtw89_chip_rfk_track(struct rtw89_dev *rtwdev)
@@ -6279,8 +6543,12 @@ static inline void rtw89_chip_set_txpwr_ctrl(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- if (chip->ops->set_txpwr_ctrl)
- chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0);
+ if (!chip->ops->set_txpwr_ctrl)
+ return;
+
+ chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_1);
}
static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev)
@@ -6291,8 +6559,8 @@ static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev)
chip->ops->power_trim(rtwdev);
}
-static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev,
- enum rtw89_phy_idx phy_idx)
+static inline void __rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -6300,6 +6568,13 @@ static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev,
chip->ops->init_txpwr_unit(rtwdev, phy_idx);
}
+static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev)
+{
+ __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_1);
+}
+
static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev,
enum rtw89_rf_path rf_path)
{
@@ -6347,20 +6622,6 @@ static inline void rtw89_chip_cfg_txrx_path(struct rtw89_dev *rtwdev)
chip->ops->cfg_txrx_path(rtwdev);
}
-static inline
-void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif)
-{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- const struct rtw89_chip_info *chip = rtwdev->chip;
-
- if (!vif->bss_conf.he_support || !vif->cfg.assoc)
- return;
-
- if (chip->ops->set_txpwr_ul_tb_offset)
- chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif->mac_idx);
-}
-
static inline void rtw89_chip_digital_pwr_comp(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx)
{
@@ -6457,14 +6718,14 @@ int rtw89_chip_resume_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en)
static inline
int rtw89_chip_h2c_dctl_sec_cam(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (!chip->ops->h2c_dctl_sec_cam)
return 0;
- return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
+ return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link);
}
static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
@@ -6479,13 +6740,14 @@ static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
return hdr->addr3;
}
-static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta)
+static inline
+bool rtw89_sta_has_beamformer_cap(struct ieee80211_link_sta *link_sta)
{
- if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) ||
- (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
+ if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) ||
+ (link_sta->he_cap.he_cap_elem.phy_cap_info[3] &
IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
- (sta->deflink.he_cap.he_cap_elem.phy_cap_info[4] &
+ (link_sta->he_cap.he_cap_elem.phy_cap_info[4] &
IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER))
return true;
return false;
@@ -6605,21 +6867,21 @@ void rtw89_core_napi_start(struct rtw89_dev *rtwdev);
void rtw89_core_napi_stop(struct rtw89_dev *rtwdev);
int rtw89_core_napi_init(struct rtw89_dev *rtwdev);
void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev);
-int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
+int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
+int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
+int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
+int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_config);
@@ -6635,22 +6897,40 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev);
u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev);
void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id);
+void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ u8 mac_id, u8 port);
+void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta, u8 mac_id);
+struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif,
+ unsigned int link_id);
+void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id);
+struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta,
+ unsigned int link_id);
+void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id);
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev);
void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef);
void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
struct rtw89_chan *chan);
int rtw89_set_channel(struct rtw89_dev *rtwdev);
-void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_chan *chan);
u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size);
void rtw89_core_release_bit_map(unsigned long *addr, u8 bit);
void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits);
int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx);
+ struct rtw89_sta_link *rtwsta_link, u8 tid,
+ u8 *cam_idx);
int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx);
-void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc);
+ struct rtw89_sta_link *rtwsta_link, u8 tid,
+ u8 *cam_idx);
+void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta);
+void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta);
+void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta);
+void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc);
int rtw89_chip_info_setup(struct rtw89_dev *rtwdev);
+void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link);
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate);
int rtw89_regd_setup(struct rtw89_dev *rtwdev);
int rtw89_regd_init(struct rtw89_dev *rtwdev,
@@ -6667,13 +6947,15 @@ void rtw89_core_update_beacon_work(struct work_struct *work);
void rtw89_roc_work(struct work_struct *work);
void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
-void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr, bool hw_scan);
void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif, bool hw_scan);
-int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link, bool hw_scan);
+int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool active);
-void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf);
void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 29f85210f919..6abd88fa80ba 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -3506,7 +3506,9 @@ out:
return count;
}
-static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
+static void rtw89_sta_link_info_get_iter(struct seq_file *m,
+ struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link)
{
static const char * const he_gi_str[] = {
[NL80211_RATE_INFO_HE_GI_0_8] = "0.8",
@@ -3518,20 +3520,26 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
[NL80211_RATE_INFO_EHT_GI_1_6] = "1.6",
[NL80211_RATE_INFO_EHT_GI_3_2] = "3.2",
};
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rate_info *rate = &rtwsta->ra_report.txrate;
- struct ieee80211_rx_status *status = &rtwsta->rx_status;
- struct seq_file *m = (struct seq_file *)data;
- struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rate_info *rate = &rtwsta_link->ra_report.txrate;
+ struct ieee80211_rx_status *status = &rtwsta_link->rx_status;
struct rtw89_hal *hal = &rtwdev->hal;
u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity;
+ struct ieee80211_link_sta *link_sta;
u8 evm_min, evm_max, evm_1ss;
+ u16 max_rc_amsdu_len;
u8 rssi;
u8 snr;
int i;
- seq_printf(m, "TX rate [%d]: ", rtwsta->mac_id);
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ max_rc_amsdu_len = link_sta->agg.max_rc_amsdu_len;
+
+ rcu_read_unlock();
+
+ seq_printf(m, "TX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id);
if (rate->flags & RATE_INFO_FLAGS_MCS)
seq_printf(m, "HT MCS-%d%s", rate->mcs,
@@ -3549,13 +3557,13 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
eht_gi_str[rate->eht_gi] : "N/A");
else
seq_printf(m, "Legacy %d", rate->legacy);
- seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : "");
+ seq_printf(m, "%s", rtwsta_link->ra_report.might_fallback_legacy ? " FB_G" : "");
seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw));
- seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate);
- seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait,
- sta->deflink.agg.max_rc_amsdu_len);
+ seq_printf(m, " (hw_rate=0x%x)", rtwsta_link->ra_report.hw_rate);
+ seq_printf(m, " ==> agg_wait=%d (%d)\n", rtwsta_link->max_agg_wait,
+ max_rc_amsdu_len);
- seq_printf(m, "RX rate [%d]: ", rtwsta->mac_id);
+ seq_printf(m, "RX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id);
switch (status->encoding) {
case RX_ENC_LEGACY:
@@ -3582,24 +3590,24 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
break;
}
seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw));
- seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->rx_hw_rate);
+ seq_printf(m, " (hw_rate=0x%x)\n", rtwsta_link->rx_hw_rate);
- rssi = ewma_rssi_read(&rtwsta->avg_rssi);
+ rssi = ewma_rssi_read(&rtwsta_link->avg_rssi);
seq_printf(m, "RSSI: %d dBm (raw=%d, prev=%d) [",
- RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta->prev_rssi);
+ RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta_link->prev_rssi);
for (i = 0; i < ant_num; i++) {
- rssi = ewma_rssi_read(&rtwsta->rssi[i]);
+ rssi = ewma_rssi_read(&rtwsta_link->rssi[i]);
seq_printf(m, "%d%s%s", RTW89_RSSI_RAW_TO_DBM(rssi),
ant_asterisk && (hal->antenna_tx & BIT(i)) ? "*" : "",
i + 1 == ant_num ? "" : ", ");
}
seq_puts(m, "]\n");
- evm_1ss = ewma_evm_read(&rtwsta->evm_1ss);
+ evm_1ss = ewma_evm_read(&rtwsta_link->evm_1ss);
seq_printf(m, "EVM: [%2u.%02u, ", evm_1ss >> 2, (evm_1ss & 0x3) * 25);
for (i = 0; i < (hal->ant_diversity ? 2 : 1); i++) {
- evm_min = ewma_evm_read(&rtwsta->evm_min[i]);
- evm_max = ewma_evm_read(&rtwsta->evm_max[i]);
+ evm_min = ewma_evm_read(&rtwsta_link->evm_min[i]);
+ evm_max = ewma_evm_read(&rtwsta_link->evm_max[i]);
seq_printf(m, "%s(%2u.%02u, %2u.%02u)", i == 0 ? "" : " ",
evm_min >> 2, (evm_min & 0x3) * 25,
@@ -3607,10 +3615,22 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
}
seq_puts(m, "]\t");
- snr = ewma_snr_read(&rtwsta->avg_snr);
+ snr = ewma_snr_read(&rtwsta_link->avg_snr);
seq_printf(m, "SNR: %u\n", snr);
}
+static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct seq_file *m = (struct seq_file *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
+ rtw89_sta_link_info_get_iter(m, rtwdev, rtwsta_link);
+}
+
static void
rtw89_debug_append_rx_rate(struct seq_file *m, struct rtw89_pkt_stat *pkt_stat,
enum rtw89_hw_rate first_rate, int len)
@@ -3652,14 +3672,22 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_rx_rate_cnt_info *info;
+ struct rtw89_hal *hal = &rtwdev->hal;
enum rtw89_hw_rate first_rate;
+ u8 rssi;
int i;
- seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n",
- stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv,
+ rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
+
+ seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d",
+ stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv);
+ if (hal->thermal_prot_lv)
+ seq_printf(m, ", duty: %d%%",
+ 100 - hal->thermal_prot_lv * RTW89_THERMAL_PROT_STEP);
+ seq_printf(m, "), RX: %u [%u] Mbps (lv: %d)\n",
stats->rx_throughput, stats->rx_throughput_raw, stats->rx_tfc_lv);
- seq_printf(m, "Beacon: %u, TF: %u\n", pkt_stat->beacon_nr,
- stats->rx_tf_periodic);
+ seq_printf(m, "Beacon: %u (%d dBm), TF: %u\n", pkt_stat->beacon_nr,
+ RTW89_RSSI_RAW_TO_DBM(rssi), stats->rx_tf_periodic);
seq_printf(m, "Avg packet length: TX=%u, RX=%u\n", stats->tx_avg_len,
stats->rx_avg_len);
@@ -3737,28 +3765,41 @@ static void rtw89_dump_pkt_offload(struct seq_file *m, struct list_head *pkt_lis
seq_puts(m, "\n");
}
+static void rtw89_vif_link_ids_get(struct seq_file *m, u8 *mac,
+ struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
+
+ seq_printf(m, " [%u] %pM\n", rtwvif_link->mac_id, rtwvif_link->mac_addr);
+ seq_printf(m, "\tlink_id=%u\n", rtwvif_link->link_id);
+ seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx);
+ rtw89_dump_addr_cam(m, rtwdev, &rtwvif_link->addr_cam);
+ rtw89_dump_pkt_offload(m, &rtwvif_link->general_pkt_list,
+ "\tpkt_ofld[GENERAL]: ");
+}
+
static
void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_dev *rtwdev = rtwvif->rtwdev;
struct seq_file *m = (struct seq_file *)data;
- struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_dev *rtwdev = rtwvif->rtwdev;
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
- seq_printf(m, "VIF [%d] %pM\n", rtwvif->mac_id, rtwvif->mac_addr);
- seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx);
- rtw89_dump_addr_cam(m, rtwdev, &rtwvif->addr_cam);
- rtw89_dump_pkt_offload(m, &rtwvif->general_pkt_list, "\tpkt_ofld[GENERAL]: ");
+ seq_printf(m, "VIF %pM\n", rtwvif->mac_addr);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_vif_link_ids_get(m, mac, rtwdev, rtwvif_link);
}
-static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta)
+static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
- struct rtw89_dev *rtwdev = rtwvif->rtwdev;
struct rtw89_ba_cam_entry *entry;
bool first = true;
- list_for_each_entry(entry, &rtwsta->ba_cam_list, list) {
+ list_for_each_entry(entry, &rtwsta_link->ba_cam_list, list) {
if (first) {
seq_puts(m, "\tba_cam ");
first = false;
@@ -3771,16 +3812,36 @@ static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta)
seq_puts(m, "\n");
}
+static void rtw89_sta_link_ids_get(struct seq_file *m,
+ struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link)
+{
+ struct ieee80211_link_sta *link_sta;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ seq_printf(m, " [%u] %pM\n", rtwsta_link->mac_id, link_sta->addr);
+
+ rcu_read_unlock();
+
+ seq_printf(m, "\tlink_id=%u\n", rtwsta_link->link_id);
+ rtw89_dump_addr_cam(m, rtwdev, &rtwsta_link->addr_cam);
+ rtw89_dump_ba_cam(m, rtwdev, rtwsta_link);
+}
+
static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_dev *rtwdev = rtwsta->rtwdev;
struct seq_file *m = (struct seq_file *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
- seq_printf(m, "STA [%d] %pM %s\n", rtwsta->mac_id, sta->addr,
- sta->tdls ? "(TDLS)" : "");
- rtw89_dump_addr_cam(m, rtwdev, &rtwsta->addr_cam);
- rtw89_dump_ba_cam(m, rtwsta);
+ seq_printf(m, "STA %pM %s\n", sta->addr, sta->tdls ? "(TDLS)" : "");
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
+ rtw89_sta_link_ids_get(m, rtwdev, rtwsta_link);
}
static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v)
@@ -3830,6 +3891,7 @@ static const struct rtw89_disabled_dm_info {
const char *name;
} rtw89_disabled_dm_infos[] = {
DM_INFO(DYNAMIC_EDCCA),
+ DM_INFO(THERMAL_PROTECT),
};
static int
diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c
index e1236079a84a..6c6c763510af 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse.c
+++ b/drivers/net/wireless/realtek/rtw89/efuse.c
@@ -11,11 +11,38 @@
#define EF_CV_MASK GENMASK(7, 4)
#define EF_CV_INV 15
+#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0)
+#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4)
+#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0)
+#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6)
+
+#define EFUSE_EXTERNALPN_ADDR_AX 0x5EC
+#define EFUSE_CUSTOMER_ADDR_AX 0x5ED
+#define EFUSE_SERIALNUM_ADDR_AX 0x5ED
+
+#define EFUSE_B1_EXTERNALPN_MASK GENMASK(7, 0)
+#define EFUSE_B2_CUSTOMER_MASK GENMASK(3, 0)
+#define EFUSE_B2_SERIALNUM_MASK GENMASK(6, 4)
+
+#define OTP_KEY_INFO_NUM 2
+
+static const u8 otp_key_info_externalPN[OTP_KEY_INFO_NUM] = {0x0, 0x0};
+static const u8 otp_key_info_customer[OTP_KEY_INFO_NUM] = {0x0, 0x1};
+static const u8 otp_key_info_serialNum[OTP_KEY_INFO_NUM] = {0x0, 0x1};
+
enum rtw89_efuse_bank {
RTW89_EFUSE_BANK_WIFI,
RTW89_EFUSE_BANK_BT,
};
+enum rtw89_efuse_mss_dev_type {
+ MSS_DEV_TYPE_FWSEC_DEF = 0xF,
+ MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC,
+ MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA,
+ MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9,
+ MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6,
+};
+
static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
enum rtw89_efuse_bank bank)
{
@@ -354,3 +381,126 @@ int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv)
return 0;
}
EXPORT_SYMBOL(rtw89_read_efuse_ver);
+
+static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type)
+{
+ switch (mss_dev_type) {
+ case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX:
+ mss_dev_type = 0x0;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB:
+ mss_dev_type = 0x1;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB:
+ mss_dev_type = 0x2;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX:
+ mss_dev_type = 0x3;
+ break;
+ case MSS_DEV_TYPE_FWSEC_DEF:
+ mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF;
+ break;
+ default:
+ rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type);
+ mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV;
+ break;
+ }
+
+ return mss_dev_type;
+}
+
+int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u8 mss_dev_type;
+
+ if (chip->chip_id == RTL8852B && b1 == 0xFF && b2 == 0x6E) {
+ mss_dev_type = MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB;
+ sec->mss_cust_idx = 0;
+ sec->mss_key_num = 0;
+
+ goto mss_dev_type;
+ }
+
+ mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK);
+ sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) |
+ u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4);
+ sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK);
+
+mss_dev_type:
+ sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type);
+ if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) {
+ rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type);
+ return -ENOENT;
+ }
+
+ sec->can_mss_v1 = true;
+
+ return 0;
+}
+
+static
+int rtw89_efuse_recognize_mss_index_v0(struct rtw89_dev *rtwdev, u8 b1, u8 b2)
+{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u8 externalPN;
+ u8 serialNum;
+ u8 customer;
+ u8 i;
+
+ externalPN = 0xFF - u8_get_bits(b1, EFUSE_B1_EXTERNALPN_MASK);
+ customer = 0xF - u8_get_bits(b2, EFUSE_B2_CUSTOMER_MASK);
+ serialNum = 0x7 - u8_get_bits(b2, EFUSE_B2_SERIALNUM_MASK);
+
+ for (i = 0; i < OTP_KEY_INFO_NUM; i++) {
+ if (externalPN == otp_key_info_externalPN[i] &&
+ customer == otp_key_info_customer[i] &&
+ serialNum == otp_key_info_serialNum[i]) {
+ sec->mss_idx = i;
+ sec->can_mss_v0 = true;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u32 sec_addr = EFUSE_EXTERNALPN_ADDR_AX;
+ u32 sec_size = 2;
+ u8 sec_map[2];
+ u8 b1, b2;
+ int ret;
+
+ ret = rtw89_dump_physical_efuse_map(rtwdev, sec_map,
+ sec_addr, sec_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump secsel map\n");
+ return ret;
+ }
+
+ b1 = sec_map[0];
+ b2 = sec_map[1];
+
+ if (b1 == 0xFF && b2 == 0xFF)
+ return 0;
+
+ rtw89_efuse_recognize_mss_index_v0(rtwdev, b1, b2);
+ rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2);
+ if (!sec->can_mss_v1 && !sec->can_mss_v0)
+ goto out;
+
+ sec->secure_boot = true;
+
+out:
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "MSS secure_boot=%d(%d/%d) dev_type=%d cust_idx=%d key_num=%d mss_index=%d\n",
+ sec->secure_boot, sec->can_mss_v0, sec->can_mss_v1,
+ sec->mss_dev_type, sec->mss_cust_idx,
+ sec->mss_key_num, sec->mss_idx);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h
index 72416f56a071..a96fc1044791 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse.h
+++ b/drivers/net/wireless/realtek/rtw89/efuse.h
@@ -23,6 +23,8 @@ 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);
+int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2);
+int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev);
int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c
index 0be26d5fdf7c..64768923b0f0 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse_be.c
+++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c
@@ -8,11 +8,7 @@
#include "reg.h"
#define EFUSE_EXTERNALPN_ADDR_BE 0x1580
-#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0)
-#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4)
#define EFUSE_SERIALNUM_ADDR_BE 0x1581
-#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0)
-#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6)
#define EFUSE_SB_CRYP_SEL_ADDR 0x1582
#define EFUSE_SB_CRYP_SEL_SIZE 2
#define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF
@@ -20,14 +16,6 @@
#define EFUSE_SEC_BE_START 0x1580
#define EFUSE_SEC_BE_SIZE 4
-enum rtw89_efuse_mss_dev_type {
- MSS_DEV_TYPE_FWSEC_DEF = 0xF,
- MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC,
- MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA,
- MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9,
- MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6,
-};
-
static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = {
0x8000100, 0xC000180
};
@@ -477,33 +465,6 @@ static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel)
return sb_cryp_sel_v + low_bit;
}
-static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type)
-{
- switch (mss_dev_type) {
- case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX:
- mss_dev_type = 0x0;
- break;
- case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB:
- mss_dev_type = 0x1;
- break;
- case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB:
- mss_dev_type = 0x2;
- break;
- case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX:
- mss_dev_type = 0x3;
- break;
- case MSS_DEV_TYPE_FWSEC_DEF:
- mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF;
- break;
- default:
- rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type);
- mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV;
- break;
- }
-
- return mss_dev_type;
-}
-
int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
{
struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
@@ -511,7 +472,6 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
u32 sec_size = EFUSE_SEC_BE_SIZE;
u16 sb_cryp_sel, sb_cryp_sel_idx;
u8 sec_map[EFUSE_SEC_BE_SIZE];
- u8 mss_dev_type;
u8 b1, b2;
int ret;
@@ -538,16 +498,9 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr];
b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr];
- mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK);
- sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) |
- u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4);
- sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK);
-
- sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type);
- if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) {
- rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type);
+ ret = rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2);
+ if (ret)
goto out;
- }
sec->secure_boot = true;
@@ -559,4 +512,3 @@ out:
return 0;
}
-EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be);
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index d9b0e7ebe619..2191c037d72e 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -56,6 +56,11 @@ static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev,
struct sk_buff *skb);
static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_wait_info *wait, unsigned int cond);
+static int __parse_security_section(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr_section_info *section_info,
+ const void *content,
+ u32 *mssc_len);
static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len,
bool header)
@@ -124,13 +129,16 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
struct rtw89_fw_bin_info *info)
{
const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_fw_hdr_section_info *section_info;
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
const struct rtw89_fw_dynhdr_hdr *fwdynhdr;
const struct rtw89_fw_hdr_section *section;
const u8 *fw_end = fw + len;
const u8 *bin;
u32 base_hdr_len;
- u32 mssc_len = 0;
+ u32 mssc_len;
+ int ret;
u32 i;
if (!info)
@@ -139,6 +147,7 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM);
base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR);
+ info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_W7_IDMEM_SHARE_MODE);
if (info->dynamic_hdr_en) {
info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN);
@@ -161,26 +170,47 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
section = &fw_hdr->sections[i];
section_info->type =
le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE);
- if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
- section_info->mssc =
- le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC);
- mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN;
- } else {
- section_info->mssc = 0;
- }
-
section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE);
+
if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM))
section_info->len += FWDL_SECTION_CHKSUM_LEN;
section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL);
section_info->dladdr =
le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff;
section_info->addr = bin;
- bin += section_info->len;
+
+ if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
+ section_info->mssc =
+ le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC);
+
+ ret = __parse_security_section(rtwdev, info, section_info,
+ bin, &mssc_len);
+ if (ret)
+ return ret;
+
+ if (sec->secure_boot && chip->chip_id == RTL8852B)
+ section_info->len_override = 960;
+ } else {
+ section_info->mssc = 0;
+ mssc_len = 0;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "section[%d] type=%d len=0x%-6x mssc=%d mssc_len=%d addr=%tx\n",
+ i, section_info->type, section_info->len,
+ section_info->mssc, mssc_len, bin - fw);
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ " ignore=%d key_addr=%p (0x%tx) key_len=%d key_idx=%d\n",
+ section_info->ignore, section_info->key_addr,
+ section_info->key_addr ?
+ section_info->key_addr - section_info->addr : 0,
+ section_info->key_len, section_info->key_idx);
+
+ bin += section_info->len + mssc_len;
section_info++;
}
- if (fw_end != bin + mssc_len) {
+ if (fw_end != bin) {
rtw89_err(rtwdev, "[ERR]fw bin size\n");
return -EINVAL;
}
@@ -235,7 +265,6 @@ static int __get_mssc_key_idx(struct rtw89_dev *rtwdev,
static int __parse_formatted_mssc(struct rtw89_dev *rtwdev,
struct rtw89_fw_bin_info *info,
struct rtw89_fw_hdr_section_info *section_info,
- const struct rtw89_fw_hdr_section_v1 *section,
const void *content,
u32 *mssc_len)
{
@@ -318,18 +347,15 @@ ignore:
static int __parse_security_section(struct rtw89_dev *rtwdev,
struct rtw89_fw_bin_info *info,
struct rtw89_fw_hdr_section_info *section_info,
- const struct rtw89_fw_hdr_section_v1 *section,
const void *content,
u32 *mssc_len)
{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
int ret;
- section_info->mssc =
- le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC);
-
- if (section_info->mssc == FORMATTED_MSSC) {
+ if ((section_info->mssc & FORMATTED_MSSC_MASK) == FORMATTED_MSSC) {
ret = __parse_formatted_mssc(rtwdev, info, section_info,
- section, content, mssc_len);
+ content, mssc_len);
if (ret)
return -EINVAL;
} else {
@@ -337,6 +363,14 @@ static int __parse_security_section(struct rtw89_dev *rtwdev,
if (info->dsp_checksum)
*mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN;
+ if (sec->secure_boot) {
+ if (sec->mss_idx >= section_info->mssc)
+ return -EFAULT;
+ section_info->key_addr = content + section_info->len +
+ sec->mss_idx * FWDL_SECURITY_SIGLEN;
+ section_info->key_len = FWDL_SECURITY_SIGLEN;
+ }
+
info->secure_section_exist = true;
}
@@ -361,6 +395,7 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM);
base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR);
+ info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_IDMEM_SHARE_MODE);
if (info->dynamic_hdr_en) {
info->hdr_len = le32_get_bits(fw_hdr->w5, FW_HDR_V1_W5_HDR_SIZE);
@@ -394,8 +429,11 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
section_info->addr = bin;
if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
+ section_info->mssc =
+ le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC);
+
ret = __parse_security_section(rtwdev, info, section_info,
- section, bin, &mssc_len);
+ bin, &mssc_len);
if (ret)
return ret;
} else {
@@ -665,11 +703,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER),
+ __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX),
__CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD),
+ __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX),
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG),
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE),
__CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER),
@@ -687,6 +727,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER),
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1),
__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0),
+ __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -1152,9 +1193,24 @@ static u32 __rtw89_fw_download_tweak_hdr_v0(struct rtw89_dev *rtwdev,
struct rtw89_fw_bin_info *info,
struct rtw89_fw_hdr *fw_hdr)
{
+ struct rtw89_fw_hdr_section_info *section_info;
+ struct rtw89_fw_hdr_section *section;
+ int i;
+
le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN,
FW_HDR_W7_PART_SIZE);
+ for (i = 0; i < info->section_num; i++) {
+ section_info = &info->section_info[i];
+
+ if (!section_info->len_override)
+ continue;
+
+ section = &fw_hdr->sections[i];
+ le32p_replace_bits(&section->w1, section_info->len_override,
+ FWSECTION_HDR_W1_SEC_SIZE);
+ }
+
return 0;
}
@@ -1283,10 +1339,20 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
if (info->ignore)
return 0;
+ if (info->len_override) {
+ if (info->len_override > info->len)
+ rtw89_warn(rtwdev, "override length %u larger than original %u\n",
+ info->len_override, info->len);
+ else
+ residue_len = info->len_override;
+ }
+
if (info->key_addr && info->key_len) {
- if (info->len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len)
- rtw89_warn(rtwdev, "ignore to copy key data because of len %d, %d, %d\n",
- info->len, FWDL_SECTION_PER_PKT_LEN, info->key_len);
+ if (residue_len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len)
+ rtw89_warn(rtwdev,
+ "ignore to copy key data because of len %d, %d, %d, %d\n",
+ info->len, FWDL_SECTION_PER_PKT_LEN,
+ info->key_len, residue_len);
else
copy_key = true;
}
@@ -1422,6 +1488,8 @@ static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev,
return ret;
}
+ rtw89_fwdl_secure_idmem_share_mode(rtwdev, info.idmem_share_mode);
+
if (rtwdev->chip->chip_id == RTL8922A &&
(fw_suit->type == RTW89_FW_NORMAL || fw_suit->type == RTW89_FW_WOWLAN))
rtw89_write32(rtwdev, R_BE_SECURE_BOOT_MALLOC_INFO, 0x20248000);
@@ -1741,8 +1809,8 @@ plain_log:
}
#define H2C_CAM_LEN 60
-int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta, const u8 *scan_mac_addr)
+int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr)
{
struct sk_buff *skb;
int ret;
@@ -1753,8 +1821,9 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
return -ENOMEM;
}
skb_put(skb, H2C_CAM_LEN);
- rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, rtwsta, scan_mac_addr, skb->data);
- rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif, rtwsta, skb->data);
+ rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif_link, rtwsta_link, scan_mac_addr,
+ skb->data);
+ rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif_link, rtwsta_link, skb->data);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
@@ -1776,8 +1845,8 @@ fail:
}
int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
struct rtw89_h2c_dctlinfo_ud_v1 *h2c;
u32 len = sizeof(*h2c);
@@ -1792,7 +1861,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_dctlinfo_ud_v1 *)skb->data;
- rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, h2c);
+ rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif_link, rtwsta_link, h2c);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
@@ -1815,8 +1884,8 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1);
int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
struct rtw89_h2c_dctlinfo_ud_v2 *h2c;
u32 len = sizeof(*h2c);
@@ -1831,7 +1900,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data;
- rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c);
+ rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif_link, rtwsta_link, h2c);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
@@ -1854,10 +1923,10 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2);
int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
struct rtw89_h2c_dctlinfo_ud_v2 *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
@@ -1908,21 +1977,24 @@ fail:
}
EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2);
-int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
bool valid, struct ieee80211_ampdu_params *params)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_h2c_ba_cam *h2c;
- u8 macid = rtwsta->mac_id;
+ u8 macid = rtwsta_link->mac_id;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
u8 entry_idx;
int ret;
ret = valid ?
- rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) :
- rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx);
+ rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid,
+ &entry_idx) :
+ rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid,
+ &entry_idx);
if (ret) {
/* it still works even if we don't have static BA CAM, because
* hardware can create dynamic BA CAM automatically.
@@ -1960,7 +2032,8 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
if (chip->bacam_ver == RTW89_BACAM_V0_EXT) {
h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) |
- le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND);
+ le32_encode_bits(rtwvif_link->mac_idx,
+ RTW89_H2C_BA_CAM_W1_BAND);
}
end:
@@ -2039,13 +2112,14 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev)
}
}
-int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
bool valid, struct ieee80211_ampdu_params *params)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_h2c_ba_cam_v1 *h2c;
- u8 macid = rtwsta->mac_id;
+ u8 macid = rtwsta_link->mac_id;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
u8 entry_idx;
@@ -2053,8 +2127,10 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
int ret;
ret = valid ?
- rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) :
- rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx);
+ rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid,
+ &entry_idx) :
+ rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid,
+ &entry_idx);
if (ret) {
/* it still works even if we don't have static BA CAM, because
* hardware can create dynamic BA CAM automatically.
@@ -2092,7 +2168,8 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */
h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) |
le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) |
- le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL);
+ le32_encode_bits(!!rtwvif_link->mac_idx,
+ RTW89_H2C_BA_CAM_V1_W1_BAND_SEL);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
@@ -2197,15 +2274,14 @@ fail:
}
static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
static const u8 gtkbody[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88,
0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03};
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_eapol_2_of_2 *eapol_pkt;
+ struct ieee80211_bss_conf *bss_conf;
struct ieee80211_hdr_3addr *hdr;
struct sk_buff *skb;
u8 key_des_ver;
@@ -2227,10 +2303,17 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev,
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_FCTL_TODS |
IEEE80211_FCTL_PROTECTED);
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+
ether_addr_copy(hdr->addr1, bss_conf->bssid);
- ether_addr_copy(hdr->addr2, vif->addr);
+ ether_addr_copy(hdr->addr2, bss_conf->addr);
ether_addr_copy(hdr->addr3, bss_conf->bssid);
+ rcu_read_unlock();
+
skb_put_zero(skb, sec_hdr_len);
eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt));
@@ -2241,11 +2324,10 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev,
}
static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
+ struct ieee80211_bss_conf *bss_conf;
struct ieee80211_hdr_3addr *hdr;
struct rtw89_sa_query *sa_query;
struct sk_buff *skb;
@@ -2258,10 +2340,17 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev,
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION |
IEEE80211_FCTL_PROTECTED);
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+
ether_addr_copy(hdr->addr1, bss_conf->bssid);
- ether_addr_copy(hdr->addr2, vif->addr);
+ ether_addr_copy(hdr->addr2, bss_conf->addr);
ether_addr_copy(hdr->addr3, bss_conf->bssid);
+ rcu_read_unlock();
+
skb_put_zero(skb, sec_hdr_len);
sa_query = skb_put_zero(skb, sizeof(*sa_query));
@@ -2272,8 +2361,9 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev,
}
static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct ieee80211_hdr_3addr *hdr;
@@ -2295,9 +2385,9 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev,
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS);
hdr->frame_control = fc;
- ether_addr_copy(hdr->addr1, rtwvif->bssid);
- ether_addr_copy(hdr->addr2, rtwvif->mac_addr);
- ether_addr_copy(hdr->addr3, rtwvif->bssid);
+ ether_addr_copy(hdr->addr1, rtwvif_link->bssid);
+ ether_addr_copy(hdr->addr2, rtwvif_link->mac_addr);
+ ether_addr_copy(hdr->addr3, rtwvif_link->bssid);
skb_put_zero(skb, sec_hdr_len);
@@ -2312,18 +2402,18 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev,
arp_hdr->ar_pln = 4;
arp_hdr->ar_op = htons(ARPOP_REPLY);
- ether_addr_copy(arp_skb->sender_hw, rtwvif->mac_addr);
+ ether_addr_copy(arp_skb->sender_hw, rtwvif_link->mac_addr);
arp_skb->sender_ip = rtwvif->ip_addr;
return skb;
}
static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
enum rtw89_fw_pkt_ofld_type type,
u8 *id)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_pktofld_info *info;
struct sk_buff *skb;
int ret;
@@ -2346,13 +2436,13 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev,
skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true);
break;
case RTW89_PKT_OFLD_TYPE_EAPOL_KEY:
- skb = rtw89_eapol_get(rtwdev, rtwvif);
+ skb = rtw89_eapol_get(rtwdev, rtwvif_link);
break;
case RTW89_PKT_OFLD_TYPE_SA_QUERY:
- skb = rtw89_sa_query_get(rtwdev, rtwvif);
+ skb = rtw89_sa_query_get(rtwdev, rtwvif_link);
break;
case RTW89_PKT_OFLD_TYPE_ARP_RSP:
- skb = rtw89_arp_response_get(rtwdev, rtwvif);
+ skb = rtw89_arp_response_get(rtwdev, rtwvif_link);
break;
default:
goto err;
@@ -2367,7 +2457,7 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev,
if (ret)
goto err;
- list_add_tail(&info->list, &rtwvif->general_pkt_list);
+ list_add_tail(&info->list, &rtwvif_link->general_pkt_list);
*id = info->id;
return 0;
@@ -2377,9 +2467,10 @@ err:
}
void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool notify_fw)
+ struct rtw89_vif_link *rtwvif_link,
+ bool notify_fw)
{
- struct list_head *pkt_list = &rtwvif->general_pkt_list;
+ struct list_head *pkt_list = &rtwvif_link->general_pkt_list;
struct rtw89_pktofld_info *info, *tmp;
list_for_each_entry_safe(info, tmp, pkt_list, list) {
@@ -2394,16 +2485,20 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev,
void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, notify_fw);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link,
+ notify_fw);
}
#define H2C_GENERAL_PKT_LEN 6
#define H2C_GENERAL_PKT_ID_UND 0xff
int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u8 macid)
+ struct rtw89_vif_link *rtwvif_link, u8 macid)
{
u8 pkt_id_ps_poll = H2C_GENERAL_PKT_ID_UND;
u8 pkt_id_null = H2C_GENERAL_PKT_ID_UND;
@@ -2411,11 +2506,11 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev,
struct sk_buff *skb;
int ret;
- rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_PS_POLL, &pkt_id_ps_poll);
- rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id_null);
- rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_QOS_NULL, &pkt_id_qos_null);
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN);
@@ -2478,7 +2573,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev,
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MAC_PS,
- H2C_FUNC_MAC_LPS_PARM, 0, 1,
+ H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode,
H2C_LPS_PARM_LEN);
ret = rtw89_h2c_tx(rtwdev, skb, false);
@@ -2494,10 +2589,10 @@ fail:
return ret;
}
-int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_h2c_lps_ch_info *h2c;
u32 len = sizeof(*h2c);
@@ -2546,13 +2641,14 @@ fail:
}
#define H2C_P2P_ACT_LEN 20
-int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf,
struct ieee80211_p2p_noa_desc *desc,
u8 act, u8 noa_id)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- bool p2p_type_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
- u8 ctwindow_oppps = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
+ bool p2p_type_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
+ u8 ctwindow_oppps = bss_conf->p2p_noa_attr.oppps_ctwindow;
struct sk_buff *skb;
u8 *cmd;
int ret;
@@ -2565,7 +2661,7 @@ int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
skb_put(skb, H2C_P2P_ACT_LEN);
cmd = skb->data;
- RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif->mac_id);
+ RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif_link->mac_id);
RTW89_SET_FWCMD_P2P_P2PID(cmd, 0);
RTW89_SET_FWCMD_P2P_NOAID(cmd, noa_id);
RTW89_SET_FWCMD_P2P_ACT(cmd, act);
@@ -2622,11 +2718,11 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev,
#define H2C_CMC_TBL_LEN 68
int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ u8 macid = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
struct sk_buff *skb;
int ret;
@@ -2648,7 +2744,7 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
}
SET_CMC_TBL_DOPPLER_CTRL(skb->data, 0);
SET_CMC_TBL_TXPWR_TOLERENCE(skb->data, 0);
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
SET_CMC_TBL_DATA_DCM(skb->data, 0);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
@@ -2671,10 +2767,10 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl);
int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
@@ -2755,24 +2851,25 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7);
static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, u8 *pads)
+ struct ieee80211_link_sta *link_sta,
+ u8 *pads)
{
bool ppe_th;
u8 ppe16, ppe8;
- u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
- u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0];
+ u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
+ u8 ppe_thres_hdr = link_sta->he_cap.ppe_thres[0];
u8 ru_bitmap;
u8 n, idx, sh;
u16 ppe;
int i;
ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
- sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]);
+ link_sta->he_cap.he_cap_elem.phy_cap_info[6]);
if (!ppe_th) {
u8 pad;
pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK,
- sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]);
+ link_sta->he_cap.he_cap_elem.phy_cap_info[9]);
for (i = 0; i < RTW89_PPE_BW_NUM; i++)
pads[i] = pad;
@@ -2794,7 +2891,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
sh = n & 7;
n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2;
- ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx]));
+ ppe = le16_to_cpu(*((__le16 *)&link_sta->he_cap.ppe_thres[idx]));
ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE;
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
@@ -2809,23 +2906,35 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
}
int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
+ struct ieee80211_link_sta *link_sta;
struct sk_buff *skb;
u8 pads[RTW89_PPE_BW_NUM];
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
u16 lowest_rate;
int ret;
memset(pads, 0, sizeof(pads));
- if (sta && sta->deflink.he_cap.has_he)
- __get_sta_he_pkt_padding(rtwdev, sta, pads);
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
+ return -ENOMEM;
+ }
+
+ rcu_read_lock();
+
+ if (rtwsta_link)
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ if (rtwsta_link && link_sta->he_cap.has_he)
+ __get_sta_he_pkt_padding(rtwdev, link_sta, pads);
if (vif->p2p)
lowest_rate = RTW89_HW_RATE_OFDM6;
@@ -2834,11 +2943,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
else
lowest_rate = RTW89_HW_RATE_OFDM6;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
- if (!skb) {
- rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
- return -ENOMEM;
- }
skb_put(skb, H2C_CMC_TBL_LEN);
SET_CTRL_INFO_MACID(skb->data, mac_id);
SET_CTRL_INFO_OPERATION(skb->data, 1);
@@ -2851,7 +2955,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
SET_CMC_TBL_ULDL(skb->data, 1);
else
SET_CMC_TBL_ULDL(skb->data, 0);
- SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif->port);
+ SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif_link->port);
if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD_V1) {
SET_CMC_TBL_NOMINAL_PKT_PADDING_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_20]);
SET_CMC_TBL_NOMINAL_PKT_PADDING40_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_40]);
@@ -2863,12 +2967,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]);
SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]);
}
- if (sta)
+ if (rtwsta_link)
SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data,
- sta->deflink.he_cap.has_he);
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ link_sta->he_cap.has_he);
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
SET_CMC_TBL_DATA_DCM(skb->data, 0);
+ rcu_read_unlock();
+
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
chip->h2c_cctl_func_id, 0, 1,
@@ -2889,9 +2995,10 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl);
static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, u8 *pads)
+ struct ieee80211_link_sta *link_sta,
+ u8 *pads)
{
- u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
+ u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
u16 ppe_thres_hdr;
u8 ppe16, ppe8;
u8 n, idx, sh;
@@ -2900,12 +3007,12 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
u16 ppe;
int i;
- ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
+ ppe_th = !!u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5],
IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT);
if (!ppe_th) {
u8 pad;
- pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
+ pad = u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5],
IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);
for (i = 0; i < RTW89_PPE_BW_NUM; i++)
@@ -2914,7 +3021,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
return;
}
- ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres);
+ ppe_thres_hdr = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres);
ru_bitmap = u16_get_bits(ppe_thres_hdr,
IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
n = hweight8(ru_bitmap);
@@ -2931,7 +3038,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
sh = n & 7;
n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2;
- ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx);
+ ppe = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres + idx);
ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE;
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
@@ -2946,14 +3053,15 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
}
int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
+ struct ieee80211_bss_conf *bss_conf;
+ struct ieee80211_link_sta *link_sta;
u8 pads[RTW89_PPE_BW_NUM];
u32 len = sizeof(*h2c);
struct sk_buff *skb;
@@ -2961,11 +3069,24 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
int ret;
memset(pads, 0, sizeof(pads));
- if (sta) {
- if (sta->deflink.eht_cap.has_eht)
- __get_sta_eht_pkt_padding(rtwdev, sta, pads);
- else if (sta->deflink.he_cap.has_he)
- __get_sta_he_pkt_padding(rtwdev, sta, pads);
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n");
+ return -ENOMEM;
+ }
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+
+ if (rtwsta_link) {
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ if (link_sta->eht_cap.has_eht)
+ __get_sta_eht_pkt_padding(rtwdev, link_sta, pads);
+ else if (link_sta->he_cap.has_he)
+ __get_sta_he_pkt_padding(rtwdev, link_sta, pads);
}
if (vif->p2p)
@@ -2975,11 +3096,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
else
lowest_rate = RTW89_HW_RATE_OFDM6;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
- if (!skb) {
- rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n");
- return -ENOMEM;
- }
skb_put(skb, len);
h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data;
@@ -3000,16 +3116,16 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL);
h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL);
- h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID);
+ h2c->w4 = le32_encode_bits(rtwvif_link->port, CCTLINFO_G7_W4_MULTI_PORT_ID);
h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID);
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) {
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) {
h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM);
h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM);
}
- if (vif->bss_conf.eht_support) {
- u16 punct = vif->bss_conf.chanreq.oper.punctured;
+ if (bss_conf->eht_support) {
+ u16 punct = bss_conf->chanreq.oper.punctured;
h2c->w4 |= le32_encode_bits(~punct,
CCTLINFO_G7_W4_ACT_SUBCH_CBW);
@@ -3036,12 +3152,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
CCTLINFO_G7_W6_ULDL);
h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL);
- if (sta) {
- h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he,
+ if (rtwsta_link) {
+ h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he,
CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
}
+ rcu_read_unlock();
+
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1,
@@ -3062,10 +3180,10 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7);
int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = rtwsta_link->rtwsta;
struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
@@ -3102,7 +3220,7 @@ int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev,
else if (agg_num > 0x200 && agg_num <= 0x400)
ba_bmap = 5;
- h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) |
+ h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, CCTLINFO_G7_C0_MACID) |
le32_encode_bits(1, CCTLINFO_G7_C0_OP);
h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP);
@@ -3128,7 +3246,7 @@ fail:
EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7);
int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta)
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
@@ -3140,15 +3258,15 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
skb_put(skb, H2C_CMC_TBL_LEN);
- SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id);
+ SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id);
SET_CTRL_INFO_OPERATION(skb->data, 1);
- if (rtwsta->cctl_tx_time) {
+ if (rtwsta_link->cctl_tx_time) {
SET_CMC_TBL_AMPDU_TIME_SEL(skb->data, 1);
- SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta->ampdu_max_time);
+ SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta_link->ampdu_max_time);
}
- if (rtwsta->cctl_tx_retry_limit) {
+ if (rtwsta_link->cctl_tx_retry_limit) {
SET_CMC_TBL_DATA_TXCNT_LMT_SEL(skb->data, 1);
- SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta->data_tx_cnt_lmt);
+ SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta_link->data_tx_cnt_lmt);
}
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
@@ -3170,7 +3288,7 @@ fail:
}
int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta)
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
@@ -3185,7 +3303,7 @@ int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
skb_put(skb, H2C_CMC_TBL_LEN);
- SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id);
+ SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id);
SET_CTRL_INFO_OPERATION(skb->data, 1);
__rtw89_fw_h2c_set_tx_path(rtwdev, skb);
@@ -3209,11 +3327,11 @@ fail:
}
int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ rtwvif_link->chanctx_idx);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_h2c_bcn_upd *h2c;
struct sk_buff *skb_beacon;
struct ieee80211_hdr *hdr;
@@ -3240,7 +3358,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
- noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+ noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data);
if (noa_len &&
(noa_len <= skb_tailroom(skb_beacon) ||
pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
@@ -3260,11 +3378,11 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_bcn_upd *)skb->data;
- h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) |
+ h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_W0_PORT) |
le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) |
- le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) |
+ le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) |
le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST);
- h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) |
+ h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) |
le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) |
le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) |
le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE);
@@ -3289,10 +3407,10 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon);
int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_h2c_bcn_upd_be *h2c;
struct sk_buff *skb_beacon;
struct ieee80211_hdr *hdr;
@@ -3319,7 +3437,7 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
- noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+ noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data);
if (noa_len &&
(noa_len <= skb_tailroom(skb_beacon) ||
pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
@@ -3339,11 +3457,11 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data;
- h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) |
+ h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) |
le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) |
- le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) |
+ le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) |
le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST);
- h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) |
+ h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) |
le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) |
le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) |
le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE);
@@ -3373,22 +3491,22 @@ EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be);
#define H2C_ROLE_MAINTAIN_LEN 4
int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
enum rtw89_upd_mode upd_mode)
{
struct sk_buff *skb;
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
u8 self_role;
int ret;
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) {
- if (rtwsta)
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) {
+ if (rtwsta_link)
self_role = RTW89_SELF_ROLE_AP_CLIENT;
else
- self_role = rtwvif->self_role;
+ self_role = rtwvif_link->self_role;
} else {
- self_role = rtwvif->self_role;
+ self_role = rtwvif_link->self_role;
}
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ROLE_MAINTAIN_LEN);
@@ -3400,7 +3518,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
SET_FWROLE_MAINTAIN_MACID(skb->data, mac_id);
SET_FWROLE_MAINTAIN_SELF_ROLE(skb->data, self_role);
SET_FWROLE_MAINTAIN_UPD_MODE(skb->data, upd_mode);
- SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif->wifi_role);
+ SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif_link->wifi_role);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT,
@@ -3421,39 +3539,53 @@ fail:
}
static enum rtw89_fw_sta_type
-rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_bss_conf *bss_conf;
+ struct ieee80211_link_sta *link_sta;
+ enum rtw89_fw_sta_type type;
- if (!sta)
+ rcu_read_lock();
+
+ if (!rtwsta_link)
goto by_vif;
- if (sta->deflink.eht_cap.has_eht)
- return RTW89_FW_BE_STA;
- else if (sta->deflink.he_cap.has_he)
- return RTW89_FW_AX_STA;
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ if (link_sta->eht_cap.has_eht)
+ type = RTW89_FW_BE_STA;
+ else if (link_sta->he_cap.has_he)
+ type = RTW89_FW_AX_STA;
else
- return RTW89_FW_N_AC_STA;
+ type = RTW89_FW_N_AC_STA;
+
+ goto out;
by_vif:
- if (vif->bss_conf.eht_support)
- return RTW89_FW_BE_STA;
- else if (vif->bss_conf.he_support)
- return RTW89_FW_AX_STA;
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+
+ if (bss_conf->eht_support)
+ type = RTW89_FW_BE_STA;
+ else if (bss_conf->he_support)
+ type = RTW89_FW_AX_STA;
else
- return RTW89_FW_N_AC_STA;
+ type = RTW89_FW_N_AC_STA;
+
+out:
+ rcu_read_unlock();
+
+ return type;
}
-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_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link, bool dis_conn)
{
struct sk_buff *skb;
- u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
- u8 self_role = rtwvif->self_role;
+ u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
+ u8 self_role = rtwvif_link->self_role;
enum rtw89_fw_sta_type sta_type;
- u8 net_type = rtwvif->net_type;
+ u8 net_type = rtwvif_link->net_type;
struct rtw89_h2c_join_v1 *h2c_v1;
struct rtw89_h2c_join *h2c;
u32 len = sizeof(*h2c);
@@ -3465,7 +3597,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
format_v1 = true;
}
- if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) {
+ if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta_link) {
self_role = RTW89_SELF_ROLE_AP_CLIENT;
net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type;
}
@@ -3480,16 +3612,17 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) |
le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) |
- le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) |
- le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) |
- le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) |
+ le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_JOININFO_W0_BAND) |
+ le32_encode_bits(rtwvif_link->wmm, RTW89_H2C_JOININFO_W0_WMM) |
+ le32_encode_bits(rtwvif_link->trigger, RTW89_H2C_JOININFO_W0_TGR) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) |
- le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) |
+ le32_encode_bits(rtwvif_link->port, RTW89_H2C_JOININFO_W0_PORT_ID) |
le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) |
- le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) |
+ le32_encode_bits(rtwvif_link->wifi_role,
+ RTW89_H2C_JOININFO_W0_WIFI_ROLE) |
le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE);
if (!format_v1)
@@ -3497,7 +3630,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data;
- sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta);
+ sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif_link, rtwsta_link);
h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE);
h2c_v1->w2 = 0;
@@ -3618,7 +3751,7 @@ fail:
}
#define H2C_EDCA_LEN 12
-int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u8 ac, u32 val)
{
struct sk_buff *skb;
@@ -3631,7 +3764,7 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
}
skb_put(skb, H2C_EDCA_LEN);
RTW89_SET_EDCA_SEL(skb->data, 0);
- RTW89_SET_EDCA_BAND(skb->data, rtwvif->mac_idx);
+ RTW89_SET_EDCA_BAND(skb->data, rtwvif_link->mac_idx);
RTW89_SET_EDCA_WMM(skb->data, 0);
RTW89_SET_EDCA_AC(skb->data, ac);
RTW89_SET_EDCA_PARAM(skb->data, val);
@@ -3655,7 +3788,8 @@ fail:
}
#define H2C_TSF32_TOGL_LEN 4
-int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool en)
{
struct sk_buff *skb;
@@ -3671,9 +3805,9 @@ int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
skb_put(skb, H2C_TSF32_TOGL_LEN);
cmd = skb->data;
- RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif->mac_idx);
+ RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif_link->mac_idx);
RTW89_SET_FWCMD_TSF32_TOGL_EN(cmd, en);
- RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif->port);
+ RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif_link->port);
RTW89_SET_FWCMD_TSF32_TOGL_EARLY(cmd, early_us);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
@@ -3726,12 +3860,57 @@ fail:
return ret;
}
+int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv)
+{
+ struct rtw89_h2c_tx_duty *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u16 pause, active;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c tx duty\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_tx_duty *)skb->data;
+
+ static_assert(RTW89_THERMAL_PROT_LV_MAX * RTW89_THERMAL_PROT_STEP < 100);
+
+ if (lv == 0 || lv > RTW89_THERMAL_PROT_LV_MAX) {
+ h2c->w1 = le32_encode_bits(1, RTW89_H2C_TX_DUTY_W1_STOP);
+ } else {
+ active = 100 - lv * RTW89_THERMAL_PROT_STEP;
+ pause = 100 - active;
+
+ h2c->w0 = le32_encode_bits(pause, RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK) |
+ le32_encode_bits(active, RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK);
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
+ H2C_FUNC_TX_DUTY, 0, 0, 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_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
+ struct rtw89_vif_link *rtwvif_link,
bool connect)
{
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
- struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL;
+ struct ieee80211_bss_conf *bss_conf;
s32 thold = RTW89_DEFAULT_CQM_THOLD;
u32 hyst = RTW89_DEFAULT_CQM_HYST;
struct rtw89_h2c_bcnfltr *h2c;
@@ -3742,9 +3921,20 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw))
return -EINVAL;
- if (!rtwvif || !bss_conf || rtwvif->net_type != RTW89_NET_TYPE_INFRA)
+ if (!rtwvif_link || rtwvif_link->net_type != RTW89_NET_TYPE_INFRA)
return -EINVAL;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false);
+
+ if (bss_conf->cqm_rssi_hyst)
+ hyst = bss_conf->cqm_rssi_hyst;
+ if (bss_conf->cqm_rssi_thold)
+ thold = bss_conf->cqm_rssi_thold;
+
+ rcu_read_unlock();
+
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c bcn filter\n");
@@ -3754,11 +3944,6 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_bcnfltr *)skb->data;
- if (bss_conf->cqm_rssi_hyst)
- hyst = bss_conf->cqm_rssi_hyst;
- if (bss_conf->cqm_rssi_thold)
- thold = bss_conf->cqm_rssi_thold;
-
h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) |
@@ -3768,7 +3953,7 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) |
le32_encode_bits(thold + MAX_RSSI,
RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) |
- le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID);
+ le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
@@ -3833,15 +4018,16 @@ fail:
return ret;
}
-int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_traffic_stats *stats = &rtwvif->stats;
struct rtw89_h2c_ofld *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
int ret;
- if (rtwvif->net_type != RTW89_NET_TYPE_INFRA)
+ if (rtwvif_link->net_type != RTW89_NET_TYPE_INFRA)
return -EINVAL;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
@@ -3853,7 +4039,7 @@ int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
skb_put(skb, len);
h2c = (struct rtw89_h2c_ofld *)skb->data;
- h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) |
+ h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) |
le32_encode_bits(stats->tx_throughput, RTW89_H2C_OFLD_W0_TX_TP) |
le32_encode_bits(stats->rx_throughput, RTW89_H2C_OFLD_W0_RX_TP);
@@ -4688,6 +4874,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
return 0;
}
+static
int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list)
{
@@ -4759,8 +4946,10 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
return 0;
}
+static
int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
- struct list_head *chan_list)
+ struct list_head *chan_list,
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct rtw89_h2c_chinfo_elem_be *elem;
@@ -4785,7 +4974,8 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
h2c->ch_num = ch_num;
h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */
- h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK);
+ h2c->arg = u8_encode_bits(rtwvif_link->mac_idx,
+ RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK);
list_for_each_entry(ch_info, chan_list, list) {
elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem));
@@ -4858,7 +5048,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
#define RTW89_SCAN_DELAY_TSF_UNIT 104800
int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool wowlan)
{
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
@@ -4880,19 +5070,19 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev,
h2c = (struct rtw89_h2c_scanofld *)skb->data;
if (option->delay) {
- ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf);
+ ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "NLO failed to get port tsf: %d\n", ret);
scan_mode = RTW89_SCAN_IMMEDIATE;
} else {
scan_mode = RTW89_SCAN_DELAY;
- tsf += option->delay * RTW89_SCAN_DELAY_TSF_UNIT;
+ tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT;
}
}
- h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) |
- le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) |
- le32_encode_bits(RTW89_PHY_0, RTW89_H2C_SCANOFLD_W0_BAND) |
+ h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) |
+ le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) |
+ le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_SCANOFLD_W0_BAND) |
le32_encode_bits(option->enable, RTW89_H2C_SCANOFLD_W0_OPERATION);
h2c->w1 = le32_encode_bits(true, RTW89_H2C_SCANOFLD_W1_NOTIFY_END) |
@@ -4963,9 +5153,10 @@ static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev,
int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool wowlan)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct cfg80211_scan_request *req = rtwvif->scan_req;
@@ -5016,8 +5207,8 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_BE_W0_REPEAT) |
le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END) |
le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH) |
- le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) |
- le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) |
+ le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) |
+ le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) |
le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_W0_BAND);
h2c->w1 = le32_encode_bits(option->num_macc_role, RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE) |
@@ -5082,11 +5273,11 @@ flex_member:
for (i = 0; i < option->num_opch; i++) {
opch = ptr;
- opch->w0 = le32_encode_bits(rtwvif->mac_id,
+ opch->w0 = le32_encode_bits(rtwvif_link->mac_id,
RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) |
le32_encode_bits(option->band,
RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) |
- le32_encode_bits(rtwvif->port,
+ le32_encode_bits(rtwvif_link->port,
RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) |
le32_encode_bits(RTW89_SCAN_OPMODE_INTV,
RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) |
@@ -5180,7 +5371,7 @@ fail:
int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
{
- struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
struct rtw89_fw_h2c_rf_get_mccch *mccch;
struct sk_buff *skb;
int ret;
@@ -5227,7 +5418,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev,
struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0;
struct rtw89_fw_h2c_rfk_pre_info *h2c;
- u8 tbl_sel = rfk_mcc->table_idx;
+ u8 tbl_sel[NUM_OF_RTW89_FW_RFK_PATH];
u32 len = sizeof(*h2c);
struct sk_buff *skb;
u8 ver = U8_MAX;
@@ -5251,19 +5442,24 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev,
h2c->common.mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode);
BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR);
+ BUILD_BUG_ON(ARRAY_SIZE(rfk_mcc->data) < NUM_OF_RTW89_FW_RFK_PATH);
for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) {
for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) {
h2c->common.dbcc.ch[path][tbl] =
- cpu_to_le32(rfk_mcc->ch[tbl]);
+ cpu_to_le32(rfk_mcc->data[path].ch[tbl]);
h2c->common.dbcc.band[path][tbl] =
- cpu_to_le32(rfk_mcc->band[tbl]);
+ cpu_to_le32(rfk_mcc->data[path].band[tbl]);
}
}
for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) {
- h2c->common.tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]);
- h2c->common.tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]);
+ tbl_sel[path] = rfk_mcc->data[path].table_idx;
+
+ h2c->common.tbl.cur_ch[path] =
+ cpu_to_le32(rfk_mcc->data[path].ch[tbl_sel[path]]);
+ h2c->common.tbl.cur_band[path] =
+ cpu_to_le32(rfk_mcc->data[path].band[tbl_sel[path]]);
}
h2c->common.phy_idx = cpu_to_le32(phy_idx);
@@ -5271,9 +5467,9 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev,
if (ver == 0) { /* RFK_PRE_NOTIFY_V0 */
h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_v0 *)skb->data;
- h2c_v0->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]);
- h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]);
- h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]);
+ h2c_v0->cur_band = cpu_to_le32(rfk_mcc->data[0].band[tbl_sel[0]]);
+ h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->data[0].bw[tbl_sel[0]]);
+ h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->data[0].ch[tbl_sel[0]]);
val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1);
h2c_v0->ktbl_sel0 = cpu_to_le32(val32);
@@ -5518,30 +5714,44 @@ fail:
}
int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
- const struct rtw89_chan *chan)
+ const struct rtw89_chan *chan, bool is_chl_k)
{
+ struct rtw89_h2c_rf_rxdck_v0 *v0;
struct rtw89_h2c_rf_rxdck *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
+ int ver = -1;
int ret;
+ if (RTW89_CHK_FW_FEATURE(RFK_RXDCK_V0, &rtwdev->fw)) {
+ len = sizeof(*v0);
+ ver = 0;
+ }
+
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c RF RXDCK\n");
return -ENOMEM;
}
skb_put(skb, len);
- h2c = (struct rtw89_h2c_rf_rxdck *)skb->data;
+ v0 = (struct rtw89_h2c_rf_rxdck_v0 *)skb->data;
+
+ v0->len = len;
+ v0->phy = phy_idx;
+ v0->is_afe = false;
+ v0->kpath = RF_AB;
+ v0->cur_band = chan->band_type;
+ v0->cur_bw = chan->band_width;
+ v0->cur_ch = chan->channel;
+ v0->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
+
+ if (ver == 0)
+ goto hdr;
- h2c->len = len;
- h2c->phy = phy_idx;
- h2c->is_afe = false;
- h2c->kpath = RF_AB;
- h2c->cur_band = chan->band_type;
- h2c->cur_bw = chan->band_width;
- h2c->cur_ch = chan->channel;
- h2c->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
+ h2c = (struct rtw89_h2c_rf_rxdck *)skb->data;
+ h2c->is_chl_k = is_chl_k;
+hdr:
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
H2C_FUNC_RFK_RXDCK_OFFLOAD, 0, 0, len);
@@ -5871,12 +6081,10 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
}
static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct cfg80211_scan_request *req,
struct rtw89_pktofld_info *info,
enum nl80211_band band, u8 ssid_idx)
{
- struct cfg80211_scan_request *req = rtwvif->scan_req;
-
if (band != NL80211_BAND_6GHZ)
return false;
@@ -5892,11 +6100,13 @@ static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
}
static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct sk_buff *skb, u8 ssid_idx)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_pktofld_info *info;
struct sk_buff *new;
int ret = 0;
@@ -5921,8 +6131,7 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
goto out;
}
- rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band,
- ssid_idx);
+ rtw89_is_6ghz_wildcard_probe_req(rtwdev, req, info, band, ssid_idx);
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new);
if (ret) {
@@ -5939,22 +6148,23 @@ out:
}
static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct sk_buff *skb;
u8 num = req->n_ssids, i;
int ret;
for (i = 0; i < num; i++) {
- skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
+ skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr,
req->ssids[i].ssid,
req->ssids[i].ssid_len,
req->ie_len);
if (!skb)
return -ENOMEM;
- ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i);
+ ret = rtw89_append_probe_req_ie(rtwdev, rtwvif_link, skb, i);
kfree_skb(skb);
if (ret)
@@ -5965,13 +6175,12 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
}
static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
+ struct ieee80211_scan_ies *ies,
struct cfg80211_scan_request *req,
struct rtw89_mac_chinfo *ch_info)
{
- struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
- struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
struct cfg80211_scan_6ghz_params *params;
struct rtw89_pktofld_info *info, *tmp;
struct ieee80211_hdr *hdr;
@@ -6000,8 +6209,11 @@ static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
if (found)
continue;
- skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
+ skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr,
NULL, 0, req->ie_len);
+ if (!skb)
+ return -ENOMEM;
+
skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]);
skb_put_data(skb, ies->common_ies, ies->common_ie_len);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -6090,8 +6302,9 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
struct rtw89_mac_chinfo *ch_info)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
- struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
+ struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_chan *op = &rtwdev->scan_info.op_chan;
struct rtw89_pktofld_info *info;
@@ -6117,7 +6330,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
}
}
- ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info);
+ ret = rtw89_update_6ghz_rnr_chan(rtwdev, ies, req, ch_info);
if (ret)
rtw89_warn(rtwdev, "RNR fails: %d\n", ret);
@@ -6155,8 +6368,10 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
ch_info->period = max_t(u8, ch_info->period,
RTW89_DFS_CHAN_TIME);
ch_info->dwell_time = RTW89_DWELL_TIME;
+ ch_info->pause_data = true;
break;
case RTW89_CHAN_ACTIVE:
+ ch_info->pause_data = true;
break;
default:
rtw89_err(rtwdev, "Channel type out of bound\n");
@@ -6207,8 +6422,8 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
struct rtw89_mac_chinfo_be *ch_info)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
- struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_pktofld_info *info;
u8 band, probe_count = 0, i;
@@ -6255,8 +6470,10 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
ch_info->period =
max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME);
ch_info->dwell_time = RTW89_DWELL_TIME;
+ ch_info->pause_data = true;
break;
case RTW89_CHAN_ACTIVE:
+ ch_info->pause_data = true;
break;
default:
rtw89_warn(rtwdev, "Channel type out of bound\n");
@@ -6265,7 +6482,7 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
}
int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config;
@@ -6315,8 +6532,9 @@ out:
}
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected)
+ struct rtw89_vif_link *rtwvif_link, bool connected)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo *ch_info, *tmp;
struct ieee80211_channel *channel;
@@ -6392,7 +6610,7 @@ out:
}
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config;
@@ -6432,7 +6650,8 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
list_add_tail(&ch_info->list, &chan_list);
}
- ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list);
+ ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list,
+ rtwvif_link);
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -6444,8 +6663,9 @@ out:
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected)
+ struct rtw89_vif_link *rtwvif_link, bool connected)
{
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
struct ieee80211_channel *channel;
@@ -6491,7 +6711,8 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
}
rtwdev->scan_info.last_chan_idx = idx;
- ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list);
+ ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list,
+ rtwvif_link);
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -6503,79 +6724,88 @@ out:
}
static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected)
+ struct rtw89_vif_link *rtwvif_link, bool connected)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
- ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif);
+ ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link);
if (ret) {
rtw89_err(rtwdev, "Update probe request failed\n");
goto out;
}
- ret = mac->add_chan_list(rtwdev, rtwvif, connected);
+ ret = mac->add_chan_list(rtwdev, rtwvif_link, connected);
out:
return ret;
}
-void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct cfg80211_scan_request *req = &scan_req->req;
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif_link->chanctx_idx);
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
u32 rx_fltr = rtwdev->hal.rx_fltr;
u8 mac_addr[ETH_ALEN];
+ u32 reg;
+
+ /* clone op and keep it during scan */
+ rtwdev->scan_info.op_chan = *chan;
- rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan);
- rtwdev->scan_info.scanning_vif = vif;
+ rtwdev->scan_info.scanning_vif = rtwvif_link;
rtwdev->scan_info.last_chan_idx = 0;
rtwdev->scan_info.abort = false;
rtwvif->scan_ies = &scan_req->ies;
rtwvif->scan_req = req;
ieee80211_stop_queues(rtwdev->hw);
- rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, false);
+ rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false);
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
get_random_mask_addr(mac_addr, req->mac_addr,
req->mac_addr_mask);
else
- ether_addr_copy(mac_addr, vif->addr);
- rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, true);
+ ether_addr_copy(mac_addr, rtwvif_link->mac_addr);
+ rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, true);
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,
- rx_fltr);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr);
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN);
}
-void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool aborted)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
struct cfg80211_scan_info info = {
.aborted = aborted,
};
+ struct rtw89_vif *rtwvif;
+ u32 reg;
- if (!vif)
+ if (!rtwvif_link)
return;
- 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);
+ rtw89_chanctx_proceed(rtwdev);
+
+ rtwvif = rtwvif_link->rtwvif;
- rtw89_core_scan_complete(rtwdev, vif, true);
+ reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr);
+
+ rtw89_core_scan_complete(rtwdev, rtwvif_link, true);
ieee80211_scan_completed(rtwdev->hw, &info);
ieee80211_wake_queues(rtwdev->hw);
- rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, true);
+ rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true);
rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true);
rtw89_release_pkt_list(rtwdev);
@@ -6584,18 +6814,17 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
scan_info->last_chan_idx = 0;
scan_info->scanning_vif = NULL;
scan_info->abort = false;
-
- rtw89_chanctx_proceed(rtwdev);
}
-void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
int ret;
scan_info->abort = true;
- ret = rtw89_hw_scan_offload(rtwdev, vif, false);
+ ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, false);
if (ret)
rtw89_warn(rtwdev, "rtw89_hw_scan_offload failed ret %d\n", ret);
@@ -6604,40 +6833,43 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
* RTW89_SCAN_END_SCAN_NOTIFY, so that ieee80211_stop() can flush scan
* work properly.
*/
- rtw89_hw_scan_complete(rtwdev, vif, true);
+ rtw89_hw_scan_complete(rtwdev, rtwvif_link, true);
}
static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- /* This variable implies connected or during attempt to connect */
- if (!is_zero_ether_addr(rtwvif->bssid))
- return true;
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ /* This variable implies connected or during attempt to connect */
+ if (!is_zero_ether_addr(rtwvif_link->bssid))
+ return true;
+ }
}
return false;
}
-int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool enable)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_scan_option opt = {0};
- struct rtw89_vif *rtwvif;
bool connected;
int ret = 0;
- rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
- if (!rtwvif)
+ if (!rtwvif_link)
return -EINVAL;
connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
opt.enable = enable;
opt.target_ch_mode = connected;
if (enable) {
- ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif, connected);
+ ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, connected);
if (ret)
goto out;
}
@@ -6645,14 +6877,14 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP;
opt.scan_mode = RTW89_SCAN_MODE_SA;
- opt.band = RTW89_PHY_0;
+ opt.band = rtwvif_link->mac_idx;
opt.num_macc_role = 0;
opt.mlo_mode = rtwdev->mlo_dbcc_mode;
opt.num_opch = connected ? 1 : 0;
opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID;
}
- ret = mac->scan_offload(rtwdev, &opt, rtwvif, false);
+ ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false);
out:
return ret;
}
@@ -6758,7 +6990,7 @@ fail:
}
#define H2C_KEEP_ALIVE_LEN 4
-int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct sk_buff *skb;
@@ -6766,7 +6998,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
int ret;
if (enable) {
- ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_NULL_DATA,
&pkt_id);
if (ret)
@@ -6784,7 +7016,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable);
RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id);
RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5);
- RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id);
+ RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif_link->mac_id);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
@@ -6806,7 +7038,7 @@ fail:
return ret;
}
-int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_h2c_arp_offload *h2c;
@@ -6816,7 +7048,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
int ret;
if (enable) {
- ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_ARP_RSP,
&pkt_id);
if (ret)
@@ -6834,7 +7066,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
h2c->w0 = le32_encode_bits(enable, RTW89_H2C_ARP_OFFLOAD_W0_ENABLE) |
le32_encode_bits(0, RTW89_H2C_ARP_OFFLOAD_W0_ACTION) |
- le32_encode_bits(rtwvif->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) |
+ le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) |
le32_encode_bits(pkt_id, RTW89_H2C_ARP_OFFLOAD_W0_PKT_ID);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
@@ -6859,11 +7091,11 @@ fail:
#define H2C_DISCONNECT_DETECT_LEN 8
int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable)
+ struct rtw89_vif_link *rtwvif_link, bool enable)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct sk_buff *skb;
- u8 macid = rtwvif->mac_id;
+ u8 macid = rtwvif_link->mac_id;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN);
@@ -6902,7 +7134,7 @@ fail:
return ret;
}
-int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
@@ -6923,7 +7155,7 @@ int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
h2c->w0 = le32_encode_bits(enable, RTW89_H2C_NLO_W0_ENABLE) |
le32_encode_bits(enable, RTW89_H2C_NLO_W0_IGNORE_CIPHER) |
- le32_encode_bits(rtwvif->mac_id, RTW89_H2C_NLO_W0_MACID);
+ le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_NLO_W0_MACID);
if (enable) {
h2c->nlo_cnt = nd_config->n_match_sets;
@@ -6953,12 +7185,12 @@ fail:
return ret;
}
-int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_h2c_wow_global *h2c;
- u8 macid = rtwvif->mac_id;
+ u8 macid = rtwvif_link->mac_id;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
int ret;
@@ -7002,12 +7234,12 @@ fail:
#define H2C_WAKEUP_CTRL_LEN 4
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct sk_buff *skb;
- u8 macid = rtwvif->mac_id;
+ u8 macid = rtwvif_link->mac_id;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN);
@@ -7100,13 +7332,13 @@ fail:
}
int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_wow_gtk_info *gtk_info = &rtw_wow->gtk_info;
struct rtw89_h2c_wow_gtk_ofld *h2c;
- u8 macid = rtwvif->mac_id;
+ u8 macid = rtwvif_link->mac_id;
u32 len = sizeof(*h2c);
u8 pkt_id_sa_query = 0;
struct sk_buff *skb;
@@ -7128,14 +7360,14 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev,
if (!enable)
goto hdr;
- ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_EAPOL_KEY,
&pkt_id_eapol);
if (ret)
goto fail;
if (gtk_info->igtk_keyid) {
- ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif,
+ ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link,
RTW89_PKT_OFLD_TYPE_SA_QUERY,
&pkt_id_sa_query);
if (ret)
@@ -7173,7 +7405,7 @@ fail:
return ret;
}
-int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wait_info *wait = &rtwdev->mac.ps_wait;
@@ -7189,7 +7421,7 @@ int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
skb_put(skb, len);
h2c = (struct rtw89_h2c_fwips *)skb->data;
- h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_FW_IPS_W0_MACID) |
+ h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_FW_IPS_W0_MACID) |
le32_encode_bits(enable, RTW89_H2C_FW_IPS_W0_ENABLE);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index ad47e77d740b..efa63d444821 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -261,6 +261,7 @@ struct rtw89_fw_hdr_section_info {
u8 redl;
const u8 *addr;
u32 len;
+ u32 len_override;
u32 dladdr;
u32 mssc;
u8 type;
@@ -275,6 +276,7 @@ struct rtw89_fw_bin_info {
u32 hdr_len;
bool dynamic_hdr_en;
u32 dynamic_hdr_len;
+ u8 idmem_share_mode;
bool dsp_checksum;
bool secure_section_exist;
struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM];
@@ -563,6 +565,7 @@ struct rtw89_fw_hdr {
#define FW_HDR_W6_SEC_NUM GENMASK(15, 8)
#define FW_HDR_W7_PART_SIZE GENMASK(15, 0)
#define FW_HDR_W7_DYN_HDR BIT(16)
+#define FW_HDR_W7_IDMEM_SHARE_MODE GENMASK(21, 18)
#define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24)
struct rtw89_fw_hdr_section_v1 {
@@ -580,6 +583,7 @@ struct rtw89_fw_hdr_section_v1 {
#define FWSECTION_HDR_V1_W1_REDL BIT(29)
#define FWSECTION_HDR_V1_W2_MSSC GENMASK(7, 0)
#define FORMATTED_MSSC 0xFF
+#define FORMATTED_MSSC_MASK GENMASK(7, 0)
#define FWSECTION_HDR_V1_W2_BBMCU_IDX GENMASK(27, 24)
struct rtw89_fw_hdr_v1 {
@@ -615,6 +619,7 @@ struct rtw89_fw_hdr_v1 {
#define FW_HDR_V1_W6_DSP_CHKSUM BIT(24)
#define FW_HDR_V1_W7_PART_SIZE GENMASK(15, 0)
#define FW_HDR_V1_W7_DYN_HDR BIT(16)
+#define FW_HDR_V1_W7_IDMEM_SHARE_MODE GENMASK(21, 18)
enum rtw89_fw_mss_pool_rmp_tbl_type {
MSS_POOL_RMP_TBL_BITMASK = 0x0,
@@ -3689,6 +3694,13 @@ struct rtw89_c2h_pkt_ofld_rsp {
#define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_OP GENMASK(10, 8)
#define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_LEN GENMASK(31, 16)
+struct rtw89_c2h_tx_duty_rpt {
+ struct rtw89_c2h_hdr c2h_hdr;
+ __le32 w2;
+} __packed;
+
+#define RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR GENMASK(2, 0)
+
struct rtw89_c2h_wow_aoac_report {
struct rtw89_c2h_hdr c2h_hdr;
u8 rpt_ver;
@@ -3713,6 +3725,15 @@ struct rtw89_c2h_wow_aoac_report {
#define RTW89_C2H_WOW_AOAC_RPT_REKEY_IDX BIT(0)
+struct rtw89_h2c_tx_duty {
+ __le32 w0;
+ __le32 w1;
+} __packed;
+
+#define RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK GENMASK(15, 0)
+#define RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK GENMASK(31, 16)
+#define RTW89_H2C_TX_DUTY_W1_STOP BIT(0)
+
struct rtw89_h2c_bcnfltr {
__le32 w0;
} __packed;
@@ -4071,6 +4092,7 @@ enum rtw89_fw_ofld_h2c_func {
H2C_FUNC_OFLD_CFG = 0x14,
H2C_FUNC_ADD_SCANOFLD_CH = 0x16,
H2C_FUNC_SCANOFLD = 0x17,
+ H2C_FUNC_TX_DUTY = 0x18,
H2C_FUNC_PKT_DROP = 0x1b,
H2C_FUNC_CFG_BCNFLTR = 0x1e,
H2C_FUNC_OFLD_RSSI = 0x1f,
@@ -4286,7 +4308,7 @@ struct rtw89_h2c_rf_dack {
__le32 type;
} __packed;
-struct rtw89_h2c_rf_rxdck {
+struct rtw89_h2c_rf_rxdck_v0 {
u8 len;
u8 phy;
u8 is_afe;
@@ -4297,6 +4319,11 @@ struct rtw89_h2c_rf_rxdck {
u8 rxdck_dbg_en;
} __packed;
+struct rtw89_h2c_rf_rxdck {
+ struct rtw89_h2c_rf_rxdck_v0 v0;
+ u8 is_chl_k;
+} __packed;
+
enum rtw89_rf_log_type {
RTW89_RF_RUN_LOG = 0,
RTW89_RF_RPT_LOG = 1,
@@ -4313,6 +4340,42 @@ struct rtw89_c2h_rf_run_log {
__le32 arg[4];
} __packed;
+struct rtw89_c2h_rf_iqk_rpt_log {
+ bool iqk_tx_fail[2];
+ bool iqk_rx_fail[2];
+ bool is_iqk_init;
+ bool is_reload;
+ bool is_wb_txiqk[2];
+ bool is_wb_rxiqk[2];
+ bool is_nbiqk;
+ bool txiqk_en;
+ bool rxiqk_en;
+ bool lok_en;
+ bool iqk_xym_en;
+ bool iqk_sram_en;
+ bool iqk_fft_en;
+ bool is_fw_iqk;
+ bool is_iqk_enable;
+ bool iqk_cfir_en;
+ bool thermal_rek_en;
+ u8 iqk_band[2];
+ u8 iqk_ch[2];
+ u8 iqk_bw[2];
+ u8 iqk_times;
+ u8 version;
+ u8 phy;
+ u8 fwk_status;
+ u8 rsvd;
+ __le32 reload_cnt;
+ __le32 iqk_fail_cnt;
+ __le32 lok_idac[2];
+ __le32 lok_vbuf[2];
+ __le32 rftxgain[2][4];
+ __le32 rfrxgain[2][4];
+ __le32 tx_xym[2][4];
+ __le32 rx_xym[2][4];
+} __packed;
+
struct rtw89_c2h_rf_dpk_rpt_log {
u8 ver;
u8 idx[2];
@@ -4334,19 +4397,25 @@ struct rtw89_c2h_rf_dpk_rpt_log {
struct rtw89_c2h_rf_dack_rpt_log {
u8 fwdack_ver;
- u8 fwdack_rpt_ver;
+ u8 fwdack_info_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 addck2_hd[2][2][2];
+ u8 addck2_ld[2][2][2];
u8 adgaink_d[2][2];
- __le16 biask_d[2][2];
+ u8 biask_hd[2][2];
+ u8 biask_ld[2][2];
u8 addck_timeout;
u8 cdack_timeout;
u8 dadck_timeout;
u8 msbk_timeout;
u8 adgaink_timeout;
+ u8 wbadcdck_timeout;
+ u8 drck_timeout;
u8 dack_fail;
+ u8 wbdck_d[2];
+ u8 rck_d;
} __packed;
struct rtw89_c2h_rf_rxdck_rpt_log {
@@ -4357,6 +4426,14 @@ struct rtw89_c2h_rf_rxdck_rpt_log {
u8 timeout[2];
} __packed;
+struct rtw89_c2h_rf_tssi_rpt_log {
+ s8 alignment_power[2][2][4];
+ u8 alignment_power_cw_h[2][2][4];
+ u8 alignment_power_cw_l[2][2][4];
+ u8 tssi_alimk_state[2][2];
+ u8 default_txagc_offset[2][2];
+} __packed;
+
struct rtw89_c2h_rf_txgapk_rpt_log {
__le32 r0x8010[2];
__le32 chk_cnt;
@@ -4404,59 +4481,60 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u8 type, u8 cat, u8 class, u8 func,
bool rack, bool dack, u32 len);
int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta);
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta);
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
+ struct rtw89_vif_link *rtwvif_link);
int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
-int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif,
- struct rtw89_sta *rtwsta, const u8 *scan_mac_addr);
+ struct rtw89_vif_link *rtwvif_link);
+int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif,
+ struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr);
int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h);
void rtw89_fw_c2h_work(struct work_struct *work);
int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
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_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link, 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,
+int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u8 ac, u32 val);
int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev);
+int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv);
int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
+ struct rtw89_vif_link *rtwvif_link,
bool connect);
int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu);
-int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi);
int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type);
@@ -4472,17 +4550,13 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type);
int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id);
int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
struct sk_buff *skb_ofld);
-int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
- struct list_head *chan_list);
-int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
- struct list_head *chan_list);
int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *opt,
- struct rtw89_vif *vif,
+ struct rtw89_vif_link *vif,
bool wowlan);
int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *opt,
- struct rtw89_vif *vif,
+ struct rtw89_vif_link *vif,
bool wowlan);
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
struct rtw89_fw_h2c_rf_reg_info *info,
@@ -4501,21 +4575,26 @@ int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
const struct rtw89_chan *chan);
int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
- const struct rtw89_chan *chan);
+ const struct rtw89_chan *chan, bool is_chl_k);
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
bool rack, bool dack);
int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len);
void rtw89_fw_send_all_early_h2c(struct rtw89_dev *rtwdev);
void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev);
-int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u8 macid);
void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool notify_fw);
+ struct rtw89_vif_link *rtwvif_link,
+ bool notify_fw);
void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw);
-int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
bool valid, struct ieee80211_ampdu_params *params);
-int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
bool valid, struct ieee80211_ampdu_params *params);
void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users,
@@ -4524,8 +4603,8 @@ int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users,
int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev,
struct rtw89_lps_parm *lps_param);
int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
-int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link);
+int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len);
struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len);
@@ -4534,49 +4613,56 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
struct rtw89_mac_c2h_info *c2h_info);
int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable);
void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev);
-void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *req);
-void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_scan_request *scan_req);
+void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool aborted);
-int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool enable);
-void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected);
+ struct rtw89_vif_link *rtwvif_link, bool connected);
int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
+ struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected);
+ struct rtw89_vif_link *rtwvif_link, bool connected);
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
+ struct rtw89_vif_link *rtwvif_link);
int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev,
const struct rtw89_pkt_drop_params *params);
-int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
+int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf,
struct ieee80211_p2p_noa_desc *desc,
u8 act, u8 noa_id);
-int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool en);
-int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable);
-int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link, bool enable);
+int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
-int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable);
+ struct rtw89_vif_link *rtwvif_link, bool enable);
int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable);
-int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link, bool enable);
+int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable);
+ struct rtw89_vif_link *rtwvif_link, bool enable);
int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev,
struct rtw89_wow_cam_info *cam_info);
int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool enable);
int rtw89_fw_h2c_wow_request_aoac(struct rtw89_dev *rtwdev);
int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev,
@@ -4621,51 +4707,73 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
}
static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta);
+ return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
}
static inline int rtw89_chip_h2c_default_dmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_sta *rtwsta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (chip->ops->h2c_default_dmac_tbl)
- return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta);
+ return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
return 0;
}
static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- return chip->ops->h2c_update_beacon(rtwdev, rtwvif);
+ return chip->ops->h2c_update_beacon(rtwdev, rtwvif_link);
}
static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta);
+ return chip->ops->h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
}
-static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static inline
+int rtw89_chip_h2c_ampdu_link_cmac_tbl(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (chip->ops->h2c_ampdu_cmac_tbl)
- return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, vif, sta);
+ return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, rtwvif_link,
+ rtwsta_link);
+
+ return 0;
+}
+
+static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = rtw89_chip_h2c_ampdu_link_cmac_tbl(rtwdev, rtwvif_link,
+ rtwsta_link);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -4675,8 +4783,20 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
bool valid, struct ieee80211_ampdu_params *params)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = chip->ops->h2c_ba_cam(rtwdev, rtwvif_link, rtwsta_link,
+ valid, params);
+ if (ret)
+ return ret;
+ }
- return chip->ops->h2c_ba_cam(rtwdev, rtwsta, valid, params);
+ return 0;
}
/* must consider compatibility; don't insert new in the mid */
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index c70a23a763b0..7907b84d204b 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -1444,6 +1444,7 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev)
static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
{
#define PWR_ACT 1
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_pwr_cfg * const *cfg_seq;
int (*cfg_func)(struct rtw89_dev *rtwdev);
@@ -1472,6 +1473,9 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
return ret;
if (on) {
+ if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags))
+ mac->efuse_read_fw_secure(rtwdev);
+
set_bit(RTW89_FLAG_POWERON, rtwdev->flags);
set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags);
set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags);
@@ -1483,7 +1487,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
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);
+ rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false);
+ rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false);
}
return 0;
@@ -3995,9 +4000,10 @@ fail:
static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid)
{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
u8 i;
- if (rtwdev->chip->chip_gen != RTW89_CHIP_AX)
+ if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot)
return;
for (i = 0; i < 4; i++) {
@@ -4009,7 +4015,9 @@ static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid)
static void rtw89_mac_cmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid)
{
- if (rtwdev->chip->chip_gen != RTW89_CHIP_AX)
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+
+ if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot)
return;
rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR,
@@ -4076,17 +4084,17 @@ static const struct rtw89_port_reg rtw89_port_base_ax = {
};
static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u8 type)
+ struct rtw89_vif_link *rtwvif_link, u8 type)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port);
+ u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif_link->port);
u32 reg_info, reg_ctrl;
u32 val;
int ret;
- reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif->mac_idx);
- reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif->mac_idx);
+ reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif_link->mac_idx);
+ reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif_link->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);
@@ -4098,26 +4106,32 @@ static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev,
rtw89_warn(rtwdev, "Polling beacon packet empty fail\n");
}
-static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_set(rtwdev, p->bcn_drop_all, 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, p->bcn_drop_all, BIT(rtwvif->port));
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN);
+ rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port));
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK,
+ 1);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area, B_AX_BCN_MSK_AREA_MASK,
+ 0);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK,
+ 0);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK, 2);
+ rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early,
+ B_AX_TBTTERLY_MASK, 1);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space,
+ B_AX_BCN_SPACE_MASK, 1);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN);
+
+ rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM0);
+ if (rtwvif_link->port == RTW89_PORT_0)
+ rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM1);
+
+ rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port));
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TBTT_PROHIB_EN);
fsleep(2000);
}
@@ -4131,286 +4145,329 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi
#define BCN_ERLY_SET_DLY (10 * 2)
static void rtw89_mac_port_cfg_func_sw(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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;
+ struct ieee80211_bss_conf *bss_conf;
bool need_backup = false;
u32 backup_val;
+ u16 beacon_int;
- if (!rtw89_read32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN))
+ if (!rtw89_read32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN))
return;
- if (chip->chip_id == RTL8852A && rtwvif->port != RTW89_PORT_0) {
+ if (chip->chip_id == RTL8852A && rtwvif_link->port != RTW89_PORT_0) {
need_backup = true;
- backup_val = rtw89_read32_port(rtwdev, rtwvif, p->tbtt_prohib);
+ backup_val = rtw89_read32_port(rtwdev, rtwvif_link, p->tbtt_prohib);
}
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
- rtw89_mac_bcn_drop(rtwdev, rtwvif);
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
+ rtw89_mac_bcn_drop(rtwdev, rtwvif_link);
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);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->tbtt_prohib,
+ B_AX_TBTT_SETUP_MASK);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib,
+ B_AX_TBTT_HOLD_MASK, 1);
+ rtw89_write16_port_clr(rtwdev, rtwvif_link, p->tbtt_early,
+ B_AX_TBTTERLY_MASK);
+ rtw89_write16_port_clr(rtwdev, rtwvif_link, 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 |
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ beacon_int = bss_conf->beacon_int;
+
+ rcu_read_unlock();
+
+ msleep(beacon_int + 1);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, 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);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSFTR_RST);
+ rtw89_write32_port(rtwdev, rtwvif_link, p->bcn_cnt_tmr, 0);
if (need_backup)
- rtw89_write32_port(rtwdev, rtwvif, p->tbtt_prohib, backup_val);
+ rtw89_write32_port(rtwdev, rtwvif_link, p->tbtt_prohib, backup_val);
}
static void rtw89_mac_port_cfg_tx_rpt(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en)
+ struct rtw89_vif_link *rtwvif_link, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg,
+ B_AX_TXBCN_RPT_EN);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg,
+ B_AX_TXBCN_RPT_EN);
}
static void rtw89_mac_port_cfg_rx_rpt(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en)
+ struct rtw89_vif_link *rtwvif_link, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg,
+ B_AX_RXBCN_RPT_EN);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg,
+ B_AX_RXBCN_RPT_EN);
}
static void rtw89_mac_port_cfg_net_type(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_NET_TYPE_MASK,
- rtwvif->net_type);
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_NET_TYPE_MASK,
+ rtwvif_link->net_type);
}
static void rtw89_mac_port_cfg_bcn_prct(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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_NO_LINK;
+ bool en = rtwvif_link->net_type != RTW89_NET_TYPE_NO_LINK;
u32 bits = B_AX_TBTT_PROHIB_EN | B_AX_BRK_SETUP;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bits);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bits);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bits);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bits);
}
static void rtw89_mac_port_cfg_rx_sw(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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_INFRA ||
- rtwvif->net_type == RTW89_NET_TYPE_AD_HOC;
+ bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA ||
+ rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC;
u32 bit = B_AX_RX_BSSID_FIT_EN;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bit);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bit);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bit);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bit);
}
void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en)
+ struct rtw89_vif_link *rtwvif_link, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN);
}
static void rtw89_mac_port_cfg_rx_sync_by_nettype(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
- bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA ||
- rtwvif->net_type == RTW89_NET_TYPE_AD_HOC;
+ bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA ||
+ rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC;
- rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, en);
+ rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, en);
}
static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en)
+ struct rtw89_vif_link *rtwvif_link, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
if (en)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN);
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN);
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, 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)
+ struct rtw89_vif_link *rtwvif_link)
{
- bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ||
- rtwvif->net_type == RTW89_NET_TYPE_AD_HOC;
+ bool en = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE ||
+ rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC;
- rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en);
+ rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en);
}
void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
- rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
+ rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en);
}
static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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);
- u16 bcn_int = vif->bss_conf.beacon_int ? vif->bss_conf.beacon_int : BCN_INTERVAL;
+ struct ieee80211_bss_conf *bss_conf;
+ u16 bcn_int;
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ if (bss_conf->beacon_int)
+ bcn_int = bss_conf->beacon_int;
+ else
+ bcn_int = BCN_INTERVAL;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK,
+ rcu_read_unlock();
+
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space, B_AX_BCN_SPACE_MASK,
bcn_int);
}
static void rtw89_mac_port_cfg_hiq_win(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
- u8 win = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0;
+ u8 win = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0;
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
u32 reg;
- reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif_link->mac_idx);
rtw89_write8(rtwdev, reg, win);
}
static void rtw89_mac_port_cfg_hiq_dtim(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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);
+ struct ieee80211_bss_conf *bss_conf;
+ u8 dtim_period;
u32 addr;
- addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif->mac_idx);
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ dtim_period = bss_conf->dtim_period;
+
+ rcu_read_unlock();
+
+ addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif_link->mac_idx);
rtw89_write8_set(rtwdev, addr, B_AX_UPD_HGQMD | B_AX_UPD_TIMIE);
- rtw89_write16_port_mask(rtwdev, rtwvif, p->dtim_ctrl, B_AX_DTIM_NUM_MASK,
- vif->bss_conf.dtim_period);
+ rtw89_write16_port_mask(rtwdev, rtwvif_link, p->dtim_ctrl, B_AX_DTIM_NUM_MASK,
+ dtim_period);
}
static void rtw89_mac_port_cfg_bcn_setup_time(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib,
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib,
B_AX_TBTT_SETUP_MASK, BCN_SETUP_DEF);
}
static void rtw89_mac_port_cfg_bcn_hold_time(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib,
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib,
B_AX_TBTT_HOLD_MASK, BCN_HOLD_DEF);
}
static void rtw89_mac_port_cfg_bcn_mask_area(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area,
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area,
B_AX_BCN_MSK_AREA_MASK, BCN_MASK_DEF);
}
static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early,
+ rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early,
B_AX_TBTTERLY_MASK, TBTT_ERLY_DEF);
}
static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
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);
static const u32 masks[RTW89_PORT_NUM] = {
B_AX_BSS_COLOB_AX_PORT_0_MASK, B_AX_BSS_COLOB_AX_PORT_1_MASK,
B_AX_BSS_COLOB_AX_PORT_2_MASK, B_AX_BSS_COLOB_AX_PORT_3_MASK,
B_AX_BSS_COLOB_AX_PORT_4_MASK,
};
- u8 port = rtwvif->port;
+ struct ieee80211_bss_conf *bss_conf;
+ u8 port = rtwvif_link->port;
u32 reg_base;
u32 reg;
u8 bss_color;
- bss_color = vif->bss_conf.he_bss_color.color;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ bss_color = bss_conf->he_bss_color.color;
+
+ rcu_read_unlock();
+
reg_base = port >= 4 ? p->bss_color + 4 : p->bss_color;
- reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, masks[port], bss_color);
}
static void rtw89_mac_port_cfg_mbssid(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
u32 reg;
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE)
return;
if (port == 0) {
- reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif_link->mac_idx);
rtw89_write32_clr(rtwdev, reg, B_AX_P0MB_ALL_MASK);
}
}
static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
u32 reg;
u32 val;
- reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif_link->mac_idx);
val = rtw89_read32(rtwdev, reg);
val &= ~FIELD_PREP(B_AX_PORT_DROP_4_0_MASK, BIT(port));
if (port == 0)
@@ -4419,31 +4476,31 @@ static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_port_cfg_func_en(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool enable)
+ struct rtw89_vif_link *rtwvif_link, bool enable)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
if (enable)
- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg,
+ rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg,
B_AX_PORT_FUNC_EN);
else
- rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg,
+ rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg,
B_AX_PORT_FUNC_EN);
}
static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK,
+ rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK,
BCN_ERLY_DEF);
}
static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
@@ -4452,20 +4509,20 @@ static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev,
if (rtwdev->chip->chip_id != RTL8852C)
return;
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT &&
- rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT &&
+ rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
return;
val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) |
B_AX_TBTT_SHIFT_OFST_SIGN;
- rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_shift,
+ rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift,
B_AX_TBTT_SHIFT_OFST_MASK, val);
}
void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_vif *rtwvif_src,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_vif_link *rtwvif_src,
u16 offset_tu)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
@@ -4473,8 +4530,8 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
u32 val, reg;
val = RTW89_PORT_OFFSET_TU_TO_32US(offset_tu);
- reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif->port * 4,
- rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif_link->port * 4,
+ rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port);
rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_OFFSET_VAL, val);
@@ -4482,16 +4539,16 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_vif *rtwvif_src,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_vif_link *rtwvif_src,
u8 offset, int *n_offset)
{
- if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src)
+ if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif_link == rtwvif_src)
return;
/* adjust offset randomly to avoid beacon conflict */
offset = offset - offset / 4 + get_random_u32() % (offset / 2);
- rtw89_mac_port_tsf_sync(rtwdev, rtwvif, rtwvif_src,
+ rtw89_mac_port_tsf_sync(rtwdev, rtwvif_link, rtwvif_src,
(*n_offset) * offset);
(*n_offset)++;
@@ -4499,15 +4556,19 @@ static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev,
static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev)
{
- struct rtw89_vif *src = NULL, *tmp;
+ struct rtw89_vif_link *src = NULL, *tmp;
u8 offset = 100, vif_aps = 0;
+ struct rtw89_vif *rtwvif;
+ unsigned int link_id;
int n_offset = 1;
- rtw89_for_each_rtwvif(rtwdev, tmp) {
- if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA)
- src = tmp;
- if (tmp->net_type == RTW89_NET_TYPE_AP_MODE)
- vif_aps++;
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ rtw89_vif_for_each_link(rtwvif, tmp, link_id) {
+ if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA)
+ src = tmp;
+ if (tmp->net_type == RTW89_NET_TYPE_AP_MODE)
+ vif_aps++;
+ }
}
if (vif_aps == 0)
@@ -4515,104 +4576,106 @@ static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev)
offset /= (vif_aps + 1);
- rtw89_for_each_rtwvif(rtwdev, tmp)
- rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, &n_offset);
+ rtw89_for_each_rtwvif(rtwdev, rtwvif)
+ rtw89_vif_for_each_link(rtwvif, tmp, link_id)
+ rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset,
+ &n_offset);
}
-int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
int ret;
- ret = rtw89_mac_port_update(rtwdev, rtwvif);
+ ret = rtw89_mac_port_update(rtwdev, rtwvif_link);
if (ret)
return ret;
- rtw89_mac_dmac_tbl_init(rtwdev, rtwvif->mac_id);
- rtw89_mac_cmac_tbl_init(rtwdev, rtwvif->mac_id);
+ rtw89_mac_dmac_tbl_init(rtwdev, rtwvif_link->mac_id);
+ rtw89_mac_cmac_tbl_init(rtwdev, rtwvif_link->mac_id);
- ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif->mac_id, false);
+ ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif_link->mac_id, false);
if (ret)
return ret;
- ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_CREATE);
+ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_CREATE);
if (ret)
return ret;
- ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
+ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true);
if (ret)
return ret;
- ret = rtw89_cam_init(rtwdev, rtwvif);
+ ret = rtw89_cam_init(rtwdev, rtwvif_link);
if (ret)
return ret;
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
if (ret)
return ret;
- ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, NULL);
+ ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, NULL);
if (ret)
return ret;
- ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, NULL);
+ ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, NULL);
if (ret)
return ret;
return 0;
}
-int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
int ret;
- ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_REMOVE);
+ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_REMOVE);
if (ret)
return ret;
- rtw89_cam_deinit(rtwdev, rtwvif);
+ rtw89_cam_deinit(rtwdev, rtwvif_link);
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
if (ret)
return ret;
return 0;
}
-int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- u8 port = rtwvif->port;
+ u8 port = rtwvif_link->port;
if (port >= RTW89_PORT_NUM)
return -EINVAL;
- rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif);
- rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif, false);
- rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif, false);
- rtw89_mac_port_cfg_net_type(rtwdev, rtwvif);
- rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif);
- rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif);
- rtw89_mac_port_cfg_rx_sync_by_nettype(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);
- rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif);
- rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif);
- rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif);
- rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif);
- rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif);
- rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif);
- rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif);
- rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif);
- rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, true);
+ rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif_link, false);
+ rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif_link, false);
+ rtw89_mac_port_cfg_net_type(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link);
+ rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true);
rtw89_mac_port_tsf_resync_all(rtwdev);
fsleep(BCN_ERLY_SET_DLY);
- rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif);
+ rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link);
return 0;
}
-int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u64 *tsf)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
@@ -4620,12 +4683,12 @@ int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
u32 tsf_low, tsf_high;
int ret;
- ret = rtw89_mac_check_mac_en(rtwdev, rtwvif->mac_idx, RTW89_CMAC_SEL);
+ ret = rtw89_mac_check_mac_en(rtwdev, rtwvif_link->mac_idx, RTW89_CMAC_SEL);
if (ret)
return ret;
- tsf_low = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_l);
- tsf_high = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_h);
+ tsf_low = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_l);
+ tsf_high = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_h);
*tsf = (u64)tsf_high << 32 | tsf_low;
return 0;
@@ -4651,65 +4714,57 @@ static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
}
void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif)
+ struct rtw89_vif_link *rtwvif_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct ieee80211_hw *hw = rtwdev->hw;
+ struct ieee80211_bss_conf *bss_conf;
+ struct cfg80211_chan_def oper;
bool tolerated = true;
u32 reg;
- if (!vif->bss_conf.he_support || vif->type != NL80211_IFTYPE_STATION)
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ if (!bss_conf->he_support || vif->type != NL80211_IFTYPE_STATION) {
+ rcu_read_unlock();
return;
+ }
- if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR))
+ oper = bss_conf->chanreq.oper;
+ if (!(oper.chan->flags & IEEE80211_CHAN_RADAR)) {
+ rcu_read_unlock();
return;
+ }
- cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper,
+ rcu_read_unlock();
+
+ cfg80211_bss_iter(hw->wiphy, &oper,
rtw89_mac_check_he_obss_narrow_bw_ru_iter,
&tolerated);
reg = rtw89_mac_reg_by_idx(rtwdev, mac->narrow_bw_ru_dis.addr,
- rtwvif->mac_idx);
+ rtwvif_link->mac_idx);
if (tolerated)
rtw89_write32_clr(rtwdev, reg, mac->narrow_bw_ru_dis.mask);
else
rtw89_write32_set(rtwdev, reg, mac->narrow_bw_ru_dis.mask);
}
-void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif);
+ rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link);
}
-int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- int ret;
-
- rtwvif->mac_id = rtw89_acquire_mac_id(rtwdev);
- if (rtwvif->mac_id == RTW89_MAX_MAC_ID_NUM)
- return -ENOSPC;
-
- ret = rtw89_mac_vif_init(rtwdev, rtwvif);
- if (ret)
- goto release_mac_id;
-
- return 0;
-
-release_mac_id:
- rtw89_release_mac_id(rtwdev, rtwvif->mac_id);
-
- return ret;
+ return rtw89_mac_vif_init(rtwdev, rtwvif_link);
}
-int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- int ret;
-
- ret = rtw89_mac_vif_deinit(rtwdev, rtwvif);
- rtw89_release_mac_id(rtwdev, rtwvif->mac_id);
-
- return ret;
+ return rtw89_mac_vif_deinit(rtwdev, rtwvif_link);
}
static void
@@ -4730,8 +4785,8 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
{
const struct rtw89_c2h_scanofld *c2h =
(const struct rtw89_c2h_scanofld *)skb->data;
- struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
+ struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif *rtwvif;
struct rtw89_chan new;
u8 reason, status, tx_fail, band, actual_period, expect_period;
u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf;
@@ -4739,9 +4794,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u16 chan;
int ret;
- if (!rtwvif)
+ if (!rtwvif_link)
return;
+ rtwvif = rtwvif_link->rtwvif;
+
tx_fail = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_TX_FAIL);
status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS);
chan = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PRI_CH);
@@ -4781,28 +4838,28 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (rtwdev->scan_info.abort)
return;
- if (rtwvif && rtwvif->scan_req &&
+ if (rtwvif_link && rtwvif->scan_req &&
last_chan < rtwvif->scan_req->n_channels) {
- ret = rtw89_hw_scan_offload(rtwdev, vif, true);
+ ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
- rtw89_hw_scan_abort(rtwdev, vif);
+ rtw89_hw_scan_abort(rtwdev, rtwvif_link);
rtw89_warn(rtwdev, "HW scan failed: %d\n", ret);
}
} else {
- rtw89_hw_scan_complete(rtwdev, vif, false);
+ rtw89_hw_scan_complete(rtwdev, rtwvif_link, false);
}
break;
case RTW89_SCAN_ENTER_OP_NOTIFY:
case RTW89_SCAN_ENTER_CH_NOTIFY:
if (rtw89_is_op_chan(rtwdev, band, chan)) {
- rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx,
+ rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_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,
RTW89_CHANNEL_WIDTH_20);
- rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx,
+ rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx,
&new);
}
break;
@@ -4812,10 +4869,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
}
static void
-rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
struct sk_buff *skb)
{
- struct ieee80211_vif *vif = rtwvif_to_vif_safe(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
enum nl80211_cqm_rssi_threshold_event nl_event;
const struct rtw89_c2h_mac_bcnfltr_rpt *c2h =
(const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data;
@@ -4827,7 +4885,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
event = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_EVENT);
mac_id = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_MACID);
- if (mac_id != rtwvif->mac_id)
+ if (mac_id != rtwvif_link->mac_id)
return;
rtw89_debug(rtwdev, RTW89_DBG_FW,
@@ -4839,7 +4897,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
if (!rtwdev->scanning && !rtwvif->offchan)
ieee80211_connection_loss(vif);
else
- rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
return;
case RTW89_BCN_FLTR_NOTIFY:
nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
@@ -4863,10 +4921,13 @@ static void
rtw89_mac_c2h_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
u32 len)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif, c2h);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif_link, c2h);
}
static void
@@ -4975,6 +5036,18 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h,
}
static void
+rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len)
+{
+ struct rtw89_c2h_tx_duty_rpt *c2h =
+ (struct rtw89_c2h_tx_duty_rpt *)skb_c2h->data;
+ u8 err;
+
+ err = le32_get_bits(c2h->w2, RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "C2H TX duty rpt with err=%d\n", err);
+}
+
+static void
rtw89_mac_c2h_tsf32_toggle_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
u32 len)
{
@@ -5300,6 +5373,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL,
[RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause,
[RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp,
+ [RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt,
[RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT] = rtw89_mac_c2h_tsf32_toggle_rpt,
[RTW89_MAC_C2H_FUNC_BCNFLTR_RPT] = rtw89_mac_c2h_bcn_fltr_rpt,
};
@@ -5490,7 +5564,8 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab
return 0;
}
-void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx)
+static
+void __rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx)
{
#define MAC_AX_TIME_TH_SH 5
#define MAC_AX_LEN_TH_SH 4
@@ -5520,6 +5595,13 @@ void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx)
rtw89_write16_mask(rtwdev, reg, B_AX_RTS_LEN_TH_MASK, len_th);
}
+void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev)
+{
+ __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_1);
+}
+
void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop)
{
bool empty;
@@ -5931,15 +6013,15 @@ static int rtw89_mac_init_bfee_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
}
static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- u8 mac_idx = rtwvif->mac_idx;
u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1;
- u8 port_sel = rtwvif->port;
+ struct ieee80211_link_sta *link_sta;
+ u8 mac_idx = rtwvif_link->mac_idx;
+ u8 port_sel = rtwvif_link->port;
u8 sound_dim = 3, t;
- u8 *phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
+ u8 *phy_cap;
u32 reg;
u16 val;
int ret;
@@ -5948,6 +6030,11 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
if (ret)
return ret;
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
+
if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
(phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) {
ldpc_en &= !!(phy_cap[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD);
@@ -5956,17 +6043,19 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
phy_cap[5]);
sound_dim = min(sound_dim, t);
}
- if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
- ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
- stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
+ if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
+ ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
+ stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
t = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
- sta->deflink.vht_cap.cap);
+ link_sta->vht_cap.cap);
sound_dim = min(sound_dim, t);
}
nc = min(nc, sound_dim);
nr = min(nr, sound_dim);
+ rcu_read_unlock();
+
reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL);
@@ -5989,34 +6078,41 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev,
}
static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M);
+ struct ieee80211_link_sta *link_sta;
+ u8 mac_idx = rtwvif_link->mac_idx;
u32 reg;
- u8 mac_idx = rtwvif->mac_idx;
int ret;
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
if (ret)
return ret;
- if (sta->deflink.he_cap.has_he) {
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ if (link_sta->he_cap.has_he) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) |
BIT(RTW89_MAC_BF_RRSC_HE_MSC3) |
BIT(RTW89_MAC_BF_RRSC_HE_MSC5));
}
- if (sta->deflink.vht_cap.vht_supported) {
+ if (link_sta->vht_cap.vht_supported) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) |
BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) |
BIT(RTW89_MAC_BF_RRSC_VHT_MSC5));
}
- if (sta->deflink.ht_cap.ht_supported) {
+ if (link_sta->ht_cap.ht_supported) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) |
BIT(RTW89_MAC_BF_RRSC_HT_MSC3) |
BIT(RTW89_MAC_BF_RRSC_HT_MSC5));
}
+
+ rcu_read_unlock();
+
reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL);
rtw89_write32_clr(rtwdev, reg, B_AX_BFMEE_CSI_FORCE_RETE_EN);
@@ -6028,35 +6124,53 @@ static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_bf_assoc_ax(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct ieee80211_link_sta *link_sta;
+ bool has_beamformer_cap;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta);
- if (rtw89_sta_has_beamformer_cap(sta)) {
+ rcu_read_unlock();
+
+ if (has_beamformer_cap) {
rtw89_debug(rtwdev, RTW89_DBG_BF,
"initialize bfee for new association\n");
- rtw89_mac_init_bfee_ax(rtwdev, rtwvif->mac_idx);
- rtw89_mac_set_csi_para_reg_ax(rtwdev, vif, sta);
- rtw89_mac_csi_rrsc_ax(rtwdev, vif, sta);
+ rtw89_mac_init_bfee_ax(rtwdev, rtwvif_link->mac_idx);
+ rtw89_mac_set_csi_para_reg_ax(rtwdev, rtwvif_link, rtwsta_link);
+ rtw89_mac_csi_rrsc_ax(rtwdev, rtwvif_link, rtwsta_link);
}
}
-void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
-
- rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, false);
+ rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, false);
}
void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- u8 mac_idx = rtwvif->mac_idx;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ u8 mac_idx;
__le32 *p;
+ rtwvif_link = rtwvif->links[conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, conf->link_id);
+ return;
+ }
+
+ mac_idx = rtwvif_link->mac_idx;
+
rtw89_debug(rtwdev, RTW89_DBG_BF, "update bf GID table\n");
p = (__le32 *)conf->mu_group.membership;
@@ -6080,7 +6194,7 @@ void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *
struct rtw89_mac_bf_monitor_iter_data {
struct rtw89_dev *rtwdev;
- struct ieee80211_sta *down_sta;
+ struct rtw89_sta_link *down_rtwsta_link;
int count;
};
@@ -6089,23 +6203,41 @@ void rtw89_mac_bf_monitor_calc_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_mac_bf_monitor_iter_data *iter_data =
(struct rtw89_mac_bf_monitor_iter_data *)data;
- struct ieee80211_sta *down_sta = iter_data->down_sta;
+ struct rtw89_sta_link *down_rtwsta_link = iter_data->down_rtwsta_link;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct ieee80211_link_sta *link_sta;
+ struct rtw89_sta_link *rtwsta_link;
+ bool has_beamformer_cap = false;
int *count = &iter_data->count;
+ unsigned int link_id;
- if (down_sta == sta)
- return;
+ rcu_read_lock();
- if (rtw89_sta_has_beamformer_cap(sta))
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ if (rtwsta_link == down_rtwsta_link)
+ continue;
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ if (rtw89_sta_has_beamformer_cap(link_sta)) {
+ has_beamformer_cap = true;
+ break;
+ }
+ }
+
+ if (has_beamformer_cap)
(*count)++;
+
+ rcu_read_unlock();
}
void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, bool disconnect)
+ struct rtw89_sta_link *rtwsta_link,
+ bool disconnect)
{
struct rtw89_mac_bf_monitor_iter_data data;
data.rtwdev = rtwdev;
- data.down_sta = disconnect ? sta : NULL;
+ data.down_rtwsta_link = disconnect ? rtwsta_link : NULL;
data.count = 0;
ieee80211_iterate_stations_atomic(rtwdev->hw,
rtw89_mac_bf_monitor_calc_iter,
@@ -6121,10 +6253,12 @@ void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev,
void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev)
{
struct rtw89_traffic_stats *stats = &rtwdev->stats;
- struct rtw89_vif *rtwvif;
+ struct rtw89_vif_link *rtwvif_link;
bool en = stats->tx_tfc_lv <= stats->rx_tfc_lv;
bool old = test_bit(RTW89_FLAG_BFEE_EN, rtwdev->flags);
+ struct rtw89_vif *rtwvif;
bool keep_timer = true;
+ unsigned int link_id;
bool old_keep_timer;
old_keep_timer = test_bit(RTW89_FLAG_BFEE_TIMER_KEEP, rtwdev->flags);
@@ -6134,30 +6268,32 @@ void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev)
if (keep_timer != old_keep_timer) {
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_mac_bfee_standby_timer(rtwdev, rtwvif->mac_idx,
- keep_timer);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_mac_bfee_standby_timer(rtwdev, rtwvif_link->mac_idx,
+ keep_timer);
}
if (en == old)
return;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, en);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, en);
}
static int
-__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link,
u32 tx_time)
{
#define MAC_AX_DFLT_TX_TIME 5280
- u8 mac_idx = rtwsta->rtwvif->mac_idx;
+ u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx;
u32 max_tx_time = tx_time == 0 ? MAC_AX_DFLT_TX_TIME : tx_time;
u32 reg;
int ret = 0;
- if (rtwsta->cctl_tx_time) {
- rtwsta->ampdu_max_time = (max_tx_time - 512) >> 9;
- ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta);
+ if (rtwsta_link->cctl_tx_time) {
+ rtwsta_link->ampdu_max_time = (max_tx_time - 512) >> 9;
+ ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link);
} else {
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
if (ret) {
@@ -6173,31 +6309,31 @@ __rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
return ret;
}
-int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link,
bool resume, u32 tx_time)
{
int ret = 0;
if (!resume) {
- rtwsta->cctl_tx_time = true;
- ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time);
+ rtwsta_link->cctl_tx_time = true;
+ ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time);
} else {
- ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time);
- rtwsta->cctl_tx_time = false;
+ ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time);
+ rtwsta_link->cctl_tx_time = false;
}
return ret;
}
-int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link,
u32 *tx_time)
{
- u8 mac_idx = rtwsta->rtwvif->mac_idx;
+ u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx;
u32 reg;
int ret = 0;
- if (rtwsta->cctl_tx_time) {
- *tx_time = (rtwsta->ampdu_max_time + 1) << 9;
+ if (rtwsta_link->cctl_tx_time) {
+ *tx_time = (rtwsta_link->ampdu_max_time + 1) << 9;
} else {
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
if (ret) {
@@ -6213,33 +6349,33 @@ int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
}
int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta,
+ struct rtw89_sta_link *rtwsta_link,
bool resume, u8 tx_retry)
{
int ret = 0;
- rtwsta->data_tx_cnt_lmt = tx_retry;
+ rtwsta_link->data_tx_cnt_lmt = tx_retry;
if (!resume) {
- rtwsta->cctl_tx_retry_limit = true;
- ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta);
+ rtwsta_link->cctl_tx_retry_limit = true;
+ ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link);
} else {
- ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta);
- rtwsta->cctl_tx_retry_limit = false;
+ ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link);
+ rtwsta_link->cctl_tx_retry_limit = false;
}
return ret;
}
int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 *tx_retry)
+ struct rtw89_sta_link *rtwsta_link, u8 *tx_retry)
{
- u8 mac_idx = rtwsta->rtwvif->mac_idx;
+ u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx;
u32 reg;
int ret = 0;
- if (rtwsta->cctl_tx_retry_limit) {
- *tx_retry = rtwsta->data_tx_cnt_lmt;
+ if (rtwsta_link->cctl_tx_retry_limit) {
+ *tx_retry = rtwsta_link->data_tx_cnt_lmt;
} else {
ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
if (ret) {
@@ -6255,10 +6391,10 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
}
int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en)
+ struct rtw89_vif_link *rtwvif_link, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
- u8 mac_idx = rtwvif->mac_idx;
+ u8 mac_idx = rtwvif_link->mac_idx;
u16 set = mac->muedca_ctrl.mask;
u32 reg;
u32 ret;
@@ -6326,7 +6462,9 @@ int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
}
static
-void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
+void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
static const enum rtw89_pkt_drop_sel sels[] = {
RTW89_PKT_DROP_SEL_MACID_BE_ONCE,
@@ -6334,15 +6472,14 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
RTW89_PKT_DROP_SEL_MACID_VI_ONCE,
RTW89_PKT_DROP_SEL_MACID_VO_ONCE,
};
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_pkt_drop_params params = {0};
int i;
- params.mac_band = RTW89_MAC_0;
- params.macid = rtwsta->mac_id;
- params.port = rtwvif->port;
+ params.mac_band = rtwvif_link->mac_idx;
+ params.macid = rtwsta_link->mac_id;
+ params.port = rtwvif_link->port;
params.mbssid = 0;
- params.tf_trs = rtwvif->trigger;
+ params.tf_trs = rtwvif_link->trigger;
for (i = 0; i < ARRAY_SIZE(sels); i++) {
params.sel = sels[i];
@@ -6352,15 +6489,21 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
static void rtw89_mac_pkt_drop_vif_iter(void *data, struct ieee80211_sta *sta)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
- struct rtw89_dev *rtwdev = rtwvif->rtwdev;
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
struct rtw89_vif *target = data;
+ unsigned int link_id;
if (rtwvif != target)
return;
- rtw89_mac_pkt_drop_sta(rtwdev, rtwsta);
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ rtw89_mac_pkt_drop_sta(rtwdev, rtwvif_link, rtwsta_link);
+ }
}
void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
@@ -6398,6 +6541,9 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
struct rtw89_mac_c2h_info c2h_info = {};
u32 ret;
+ if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw))
+ return 0;
+
h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL;
h2c_info.content_len = sizeof(h2c_info.u.hdr);
h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN);
@@ -6434,6 +6580,9 @@ static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow)
rtw89_write32(rtwdev, R_AX_TF_FWD, 0);
rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0);
+ if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw))
+ return 0;
+
if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev))
rtw89_write8(rtwdev, R_BE_DBG_WOW_READY, WOWLAN_NOT_READY);
else
@@ -6475,6 +6624,20 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev,
rtwdev, R_AX_WCPU_FW_CTRL);
}
+static
+void rtw89_fwdl_secure_idmem_share_mode_ax(struct rtw89_dev *rtwdev, u8 mode)
+{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+
+ if (!sec->secure_boot)
+ return;
+
+ rtw89_write32_mask(rtwdev, R_AX_WCPU_FW_CTRL,
+ B_AX_IDMEM_SHARE_MODE_RECORD_MASK, mode);
+ rtw89_write32_set(rtwdev, R_AX_WCPU_FW_CTRL,
+ B_AX_IDMEM_SHARE_MODE_RECORD_VALID);
+}
+
const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.band1_offset = RTW89_MAC_AX_BAND_REG_OFFSET,
.filter_model_addr = R_AX_FILTER_MODEL_ADDR,
@@ -6528,9 +6691,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_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,
+ .fwdl_secure_idmem_share_mode = rtw89_fwdl_secure_idmem_share_mode_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,
+ .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_ax,
.cfg_plt = rtw89_mac_cfg_plt_ax,
.get_plt_cnt = rtw89_mac_get_plt_cnt_ax,
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index 67c2a4507124..18579c020548 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -391,6 +391,7 @@ enum rtw89_mac_c2h_ofld_func {
RTW89_MAC_C2H_FUNC_MACID_PAUSE,
RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT = 0x6,
RTW89_MAC_C2H_FUNC_SCANOFLD_RSP = 0x9,
+ RTW89_MAC_C2H_FUNC_TX_DUTY_RPT = 0xa,
RTW89_MAC_C2H_FUNC_BCNFLTR_RPT = 0xd,
RTW89_MAC_C2H_FUNC_OFLD_MAX,
};
@@ -951,8 +952,9 @@ struct rtw89_mac_gen_def {
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);
+ void (*bf_assoc)(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
int (*typ_fltr_opt)(struct rtw89_dev *rtwdev,
enum rtw89_machdr_frame_type type,
@@ -983,9 +985,11 @@ struct rtw89_mac_gen_def {
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);
+ void (*fwdl_secure_idmem_share_mode)(struct rtw89_dev *rtwdev, u8 mode);
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);
+ int (*efuse_read_fw_secure)(struct rtw89_dev *rtwdev);
int (*cfg_plt)(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt);
u16 (*get_plt_cnt)(struct rtw89_dev *rtwdev, u8 band);
@@ -1004,12 +1008,12 @@ struct rtw89_mac_gen_def {
bool (*is_txq_empty)(struct rtw89_dev *rtwdev);
int (*add_chan_list)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected);
+ struct rtw89_vif_link *rtwvif_link, bool connected);
int (*add_chan_list_pno)(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif);
+ struct rtw89_vif_link *rtwvif_link);
int (*scan_offload)(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
bool wowlan);
int (*wow_config_mac)(struct rtw89_dev *rtwdev, bool enable_wow);
@@ -1033,81 +1037,89 @@ u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_id
}
static inline u32
-rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base)
+rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
return rtw89_read32(rtwdev, reg);
}
static inline u32
-rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u32 mask)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
return rtw89_read32_mask(rtwdev, reg, mask);
}
static inline void
-rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base,
+rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base,
u32 data)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write32(rtwdev, reg, data);
}
static inline void
-rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u32 mask, u32 data)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, mask, data);
}
static inline void
-rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u32 mask, u16 data)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write16_mask(rtwdev, reg, mask, data);
}
static inline void
-rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u32 bit)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write32_clr(rtwdev, reg, bit);
}
static inline void
-rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u16 bit)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write16_clr(rtwdev, reg, bit);
}
static inline void
-rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u32 base, u32 bit)
{
u32 reg;
- reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port,
+ rtwvif_link->mac_idx);
rtw89_write32_set(rtwdev, reg, bit);
}
@@ -1139,21 +1151,21 @@ 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);
+int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif);
+int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
- struct rtw89_vif *rtwvif_src,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_vif_link *rtwvif_src,
u16 offset_tu);
-int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
u64 *tsf);
void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en);
+ struct rtw89_vif_link *rtwvif_link, bool en);
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);
+ struct rtw89_vif_link *rtwvif_link);
+void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
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_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif);
int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev);
int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev);
@@ -1213,7 +1225,22 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable)
return mac->cfg_ppdu_status(rtwdev, mac_idx, enable);
}
-void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx);
+static inline
+int rtw89_mac_cfg_ppdu_status_bands(struct rtw89_dev *rtwdev, bool enable)
+{
+ int ret;
+
+ ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, enable);
+ if (ret)
+ return ret;
+
+ if (!rtwdev->dbcc_en)
+ return 0;
+
+ return rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_1, enable);
+}
+
+void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev);
void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop);
int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex *coex);
int rtw89_mac_coex_init_v1(struct rtw89_dev *rtwdev,
@@ -1251,27 +1278,30 @@ void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter);
void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev);
static inline
-void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
if (mac->bf_assoc)
- mac->bf_assoc(rtwdev, vif, sta);
+ mac->bf_assoc(rtwdev, rtwvif_link, rtwsta_link);
}
-void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
+void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link);
void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf);
void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, bool disconnect);
+ struct rtw89_sta_link *rtwsta_link,
+ bool disconnect);
void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev);
void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en);
-int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
-int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
+int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool en);
+ struct rtw89_vif_link *rtwvif_link, bool en);
int rtw89_mac_set_macid_pause(struct rtw89_dev *rtwdev, u8 macid, bool pause);
static inline void rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev)
@@ -1376,15 +1406,15 @@ static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev)
return !!val;
}
-int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link,
bool resume, u32 tx_time);
-int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link,
u32 *tx_time);
int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta,
+ struct rtw89_sta_link *rtwsta_link,
bool resume, u8 tx_retry);
int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta, u8 *tx_retry);
+ struct rtw89_sta_link *rtwsta_link, u8 *tx_retry);
enum rtw89_mac_xtal_si_offset {
XTAL0 = 0x0,
@@ -1466,4 +1496,14 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev,
struct rtw89_mac_dle_rsvd_qt_cfg *cfg);
int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable);
+static inline
+void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ if (!mac->fwdl_secure_idmem_share_mode)
+ return;
+
+ return mac->fwdl_secure_idmem_share_mode(rtwdev, mode);
+}
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 48ad0d0f76bf..619d2d3771d5 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -23,13 +23,13 @@ static void rtw89_ops_tx(struct ieee80211_hw *hw,
struct rtw89_dev *rtwdev = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct ieee80211_sta *sta = control->sta;
u32 flags = IEEE80211_SKB_CB(skb)->flags;
int ret, qsel;
if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) {
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
rtw89_debug(rtwdev, RTW89_DBG_TXRX, "ops_tx during offchan\n");
skb_queue_tail(&rtwsta->roc_queue, skb);
@@ -105,11 +105,61 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed)
return 0;
}
+static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct ieee80211_bss_conf *bss_conf;
+ int ret;
+
+ rtw89_leave_ps_mode(rtwdev);
+
+ rtw89_vif_type_mapping(rtwvif_link, false);
+
+ INIT_WORK(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work);
+ INIT_LIST_HEAD(&rtwvif_link->general_pkt_list);
+
+ rtwvif_link->hit_rule = 0;
+ rtwvif_link->bcn_hit_cond = 0;
+ rtwvif_link->chanctx_assigned = false;
+ rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr);
+
+ rcu_read_unlock();
+
+ ret = rtw89_mac_add_vif(rtwdev, rtwvif_link);
+ if (ret)
+ return ret;
+
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_START);
+ return 0;
+}
+
+static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ mutex_unlock(&rtwdev->mutex);
+ cancel_work_sync(&rtwvif_link->update_beacon_work);
+ mutex_lock(&rtwdev->mutex);
+
+ rtw89_leave_ps_mode(rtwdev);
+
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_STOP);
+
+ rtw89_mac_remove_vif(rtwdev, rtwvif_link);
+}
+
static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ u8 mac_id, port;
int ret = 0;
rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n",
@@ -123,49 +173,58 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
- rtwvif->rtwdev = rtwdev;
- rtwvif->roc.state = RTW89_ROC_IDLE;
- rtwvif->offchan = false;
+ mac_id = rtw89_acquire_mac_id(rtwdev);
+ if (mac_id == RTW89_MAX_MAC_ID_NUM) {
+ ret = -ENOSPC;
+ goto err;
+ }
+
+ port = rtw89_core_acquire_bit_map(rtwdev->hw_port, RTW89_PORT_NUM);
+ if (port == RTW89_PORT_NUM) {
+ ret = -ENOSPC;
+ goto release_macid;
+ }
+
+ rtw89_init_vif(rtwdev, rtwvif, mac_id, port);
+
+ rtw89_core_txq_init(rtwdev, vif->txq);
+
if (!rtw89_rtwvif_in_list(rtwdev, rtwvif))
list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
- INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work);
+ INIT_LIST_HEAD(&rtwvif->mgnt_entry);
+
+ ether_addr_copy(rtwvif->mac_addr, vif->addr);
+
+ rtwvif->offchan = false;
+ rtwvif->roc.state = RTW89_ROC_IDLE;
INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work);
- rtw89_leave_ps_mode(rtwdev);
rtw89_traffic_stats_init(rtwdev, &rtwvif->stats);
- rtw89_vif_type_mapping(vif, false);
- rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port,
- RTW89_PORT_NUM);
- if (rtwvif->port == RTW89_PORT_NUM) {
- ret = -ENOSPC;
- list_del_init(&rtwvif->list);
- goto out;
- }
- rtwvif->bcn_hit_cond = 0;
- rtwvif->mac_idx = RTW89_MAC_0;
- rtwvif->phy_idx = RTW89_PHY_0;
- rtwvif->chanctx_idx = RTW89_CHANCTX_0;
- rtwvif->chanctx_assigned = false;
- rtwvif->hit_rule = 0;
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
- ether_addr_copy(rtwvif->mac_addr, vif->addr);
- INIT_LIST_HEAD(&rtwvif->general_pkt_list);
-
- ret = rtw89_mac_add_vif(rtwdev, rtwvif);
- if (ret) {
- rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
- list_del_init(&rtwvif->list);
- goto out;
+ rtwvif_link = rtw89_vif_set_link(rtwvif, 0);
+ if (!rtwvif_link) {
+ ret = -EINVAL;
+ goto release_port;
}
- rtw89_core_txq_init(rtwdev, vif->txq);
-
- rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START);
+ ret = __rtw89_ops_add_iface_link(rtwdev, rtwvif_link);
+ if (ret)
+ goto unset_link;
rtw89_recalc_lps(rtwdev);
-out:
+
+ mutex_unlock(&rtwdev->mutex);
+ return 0;
+
+unset_link:
+ rtw89_vif_unset_link(rtwvif, 0);
+release_port:
+ list_del_init(&rtwvif->list);
+ rtw89_core_release_bit_map(rtwdev->hw_port, port);
+release_macid:
+ rtw89_release_mac_id(rtwdev, mac_id);
+err:
mutex_unlock(&rtwdev->mutex);
return ret;
@@ -175,20 +234,35 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ u8 macid = rtw89_vif_get_main_macid(rtwvif);
+ u8 port = rtw89_vif_get_main_port(rtwvif);
+ struct rtw89_vif_link *rtwvif_link;
rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n",
vif->addr, vif->type, vif->p2p);
- cancel_work_sync(&rtwvif->update_beacon_work);
cancel_delayed_work_sync(&rtwvif->roc.roc_work);
mutex_lock(&rtwdev->mutex);
- rtw89_leave_ps_mode(rtwdev);
- rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP);
- rtw89_mac_remove_vif(rtwdev, rtwvif);
- rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
+
+ rtwvif_link = rtwvif->links[0];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, 0);
+ goto bottom;
+ }
+
+ __rtw89_ops_remove_iface_link(rtwdev, rtwvif_link);
+
+ rtw89_vif_unset_link(rtwvif, 0);
+
+bottom:
list_del_init(&rtwvif->list);
+ rtw89_core_release_bit_map(rtwdev->hw_port, port);
+ rtw89_release_mac_id(rtwdev, macid);
+
rtw89_recalc_lps(rtwdev);
rtw89_enter_ips_by_hwflags(rtwdev);
@@ -311,24 +385,30 @@ static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = {
};
static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u8 aifsn)
+ struct rtw89_vif_link *rtwvif_link, u8 aifsn)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
+ struct ieee80211_bss_conf *bss_conf;
u8 slot_time;
u8 sifs;
- slot_time = vif->bss_conf.use_short_slot ? 9 : 20;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ slot_time = bss_conf->use_short_slot ? 9 : 20;
+
+ rcu_read_unlock();
+
sifs = chan->band_type == RTW89_BAND_2G ? 10 : 16;
return aifsn * slot_time + sifs;
}
static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u16 ac)
+ struct rtw89_vif_link *rtwvif_link, u16 ac)
{
- struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac];
+ struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac];
u32 val;
u8 ecw_max, ecw_min;
u8 aifs;
@@ -336,12 +416,12 @@ static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev,
/* 2^ecw - 1 = cw; ecw = log2(cw + 1) */
ecw_max = ilog2(params->cw_max + 1);
ecw_min = ilog2(params->cw_min + 1);
- aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs);
+ aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, params->aifs);
val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) |
FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) |
FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) |
FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs);
- rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val);
+ rtw89_fw_h2c_set_edca(rtwdev, rtwvif_link, ac_to_fw_idx[ac], val);
}
#define R_MUEDCA_ACS_PARAM(acs) {R_AX_MUEDCA_ ## acs ## _PARAM_0, \
@@ -355,9 +435,9 @@ static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS][RTW89_CHIP_GEN_NUM] = {
};
static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u16 ac)
+ struct rtw89_vif_link *rtwvif_link, u16 ac)
{
- struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac];
+ struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac];
struct ieee80211_he_mu_edca_param_ac_rec *mu_edca;
int gen = rtwdev->chip->chip_gen;
u8 aifs, aifsn;
@@ -370,32 +450,199 @@ static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev,
mu_edca = &params->mu_edca_param_rec;
aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn);
- aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0;
+ aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, aifsn) : 0;
timer_32us = mu_edca->mu_edca_timer << 8;
val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) |
FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) |
FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs);
- reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen],
+ rtwvif_link->mac_idx);
rtw89_write32(rtwdev, reg, val);
- rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true);
+ rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif_link, true);
}
static void __rtw89_conf_tx(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, u16 ac)
+ struct rtw89_vif_link *rtwvif_link, u16 ac)
{
- ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac);
- ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac);
+ ____rtw89_conf_tx_edca(rtwdev, rtwvif_link, ac);
+ ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif_link, ac);
}
static void rtw89_conf_tx(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
u16 ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- __rtw89_conf_tx(rtwdev, rtwvif, ac);
+ __rtw89_conf_tx(rtwdev, rtwvif_link, ac);
+}
+
+static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ bool acquire_macid = false;
+ u8 macid;
+ int ret;
+ int i;
+
+ if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
+ /* for station mode, assign the mac_id from itself */
+ macid = rtw89_vif_get_main_macid(rtwvif);
+ } else {
+ macid = rtw89_acquire_mac_id(rtwdev);
+ if (macid == RTW89_MAX_MAC_ID_NUM)
+ return -ENOSPC;
+
+ acquire_macid = true;
+ }
+
+ rtw89_init_sta(rtwdev, rtwvif, rtwsta, macid);
+
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
+ rtw89_core_txq_init(rtwdev, sta->txq[i]);
+
+ skb_queue_head_init(&rtwsta->roc_queue);
+
+ rtwsta_link = rtw89_sta_set_link(rtwsta, sta->deflink.link_id);
+ if (!rtwsta_link) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ rtwvif_link = rtwsta_link->rtwvif_link;
+
+ ret = rtw89_core_sta_link_add(rtwdev, rtwvif_link, rtwsta_link);
+ if (ret)
+ goto unset_link;
+
+ if (vif->type == NL80211_IFTYPE_AP || sta->tdls)
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
+
+ return 0;
+
+unset_link:
+ rtw89_sta_unset_link(rtwsta, sta->deflink.link_id);
+err:
+ if (acquire_macid)
+ rtw89_release_mac_id(rtwdev, macid);
+
+ return ret;
+}
+
+static int __rtw89_ops_sta_assoc(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool station_mode)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+
+ if (station_mode)
+ rtw89_vif_type_mapping(rtwvif_link, true);
+
+ ret = rtw89_core_sta_link_assoc(rtwdev, rtwvif_link, rtwsta_link);
+ if (ret)
+ return ret;
+ }
+
+ rtwdev->total_sta_assoc++;
+ if (sta->tdls)
+ rtwvif->tdls_peer++;
+
+ return 0;
+}
+
+static int __rtw89_ops_sta_disassoc(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = rtw89_core_sta_link_disassoc(rtwdev, rtwvif_link, rtwsta_link);
+ if (ret)
+ return ret;
+ }
+
+ rtwsta->disassoc = true;
+
+ rtwdev->total_sta_assoc--;
+ if (sta->tdls)
+ rtwvif->tdls_peer--;
+
+ return 0;
+}
+
+static int __rtw89_ops_sta_disconnect(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_core_free_sta_pending_ba(rtwdev, sta);
+ rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta);
+ rtw89_core_free_sta_pending_roc_tx(rtwdev, sta);
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = rtw89_core_sta_link_disconnect(rtwdev, rtwvif_link, rtwsta_link);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __rtw89_ops_sta_remove(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ u8 macid = rtw89_sta_get_main_macid(rtwsta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ int ret;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ ret = rtw89_core_sta_link_remove(rtwdev, rtwvif_link, rtwsta_link);
+ if (ret)
+ return ret;
+
+ rtw89_sta_unset_link(rtwsta, link_id);
+ }
+
+ if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
+ rtw89_release_mac_id(rtwdev, macid);
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
+ }
+
+ return 0;
}
static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev,
@@ -412,16 +659,34 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev,
return;
}
- rtw89_vif_type_mapping(vif, true);
+ __rtw89_ops_sta_assoc(rtwdev, vif, sta, true);
+}
+
+static void __rtw89_ops_bss_link_assoc(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ rtw89_phy_set_bss_color(rtwdev, rtwvif_link);
+ rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link);
+ rtw89_mac_port_update(rtwdev, rtwvif_link);
+ rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, rtwvif_link);
+}
+
+static void __rtw89_ops_bss_assoc(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
- rtw89_core_sta_assoc(rtwdev, vif, sta);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ __rtw89_ops_bss_link_assoc(rtwdev, rtwvif_link);
}
static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u64 changed)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
@@ -429,10 +694,7 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
if (vif->cfg.assoc) {
rtw89_station_mode_sta_assoc(rtwdev, vif);
- rtw89_phy_set_bss_color(rtwdev, vif);
- rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif);
- rtw89_mac_port_update(rtwdev, rtwvif);
- rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif);
+ __rtw89_ops_bss_assoc(rtwdev, vif);
rtw89_queue_chanctx_work(rtwdev);
} else {
@@ -459,39 +721,49 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,
u64 changed)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
+ rtwvif_link = rtwvif->links[conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, conf->link_id);
+ goto out;
+ }
+
if (changed & BSS_CHANGED_BSSID) {
- ether_addr_copy(rtwvif->bssid, conf->bssid);
- rtw89_cam_bssid_changed(rtwdev, rtwvif);
- rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
- WRITE_ONCE(rtwvif->sync_bcn_tsf, 0);
+ ether_addr_copy(rtwvif_link->bssid, conf->bssid);
+ rtw89_cam_bssid_changed(rtwdev, rtwvif_link);
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
+ WRITE_ONCE(rtwvif_link->sync_bcn_tsf, 0);
}
if (changed & BSS_CHANGED_BEACON)
- rtw89_chip_h2c_update_beacon(rtwdev, rtwvif);
+ rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
if (changed & BSS_CHANGED_ERP_SLOT)
- rtw89_conf_tx(rtwdev, rtwvif);
+ rtw89_conf_tx(rtwdev, rtwvif_link);
if (changed & BSS_CHANGED_HE_BSS_COLOR)
- rtw89_phy_set_bss_color(rtwdev, vif);
+ rtw89_phy_set_bss_color(rtwdev, rtwvif_link);
if (changed & BSS_CHANGED_MU_GROUPS)
rtw89_mac_bf_set_gid_table(rtwdev, vif, conf);
if (changed & BSS_CHANGED_P2P_PS)
- rtw89_core_update_p2p_ps(rtwdev, vif);
+ rtw89_core_update_p2p_ps(rtwdev, rtwvif_link, conf);
if (changed & BSS_CHANGED_CQM)
- rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
if (changed & BSS_CHANGED_TPE)
- rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true);
+ rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true);
+out:
mutex_unlock(&rtwdev->mutex);
}
@@ -500,12 +772,21 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *link_conf)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
const struct rtw89_chan *chan;
mutex_lock(&rtwdev->mutex);
- chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
+ rtwvif_link = rtwvif->links[link_conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, link_conf->link_id);
+ goto out;
+ }
+
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
if (chan->band_type == RTW89_BAND_6G) {
mutex_unlock(&rtwdev->mutex);
return -EOPNOTSUPP;
@@ -514,16 +795,18 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
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);
- rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL);
- rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE);
- rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
- rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
- rtw89_chip_rfk_channel(rtwdev, rtwvif);
+ ether_addr_copy(rtwvif_link->bssid, link_conf->bssid);
+ rtw89_cam_bssid_changed(rtwdev, rtwvif_link);
+ rtw89_mac_port_update(rtwdev, rtwvif_link);
+ rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL);
+ rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_TYPE_CHANGE);
+ rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true);
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
+ rtw89_chip_rfk_channel(rtwdev, rtwvif_link);
rtw89_queue_chanctx_work(rtwdev);
+
+out:
mutex_unlock(&rtwdev->mutex);
return 0;
@@ -534,12 +817,24 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
mutex_lock(&rtwdev->mutex);
- rtw89_mac_stop_ap(rtwdev, rtwvif);
- rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL);
- rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true);
+
+ rtwvif_link = rtwvif->links[link_conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, link_conf->link_id);
+ goto out;
+ }
+
+ rtw89_mac_stop_ap(rtwdev, rtwvif_link);
+ rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL);
+ rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true);
+
+out:
mutex_unlock(&rtwdev->mutex);
}
@@ -547,10 +842,13 @@ static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
- ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ ieee80211_queue_work(rtwdev->hw, &rtwvif_link->update_beacon_work);
return 0;
}
@@ -561,15 +859,29 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw,
const struct ieee80211_tx_queue_params *params)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ int ret = 0;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
- rtwvif->tx_params[ac] = *params;
- __rtw89_conf_tx(rtwdev, rtwvif, ac);
+
+ rtwvif_link = rtwvif->links[link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, link_id);
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ rtwvif_link->tx_params[ac] = *params;
+ __rtw89_conf_tx(rtwdev, rtwvif_link, ac);
+
+out:
mutex_unlock(&rtwdev->mutex);
- return 0;
+ return ret;
}
static int __rtw89_ops_sta_state(struct ieee80211_hw *hw,
@@ -582,26 +894,26 @@ static int __rtw89_ops_sta_state(struct ieee80211_hw *hw,
if (old_state == IEEE80211_STA_NOTEXIST &&
new_state == IEEE80211_STA_NONE)
- return rtw89_core_sta_add(rtwdev, vif, sta);
+ return __rtw89_ops_sta_add(rtwdev, vif, sta);
if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC) {
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
return 0; /* defer to bss_info_changed to have vif info */
- return rtw89_core_sta_assoc(rtwdev, vif, sta);
+ return __rtw89_ops_sta_assoc(rtwdev, vif, sta, false);
}
if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH)
- return rtw89_core_sta_disassoc(rtwdev, vif, sta);
+ return __rtw89_ops_sta_disassoc(rtwdev, vif, sta);
if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_NONE)
- return rtw89_core_sta_disconnect(rtwdev, vif, sta);
+ return __rtw89_ops_sta_disconnect(rtwdev, vif, sta);
if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST)
- return rtw89_core_sta_remove(rtwdev, vif, sta);
+ return __rtw89_ops_sta_remove(rtwdev, vif, sta);
return 0;
}
@@ -667,7 +979,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,
{
struct rtw89_dev *rtwdev = hw->priv;
struct ieee80211_sta *sta = params->sta;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
u16 tid = params->tid;
struct ieee80211_txq *txq = sta->txq[tid];
struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv;
@@ -681,7 +994,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,
mutex_lock(&rtwdev->mutex);
clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags);
clear_bit(tid, rtwsta->ampdu_map);
- rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta);
+ rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta);
mutex_unlock(&rtwdev->mutex);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
@@ -692,7 +1005,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,
rtwsta->ampdu_params[tid].amsdu = params->amsdu;
set_bit(tid, rtwsta->ampdu_map);
rtw89_leave_ps_mode(rtwdev);
- rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta);
+ rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta);
mutex_unlock(&rtwdev->mutex);
break;
case IEEE80211_AMPDU_RX_START:
@@ -720,7 +1033,7 @@ static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags))
- rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
+ rtw89_mac_update_rts_threshold(rtwdev);
mutex_unlock(&rtwdev->mutex);
return 0;
@@ -731,9 +1044,14 @@ static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
- sinfo->txrate = rtwsta->ra_report.txrate;
+ rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
+ if (unlikely(!rtwsta_link))
+ return;
+
+ sinfo->txrate = rtwsta_link->ra_report.txrate;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
@@ -743,7 +1061,7 @@ void __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
struct rtw89_vif *rtwvif;
if (vif) {
- rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ rtwvif = vif_to_rtwvif(vif);
rtw89_mac_pkt_drop_vif(rtwdev, rtwvif);
} else {
rtw89_for_each_rtwvif(rtwdev, rtwvif)
@@ -777,14 +1095,20 @@ struct rtw89_iter_bitrate_mask_data {
static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_iter_bitrate_mask_data *br_data = data;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif);
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
if (vif != br_data->vif || vif->p2p)
return;
- rtwsta->use_cfg_mask = true;
- rtwsta->mask = *br_data->mask;
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwsta_link->use_cfg_mask = true;
+ rtwsta_link->mask = *br_data->mask;
+ }
+
rtw89_phy_ra_update_sta(br_data->rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED);
}
@@ -854,10 +1178,20 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw,
const u8 *mac_addr)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
mutex_lock(&rtwdev->mutex);
- rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false);
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "sw scan start: find no link on HW-0\n");
+ goto out;
+ }
+
+ rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false);
+
+out:
mutex_unlock(&rtwdev->mutex);
}
@@ -865,9 +1199,20 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
mutex_lock(&rtwdev->mutex);
- rtw89_core_scan_complete(rtwdev, vif, false);
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "sw scan complete: find no link on HW-0\n");
+ goto out;
+ }
+
+ rtw89_core_scan_complete(rtwdev, rtwvif_link, false);
+
+out:
mutex_unlock(&rtwdev->mutex);
}
@@ -884,22 +1229,35 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
- int ret = 0;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ int ret;
if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw))
return 1;
- if (rtwdev->scanning || rtwvif->offchan)
- return -EBUSY;
-
mutex_lock(&rtwdev->mutex);
- rtw89_hw_scan_start(rtwdev, vif, req);
- ret = rtw89_hw_scan_offload(rtwdev, vif, true);
+
+ if (rtwdev->scanning || rtwvif->offchan) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "hw scan: find no link on HW-0\n");
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ rtw89_hw_scan_start(rtwdev, rtwvif_link, req);
+ ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
- rtw89_hw_scan_abort(rtwdev, vif);
+ rtw89_hw_scan_abort(rtwdev, rtwvif_link);
rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret);
}
+
+out:
mutex_unlock(&rtwdev->mutex);
return ret;
@@ -909,6 +1267,8 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct rtw89_dev *rtwdev = hw->priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw))
return;
@@ -917,14 +1277,25 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,
return;
mutex_lock(&rtwdev->mutex);
- rtw89_hw_scan_abort(rtwdev, vif);
+
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev, "cancel hw scan: find no link on HW-0\n");
+ goto out;
+ }
+
+ rtw89_hw_scan_abort(rtwdev, rtwvif_link);
+
+out:
mutex_unlock(&rtwdev->mutex);
}
static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, u32 changed)
+ struct ieee80211_link_sta *link_sta,
+ u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct rtw89_dev *rtwdev = hw->priv;
rtw89_phy_ra_update_sta(rtwdev, sta, changed);
@@ -970,11 +1341,24 @@ static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
int ret;
mutex_lock(&rtwdev->mutex);
- ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx);
+
+ rtwvif_link = rtwvif->links[link_conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, link_conf->link_id);
+ ret = -ENOLINK;
+ goto out;
+ }
+
+ ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, ctx);
+
+out:
mutex_unlock(&rtwdev->mutex);
return ret;
@@ -986,10 +1370,21 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx)
{
struct rtw89_dev *rtwdev = hw->priv;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
mutex_lock(&rtwdev->mutex);
- rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx);
+
+ rtwvif_link = rtwvif->links[link_conf->link_id];
+ if (unlikely(!rtwvif_link)) {
+ mutex_unlock(&rtwdev->mutex);
+ rtw89_err(rtwdev,
+ "%s: rtwvif link (link_id %u) is not active\n",
+ __func__, link_conf->link_id);
+ return;
+ }
+
+ rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx);
mutex_unlock(&rtwdev->mutex);
}
@@ -1003,7 +1398,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw,
struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
struct rtw89_roc *roc = &rtwvif->roc;
- if (!vif)
+ if (!rtwvif)
return -EINVAL;
mutex_lock(&rtwdev->mutex);
@@ -1053,8 +1448,8 @@ static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw,
static void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta)
{
struct cfg80211_tid_config *tid_config = data;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
rtw89_core_set_tid_config(rtwdev, sta, tid_config);
}
@@ -1203,7 +1598,7 @@ const struct ieee80211_ops rtw89_ops = {
.remain_on_channel = rtw89_ops_remain_on_channel,
.cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel,
.set_sar_specs = rtw89_ops_set_sar_specs,
- .sta_rc_update = rtw89_ops_sta_rc_update,
+ .link_sta_rc_update = rtw89_ops_sta_rc_update,
.set_tid_config = rtw89_ops_set_tid_config,
#ifdef CONFIG_PM
.suspend = rtw89_ops_suspend,
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
index 31f0a5225b11..f7a396c8a3cd 100644
--- a/drivers/net/wireless/realtek/rtw89/mac_be.c
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -773,7 +773,7 @@ static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
return ret;
}
- ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode);
+ ret = rtw89_mac_preload_init(rtwdev, mac_idx, rtwdev->mac.qta_mode);
if (ret) {
rtw89_err(rtwdev, "[ERR]preload init %d\n", ret);
return ret;
@@ -2091,13 +2091,13 @@ static int rtw89_mac_init_bfee_be(struct rtw89_dev *rtwdev, u8 mac_idx)
}
static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1;
- u8 mac_idx = rtwvif->mac_idx;
- u8 port_sel = rtwvif->port;
+ struct ieee80211_link_sta *link_sta;
+ u8 mac_idx = rtwvif_link->mac_idx;
+ u8 port_sel = rtwvif_link->port;
u8 sound_dim = 3, t;
u8 *phy_cap;
u32 reg;
@@ -2108,7 +2108,10 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
if (ret)
return ret;
- phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
(phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) {
@@ -2119,11 +2122,11 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
sound_dim = min(sound_dim, t);
}
- if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
- ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
- stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
- t = u32_get_bits(sta->deflink.vht_cap.cap,
+ if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
+ ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
+ stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK);
+ t = u32_get_bits(link_sta->vht_cap.cap,
IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
sound_dim = min(sound_dim, t);
}
@@ -2131,6 +2134,8 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
nc = min(nc, sound_dim);
nr = min(nr, sound_dim);
+ rcu_read_unlock();
+
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL);
@@ -2155,12 +2160,12 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev,
}
static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M);
- u8 mac_idx = rtwvif->mac_idx;
+ struct ieee80211_link_sta *link_sta;
+ u8 mac_idx = rtwvif_link->mac_idx;
int ret;
u32 reg;
@@ -2168,22 +2173,28 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev,
if (ret)
return ret;
- if (sta->deflink.he_cap.has_he) {
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+
+ if (link_sta->he_cap.has_he) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) |
BIT(RTW89_MAC_BF_RRSC_HE_MSC3) |
BIT(RTW89_MAC_BF_RRSC_HE_MSC5));
}
- if (sta->deflink.vht_cap.vht_supported) {
+ if (link_sta->vht_cap.vht_supported) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) |
BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) |
BIT(RTW89_MAC_BF_RRSC_VHT_MSC5));
}
- if (sta->deflink.ht_cap.ht_supported) {
+ if (link_sta->ht_cap.ht_supported) {
rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) |
BIT(RTW89_MAC_BF_RRSC_HT_MSC3) |
BIT(RTW89_MAC_BF_RRSC_HT_MSC5));
}
+ rcu_read_unlock();
+
reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx);
rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL);
rtw89_write32_clr(rtwdev, reg, B_BE_BFMEE_CSI_FORCE_RETE_EN);
@@ -2195,17 +2206,25 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct ieee80211_link_sta *link_sta;
+ bool has_beamformer_cap;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta);
+
+ rcu_read_unlock();
- if (rtw89_sta_has_beamformer_cap(sta)) {
+ if (has_beamformer_cap) {
rtw89_debug(rtwdev, RTW89_DBG_BF,
"initialize bfee for new association\n");
- rtw89_mac_init_bfee_be(rtwdev, rtwvif->mac_idx);
- rtw89_mac_set_csi_para_reg_be(rtwdev, vif, sta);
- rtw89_mac_csi_rrsc_be(rtwdev, vif, sta);
+ rtw89_mac_init_bfee_be(rtwdev, rtwvif_link->mac_idx);
+ rtw89_mac_set_csi_para_reg_be(rtwdev, rtwvif_link, rtwsta_link);
+ rtw89_mac_csi_rrsc_be(rtwdev, rtwvif_link, rtwsta_link);
}
}
@@ -2581,9 +2600,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_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,
+ .fwdl_secure_idmem_share_mode = NULL,
.parse_efuse_map = rtw89_parse_efuse_map_be,
.parse_phycap_map = rtw89_parse_phycap_map_be,
.cnv_efuse_state = rtw89_cnv_efuse_state_be,
+ .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_be,
.cfg_plt = rtw89_mac_cfg_plt_be,
.get_plt_cnt = rtw89_mac_get_plt_cnt_be,
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 02afeb3acce4..f923bec03d41 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -2358,13 +2358,15 @@ static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev)
return 0;
}
-static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev)
+static void rtw89_pci_disable_eq_ax(struct rtw89_dev *rtwdev)
{
u16 g1_oobs, g2_oobs;
u32 backup_aspm;
u32 phy_offset;
+ u16 offset_cal;
u16 oobs_val;
int ret;
+ u8 gen;
if (rtwdev->chip->chip_id != RTL8852C)
return;
@@ -2400,6 +2402,28 @@ static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev)
rtw89_write16_set(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA09 * RAC_MULT,
BAC_OOBS_SEL);
+ /* offset K */
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 :
+ R_RAC_DIRECT_OFFSET_G2;
+
+ rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT,
+ B_PCIE_BIT_RD_SEL);
+ }
+
+ offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G1 +
+ RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK);
+
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 :
+ R_RAC_DIRECT_OFFSET_G2;
+
+ rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT,
+ MANUAL_LVL_MASK, offset_cal);
+ rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT,
+ OFFSET_CAL_MODE);
+ }
+
out:
rtw89_write32(rtwdev, R_AX_PCIE_MIX_CFG_V1, backup_aspm);
}
@@ -2647,9 +2671,10 @@ static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev)
static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_pci_info *info = rtwdev->pci_info;
- u32 ret, check, dma_busy;
u32 dma_busy1 = info->dma_busy1.addr;
u32 dma_busy2 = info->dma_busy2_reg;
+ u32 check, dma_busy;
+ int ret;
check = info->dma_busy1.mask;
@@ -2674,8 +2699,9 @@ static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev)
static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_pci_info *info = rtwdev->pci_info;
- u32 ret, check, dma_busy;
u32 dma_busy3 = info->dma_busy3_reg;
+ u32 check, dma_busy;
+ int ret;
check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY;
@@ -3026,24 +3052,54 @@ static void rtw89_pci_declaim_device(struct rtw89_dev *rtwdev,
pci_disable_device(pdev);
}
-static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
+static bool rtw89_pci_chip_is_manual_dac(struct rtw89_dev *rtwdev)
{
- struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
const struct rtw89_chip_info *chip = rtwdev->chip;
- if (!rtwpci->enable_dac)
- return;
-
switch (chip->chip_id) {
case RTL8852A:
case RTL8852B:
case RTL8851B:
case RTL8852BT:
- break;
+ return true;
default:
- return;
+ return false;
+ }
+}
+
+static bool rtw89_pci_is_dac_compatible_bridge(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+ struct pci_dev *bridge = pci_upstream_bridge(rtwpci->pdev);
+
+ if (!rtw89_pci_chip_is_manual_dac(rtwdev))
+ return true;
+
+ if (!bridge)
+ return false;
+
+ switch (bridge->vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ return true;
+ case PCI_VENDOR_ID_ASMEDIA:
+ if (bridge->device == 0x2806)
+ return true;
+ break;
}
+ return false;
+}
+
+static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+ if (!rtwpci->enable_dac)
+ return;
+
+ if (!rtw89_pci_chip_is_manual_dac(rtwdev))
+ return;
+
rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS);
}
@@ -3061,6 +3117,9 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
goto err;
}
+ if (!rtw89_pci_is_dac_compatible_bridge(rtwdev))
+ goto no_dac;
+
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
if (!ret) {
rtwpci->enable_dac = true;
@@ -3073,6 +3132,7 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
goto err_release_regions;
}
}
+no_dac:
resource_len = pci_resource_len(pdev, bar_id);
rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);
@@ -3724,19 +3784,16 @@ static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev,
pci_free_irq_vectors(pdev);
}
-static u16 gray_code_to_bin(u16 gray_code, u32 bit_num)
+static u16 gray_code_to_bin(u16 gray_code)
{
- u16 bin = 0, gray_bit;
- u32 bit_idx;
+ u16 binary = gray_code;
- for (bit_idx = 0; bit_idx < bit_num; bit_idx++) {
- gray_bit = (gray_code >> bit_idx) & 0x1;
- if (bit_num - bit_idx > 1)
- gray_bit ^= (gray_code >> (bit_idx + 1)) & 0x1;
- bin |= (gray_bit << bit_idx);
+ while (gray_code) {
+ gray_code >>= 1;
+ binary ^= gray_code;
}
- return bin;
+ return binary;
}
static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev)
@@ -3772,7 +3829,7 @@ static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev)
val16 = rtw89_read16_mask(rtwdev,
phy_offset + RAC_ANA1F * RAC_MULT,
FILTER_OUT_EQ_MASK);
- val16 = gray_code_to_bin(val16, hweight16(val16));
+ val16 = gray_code_to_bin(val16);
filter_out_val = rtw89_read16(rtwdev, phy_offset + RAC_ANA24 *
RAC_MULT);
filter_out_val &= ~REG_FILTER_OUT_MASK;
@@ -4154,6 +4211,36 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
return work_done;
}
+static
+void rtw89_check_pci_ssid_quirks(struct rtw89_dev *rtwdev,
+ struct pci_dev *pdev,
+ const struct rtw89_pci_ssid_quirk *ssid_quirks)
+{
+ int i;
+
+ if (!ssid_quirks)
+ return;
+
+ for (i = 0; i < 200; i++, ssid_quirks++) {
+ if (ssid_quirks->vendor == 0 && ssid_quirks->device == 0)
+ break;
+
+ if (ssid_quirks->vendor != pdev->vendor ||
+ ssid_quirks->device != pdev->device ||
+ ssid_quirks->subsystem_vendor != pdev->subsystem_vendor ||
+ ssid_quirks->subsystem_device != pdev->subsystem_device)
+ continue;
+
+ bitmap_or(rtwdev->quirks, rtwdev->quirks, &ssid_quirks->bitmap,
+ NUM_OF_RTW89_QUIRKS);
+ rtwdev->custid = ssid_quirks->custid;
+ break;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_HCI, "quirks=%*ph custid=%d\n",
+ (int)sizeof(rtwdev->quirks), rtwdev->quirks, rtwdev->custid);
+}
+
static int __maybe_unused rtw89_pci_suspend(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
@@ -4188,6 +4275,17 @@ static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev)
RTW89_PCIE_BIT_CFG_RST_MSTATE);
}
+void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume)
+{
+ if (resume)
+ rtw89_pci_cfg_dac(rtwdev);
+
+ rtw89_pci_disable_eq(rtwdev);
+ rtw89_pci_filter_out(rtwdev);
+ rtw89_pci_link_cfg(rtwdev);
+ rtw89_pci_l1ss_cfg(rtwdev);
+}
+
static int __maybe_unused rtw89_pci_resume(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
@@ -4209,11 +4307,8 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev)
B_AX_SEL_REQ_ENTR_L1);
}
rtw89_pci_l2_hci_ldo(rtwdev);
- rtw89_pci_disable_eq(rtwdev);
- rtw89_pci_cfg_dac(rtwdev);
- rtw89_pci_filter_out(rtwdev);
- rtw89_pci_link_cfg(rtwdev);
- rtw89_pci_l1ss_cfg(rtwdev);
+
+ rtw89_pci_basic_cfg(rtwdev, true);
return 0;
}
@@ -4246,6 +4341,8 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
.aspm_set = rtw89_pci_aspm_set_ax,
.clkreq_set = rtw89_pci_clkreq_set_ax,
.l1ss_set = rtw89_pci_l1ss_set_ax,
+
+ .disable_eq = rtw89_pci_disable_eq_ax,
};
EXPORT_SYMBOL(rtw89_pci_gen_ax);
@@ -4318,6 +4415,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rtwdev->hci.cpwm_addr = pci_info->cpwm_addr;
rtw89_check_quirks(rtwdev, info->quirks);
+ rtw89_check_pci_ssid_quirks(rtwdev, pdev, pci_info->ssid_quirks);
SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
@@ -4345,10 +4443,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_clear_resource;
}
- rtw89_pci_disable_eq(rtwdev);
- rtw89_pci_filter_out(rtwdev);
- rtw89_pci_link_cfg(rtwdev);
- rtw89_pci_l1ss_cfg(rtwdev);
+ rtw89_pci_basic_cfg(rtwdev, false);
ret = rtw89_core_napi_init(rtwdev);
if (ret) {
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index 48c3ab735db2..b68e2d82eea9 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -18,11 +18,16 @@
#define BAC_OOBS_SEL BIT(4)
#define RAC_ANA0A 0x0A
#define B_BAC_EQ_SEL BIT(5)
+#define RAC_ANA0B 0x0B
+#define MANUAL_LVL_MASK GENMASK(8, 5)
#define RAC_ANA0C 0x0C
#define B_PCIE_BIT_PSAVE BIT(15)
#define RAC_ANA0D 0x0D
+#define OFFSET_CAL_MODE BIT(13)
#define BAC_RX_TEST_EN BIT(6)
#define RAC_ANA10 0x10
+#define ADDR_SEL_MASK GENMASK(9, 4)
+#define ADDR_SEL_VAL 0x3C
#define ADDR_SEL_PINOUT_DIS_VAL 0x3C4
#define B_PCIE_BIT_PINOUT_DIS BIT(3)
#define RAC_REG_REV2 0x1B
@@ -38,6 +43,7 @@
#define RAC_ANA1E_G2_VAL 0x6EEA
#define RAC_ANA1F 0x1F
#define OOBS_LEVEL_MASK GENMASK(12, 8)
+#define OFFSET_CAL_MASK GENMASK(7, 4)
#define RAC_ANA24 0x24
#define B_AX_DEGLITCH GENMASK(11, 8)
#define RAC_ANA26 0x26
@@ -134,6 +140,11 @@
#define REG_FILTER_OUT_MASK GENMASK(6, 2)
#define RAC_MULT 2
+#define R_RAC_DIRECT_OFFSET_BE_LANE0_G1 0x3800
+#define R_RAC_DIRECT_OFFSET_BE_LANE1_G1 0x3880
+#define R_RAC_DIRECT_OFFSET_BE_LANE0_G2 0x3900
+#define R_RAC_DIRECT_OFFSET_BE_LANE1_G2 0x3980
+
#define RTW89_PCI_WR_RETRY_CNT 20
/* Interrupts */
@@ -299,6 +310,7 @@
#define B_BE_L1SS_TIMEOUT_CTRL BIT(18)
#define B_BE_ASPM_CTRL_L1 BIT(17)
#define B_BE_ASPM_CTRL_L0 BIT(16)
+#define B_BE_RTK_ASPM_CTRL_MASK GENMASK(17, 16)
#define B_BE_XFER_PENDING_FW BIT(11)
#define B_BE_XFER_PENDING BIT(10)
#define B_BE_REQ_EXIT_L1 BIT(9)
@@ -1276,6 +1288,21 @@ struct rtw89_pci_gen_def {
void (*aspm_set)(struct rtw89_dev *rtwdev, bool enable);
void (*clkreq_set)(struct rtw89_dev *rtwdev, bool enable);
void (*l1ss_set)(struct rtw89_dev *rtwdev, bool enable);
+
+ void (*disable_eq)(struct rtw89_dev *rtwdev);
+};
+
+#define RTW89_PCI_SSID(v, d, ssv, ssd, cust) \
+ .vendor = v, .device = d, .subsystem_vendor = ssv, .subsystem_device = ssd, \
+ .custid = RTW89_CUSTID_ ##cust
+
+struct rtw89_pci_ssid_quirk {
+ unsigned short vendor;
+ unsigned short device;
+ unsigned short subsystem_vendor;
+ unsigned short subsystem_device;
+ enum rtw89_custid custid;
+ unsigned long bitmap; /* bitmap of rtw89_quirks */
};
struct rtw89_pci_info {
@@ -1331,6 +1358,8 @@ struct rtw89_pci_info {
void (*recognize_intrs)(struct rtw89_dev *rtwdev,
struct rtw89_pci *rtwpci,
struct rtw89_pci_isrs *isrs);
+
+ const struct rtw89_pci_ssid_quirk *ssid_quirks;
};
struct rtw89_pci_tx_data {
@@ -1600,6 +1629,7 @@ 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_basic_cfg(struct rtw89_dev *rtwdev, bool resume);
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);
@@ -1766,4 +1796,13 @@ static inline int rtw89_pci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev)
return gen_def->poll_txdma_ch_idle(rtwdev);
}
+
+static inline void rtw89_pci_disable_eq(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->disable_eq(rtwdev);
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c
index 7cc328222965..34154506f5d4 100644
--- a/drivers/net/wireless/realtek/rtw89/pci_be.c
+++ b/drivers/net/wireless/realtek/rtw89/pci_be.c
@@ -550,6 +550,79 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev)
return 0;
}
+static void rtw89_pci_disable_eq_be(struct rtw89_dev *rtwdev)
+{
+ u32 backup_aspm, phy_offset;
+ u16 oobs_val, offset_cal;
+ u16 g1_oobs, g2_oobs;
+ u8 gen;
+
+ if (rtwdev->chip->chip_id != RTL8922A)
+ return;
+
+ g1_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 +
+ RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL);
+ g2_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G2 +
+ RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL);
+ if (g1_oobs && g2_oobs)
+ return;
+
+ backup_aspm = rtw89_read32(rtwdev, R_BE_PCIE_MIX_CFG);
+ rtw89_write32_clr(rtwdev, R_BE_PCIE_MIX_CFG, B_BE_RTK_ASPM_CTRL_MASK);
+
+ /* offset K */
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 :
+ R_RAC_DIRECT_OFFSET_BE_LANE0_G2;
+
+ rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT,
+ B_PCIE_BIT_RD_SEL);
+ }
+
+ offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 +
+ RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK);
+
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 :
+ R_RAC_DIRECT_OFFSET_BE_LANE0_G2;
+
+ rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT,
+ MANUAL_LVL_MASK, offset_cal);
+ rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT,
+ OFFSET_CAL_MODE);
+ }
+
+ /* OOBS */
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 :
+ R_RAC_DIRECT_OFFSET_BE_LANE0_G2;
+
+ rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT,
+ BAC_RX_TEST_EN);
+ rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT,
+ ADDR_SEL_MASK, ADDR_SEL_VAL);
+ rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT,
+ B_PCIE_BIT_PINOUT_DIS);
+ rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT,
+ B_PCIE_BIT_RD_SEL);
+ }
+
+ oobs_val = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 +
+ RAC_ANA1F * RAC_MULT, OOBS_LEVEL_MASK);
+
+ for (gen = 1; gen <= 2; gen++) {
+ phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 :
+ R_RAC_DIRECT_OFFSET_BE_LANE0_G2;
+
+ rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA03 * RAC_MULT,
+ OOBS_SEN_MASK, oobs_val);
+ rtw89_write16_set(rtwdev, phy_offset + RAC_ANA09 * RAC_MULT,
+ BAC_OOBS_SEL);
+ }
+
+ rtw89_write32(rtwdev, R_BE_PCIE_MIX_CFG, backup_aspm);
+}
+
static int __maybe_unused rtw89_pci_suspend_be(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
@@ -584,6 +657,8 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev)
rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR);
+ rtw89_pci_basic_cfg(rtwdev, true);
+
return 0;
}
@@ -614,5 +689,7 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = {
.aspm_set = rtw89_pci_aspm_set_be,
.clkreq_set = rtw89_pci_clkreq_set_be,
.l1ss_set = rtw89_pci_l1ss_set_be,
+
+ .disable_eq = rtw89_pci_disable_eq_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 c7165e757842..f24aca663cf0 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -75,12 +75,12 @@ static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap)
return ra_mask;
}
-static u64 get_he_ra_mask(struct ieee80211_sta *sta)
+static u64 get_he_ra_mask(struct ieee80211_link_sta *link_sta)
{
- struct ieee80211_sta_he_cap cap = sta->deflink.he_cap;
+ struct ieee80211_sta_he_cap cap = link_sta->he_cap;
u16 mcs_map;
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
if (cap.he_cap_elem.phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
@@ -118,14 +118,14 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss)
return mask;
}
-static u64 get_eht_ra_mask(struct ieee80211_sta *sta)
+static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta)
{
- struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap;
+ struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz;
struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss;
- u8 *he_phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info;
+ u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_320:
mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._320;
/* MCS 9, 11, 13 */
@@ -195,15 +195,16 @@ static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak)
return ra_mask;
}
-static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
const struct rtw89_chan *chan)
{
- struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
- struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
+ struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask;
enum nl80211_band band;
u64 cfg_mask;
- if (!rtwsta->use_cfg_mask)
+ if (!rtwsta_link->use_cfg_mask)
return -1;
switch (chan->band_type) {
@@ -227,17 +228,17 @@ static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtw
return -1;
}
- if (sta->deflink.he_cap.has_he) {
+ if (link_sta->he_cap.has_he) {
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0],
RA_MASK_HE_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1],
RA_MASK_HE_2SS_RATES);
- } else if (sta->deflink.vht_cap.vht_supported) {
+ } else if (link_sta->vht_cap.vht_supported) {
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0],
RA_MASK_VHT_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1],
RA_MASK_VHT_2SS_RATES);
- } else if (sta->deflink.ht_cap.ht_supported) {
+ } else if (link_sta->ht_cap.ht_supported) {
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0],
RA_MASK_HT_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1],
@@ -261,17 +262,17 @@ rtw89_ra_mask_eht_rates[4] = {RA_MASK_EHT_1SS_RATES, RA_MASK_EHT_2SS_RATES,
RA_MASK_EHT_3SS_RATES, RA_MASK_EHT_4SS_RATES};
static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta,
+ struct rtw89_sta_link *rtwsta_link,
const struct rtw89_chan *chan,
bool *fix_giltf_en, u8 *fix_giltf)
{
- struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
+ struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask;
u8 band = chan->band_type;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
u8 he_gi = mask->control[nl_band].he_gi;
u8 he_ltf = mask->control[nl_band].he_ltf;
- if (!rtwsta->use_cfg_mask)
+ if (!rtwsta_link->use_cfg_mask)
return;
if (he_ltf == 2 && he_gi == 2) {
@@ -295,17 +296,17 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
}
static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, bool csi)
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ bool p2p, bool csi)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
- struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
- struct rtw89_ra_info *ra = &rtwsta->ra;
+ struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern;
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif);
+ rtwvif_link->chanctx_idx);
const u64 *high_rate_masks = rtw89_ra_mask_ht_rates;
- u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi);
+ u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi);
u64 ra_mask = 0;
u64 ra_mask_bak;
u8 mode = 0;
@@ -320,65 +321,65 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
memset(ra, 0, sizeof(*ra));
/* Set the ra mask from sta's capability */
- if (sta->deflink.eht_cap.has_eht) {
+ if (link_sta->eht_cap.has_eht) {
mode |= RTW89_RA_MODE_EHT;
- ra_mask |= get_eht_ra_mask(sta);
+ ra_mask |= get_eht_ra_mask(link_sta);
high_rate_masks = rtw89_ra_mask_eht_rates;
- } else if (sta->deflink.he_cap.has_he) {
+ } else if (link_sta->he_cap.has_he) {
mode |= RTW89_RA_MODE_HE;
csi_mode = RTW89_RA_RPT_MODE_HE;
- ra_mask |= get_he_ra_mask(sta);
+ ra_mask |= get_he_ra_mask(link_sta);
high_rate_masks = rtw89_ra_mask_he_rates;
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[2] &
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
stbc_en = 1;
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
ldpc_en = 1;
- rtw89_phy_ra_gi_ltf(rtwdev, rtwsta, chan, &fix_giltf_en, &fix_giltf);
- } else if (sta->deflink.vht_cap.vht_supported) {
- u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
+ rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, chan, &fix_giltf_en, &fix_giltf);
+ } else if (link_sta->vht_cap.vht_supported) {
+ u16 mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map);
mode |= RTW89_RA_MODE_VHT;
csi_mode = RTW89_RA_RPT_MODE_VHT;
/* MCS9 (non-20MHz), MCS8, MCS7 */
- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
+ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
ra_mask |= get_mcs_ra_mask(mcs_map, 8, 1);
else
ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1);
high_rate_masks = rtw89_ra_mask_vht_rates;
- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
+ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
stbc_en = 1;
- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
+ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
ldpc_en = 1;
- } else if (sta->deflink.ht_cap.ht_supported) {
+ } else if (link_sta->ht_cap.ht_supported) {
mode |= RTW89_RA_MODE_HT;
csi_mode = RTW89_RA_RPT_MODE_HT;
- ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
- ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
- ((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
- ((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
+ ra_mask |= ((u64)link_sta->ht_cap.mcs.rx_mask[3] << 48) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[2] << 36) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[1] << 24) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[0] << 12);
high_rate_masks = rtw89_ra_mask_ht_rates;
- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
stbc_en = 1;
- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
+ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
ldpc_en = 1;
}
switch (chan->band_type) {
case RTW89_BAND_2G:
- ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ];
- if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf)
+ ra_mask |= link_sta->supp_rates[NL80211_BAND_2GHZ];
+ if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xf)
mode |= RTW89_RA_MODE_CCK;
- if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0)
+ if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xff0)
mode |= RTW89_RA_MODE_OFDM;
break;
case RTW89_BAND_5G:
- ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4;
+ ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_5GHZ] << 4;
mode |= RTW89_RA_MODE_OFDM;
break;
case RTW89_BAND_6G:
- ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4;
+ ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_6GHZ] << 4;
mode |= RTW89_RA_MODE_OFDM;
break;
default:
@@ -405,48 +406,48 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0);
ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak);
- ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan);
+ ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
bw_mode = RTW89_CHANNEL_WIDTH_160;
- sgi = sta->deflink.vht_cap.vht_supported &&
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
+ sgi = link_sta->vht_cap.vht_supported &&
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
break;
case IEEE80211_STA_RX_BW_80:
bw_mode = RTW89_CHANNEL_WIDTH_80;
- sgi = sta->deflink.vht_cap.vht_supported &&
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
+ sgi = link_sta->vht_cap.vht_supported &&
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
break;
case IEEE80211_STA_RX_BW_40:
bw_mode = RTW89_CHANNEL_WIDTH_40;
- sgi = sta->deflink.ht_cap.ht_supported &&
- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
+ sgi = link_sta->ht_cap.ht_supported &&
+ (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
break;
default:
bw_mode = RTW89_CHANNEL_WIDTH_20;
- sgi = sta->deflink.ht_cap.ht_supported &&
- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
+ sgi = link_sta->ht_cap.ht_supported &&
+ (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
break;
}
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[3] &
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM)
ra->dcm_cap = 1;
- if (rate_pattern->enable && !vif->p2p) {
- ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan);
+ if (rate_pattern->enable && !p2p) {
+ ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
ra_mask &= rate_pattern->ra_mask;
mode = rate_pattern->ra_mode;
}
ra->bw_cap = bw_mode;
- ra->er_cap = rtwsta->er_cap;
+ ra->er_cap = rtwsta_link->er_cap;
ra->mode_ctrl = mode;
- ra->macid = rtwsta->mac_id;
+ ra->macid = rtwsta_link->mac_id;
ra->stbc_cap = stbc_en;
ra->ldpc_cap = ldpc_en;
- ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
+ ra->ss_num = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
ra->en_sgi = sgi;
ra->ra_mask = ra_mask;
ra->fix_giltf_en = fix_giltf_en;
@@ -458,20 +459,29 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
ra->fixed_csi_rate_en = false;
ra->ra_csi_rate_en = true;
ra->cr_tbl_sel = false;
- ra->band_num = rtwvif->phy_idx;
+ ra->band_num = rtwvif_link->phy_idx;
ra->csi_bw = bw_mode;
ra->csi_gi_ltf = RTW89_GILTF_LGI_4XHE32;
ra->csi_mcs_ss_idx = 5;
ra->csi_mode = csi_mode;
}
-void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
- u32 changed)
+static void __rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ u32 changed)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_ra_info *ra = &rtwsta->ra;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
+ struct ieee80211_link_sta *link_sta;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
+ link_sta, vif->p2p, false);
- rtw89_phy_ra_sta_update(rtwdev, sta, false);
+ rcu_read_unlock();
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED)
ra->upd_mask = 1;
@@ -489,6 +499,20 @@ void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta
rtw89_fw_h2c_ra(rtwdev, ra, false);
}
+void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
+ u32 changed)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ __rtw89_phy_ra_update_sta(rtwdev, rtwvif_link, rtwsta_link, changed);
+ }
+}
+
static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
u16 rate_base, u64 ra_mask, u8 ra_mode,
u32 rate_ctrl, u32 ctrl_skip, bool force)
@@ -523,15 +547,15 @@ static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
[RTW89_CHIP_BE] = RTW89_HW_RATE_V1_ ## rate, \
}
-void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- const struct cfg80211_bitrate_mask *mask)
+static
+void __rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ const struct cfg80211_bitrate_mask *mask)
{
struct ieee80211_supported_band *sband;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_phy_rate_pattern next_pattern = {0};
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
static const u16 hw_rate_he[][RTW89_CHIP_GEN_NUM] = {
RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS1_MCS0),
RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS2_MCS0),
@@ -600,7 +624,7 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
if (!next_pattern.enable)
goto out;
- rtwvif->rate_pattern = next_pattern;
+ rtwvif_link->rate_pattern = next_pattern;
rtw89_debug(rtwdev, RTW89_DBG_RA,
"configure pattern: rate 0x%x, mask 0x%llx, mode 0x%x\n",
next_pattern.rate,
@@ -609,10 +633,22 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
return;
out:
- rtwvif->rate_pattern.enable = false;
+ rtwvif_link->rate_pattern.enable = false;
rtw89_debug(rtwdev, RTW89_DBG_RA, "unset rate pattern\n");
}
+void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ __rtw89_phy_rate_pattern_vif(rtwdev, rtwvif_link, mask);
+}
+
static void rtw89_phy_ra_update_sta_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_dev *rtwdev = (struct rtw89_dev *)data;
@@ -627,14 +663,24 @@ void rtw89_phy_ra_update(struct rtw89_dev *rtwdev)
rtwdev);
}
-void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta)
+void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_ra_info *ra = &rtwsta->ra;
- u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
- bool csi = rtw89_sta_has_beamformer_cap(sta);
+ struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
+ u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
+ struct ieee80211_link_sta *link_sta;
+ bool csi;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ csi = rtw89_sta_has_beamformer_cap(link_sta);
- rtw89_phy_ra_sta_update(rtwdev, sta, csi);
+ rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
+ link_sta, vif->p2p, csi);
+
+ rcu_read_unlock();
if (rssi > 40)
ra->init_rate_lv = 1;
@@ -1068,14 +1114,21 @@ static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev)
return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1;
}
-static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev,
- enum rtw89_phy_idx phy_idx)
+static void __rtw89_phy_bb_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
chip->ops->bb_reset(rtwdev, phy_idx);
}
+static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev)
+{
+ __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_1);
+}
+
static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev,
const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path,
@@ -1621,13 +1674,15 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
if (rtwdev->dbcc_en)
rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg,
(void *)RTW89_PHY_1);
- rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
+
+ rtw89_chip_init_txpwr_unit(rtwdev);
bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table;
if (bb_gain_table)
rtw89_phy_init_reg(rtwdev, bb_gain_table,
chip->phy_def->config_bb_gain, NULL);
- rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
+
+ rtw89_phy_bb_reset(rtwdev);
}
static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev)
@@ -1747,6 +1802,24 @@ void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
}
EXPORT_SYMBOL(rtw89_phy_write32_idx);
+void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
+ addr += rtw89_phy0_phy1_offset(rtwdev, addr);
+ rtw89_phy_write32_set(rtwdev, addr, bits);
+}
+EXPORT_SYMBOL(rtw89_phy_write32_idx_set);
+
+void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
+ addr += rtw89_phy0_phy1_offset(rtwdev, addr);
+ rtw89_phy_write32_clr(rtwdev, addr, bits);
+}
+EXPORT_SYMBOL(rtw89_phy_write32_idx_clr);
+
u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
enum rtw89_phy_idx phy_idx)
{
@@ -2553,14 +2626,14 @@ struct rtw89_phy_iter_ra_data {
struct sk_buff *c2h;
};
-static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
+static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ struct rtw89_phy_iter_ra_data *ra_data)
{
- struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
struct rtw89_dev *rtwdev = ra_data->rtwdev;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
const struct rtw89_c2h_ra_rpt *c2h =
(const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data;
- struct rtw89_ra_report *ra_report = &rtwsta->ra_report;
+ struct rtw89_ra_report *ra_report = &rtwsta_link->ra_report;
const struct rtw89_chip_info *chip = rtwdev->chip;
bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
u8 mode, rate, bw, giltf, mac_id;
@@ -2570,7 +2643,7 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
u8 t;
mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID);
- if (mac_id != rtwsta->mac_id)
+ if (mac_id != rtwsta_link->mac_id)
return;
rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS);
@@ -2661,8 +2734,26 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
ra_report->might_fallback_legacy = mcs <= 2;
- sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
- rtwsta->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1;
+ link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
+ rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1;
+}
+
+static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ rcu_read_lock();
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data);
+ }
+
+ rcu_read_unlock();
}
static void
@@ -2692,9 +2783,85 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
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_tssi_rpt_log *tssi;
struct rtw89_c2h_rf_dpk_rpt_log *dpk;
+ struct rtw89_c2h_rf_iqk_rpt_log *iqk;
+ int i, j, k;
switch (func) {
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK:
+ if (len != sizeof(*iqk))
+ goto out;
+
+ iqk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_iqk_init = %x\n", iqk->is_iqk_init);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_reload = %x\n", iqk->is_reload);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_nbiqk = %x\n", iqk->is_nbiqk);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->txiqk_en = %x\n", iqk->txiqk_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rxiqk_en = %x\n", iqk->rxiqk_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->lok_en = %x\n", iqk->lok_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_xym_en = %x\n", iqk->iqk_xym_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_sram_en = %x\n", iqk->iqk_sram_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_fft_en = %x\n", iqk->iqk_fft_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_fw_iqk = %x\n", iqk->is_fw_iqk);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_iqk_enable = %x\n", iqk->is_iqk_enable);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_cfir_en = %x\n", iqk->iqk_cfir_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->thermal_rek_en = %x\n", iqk->thermal_rek_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->version = %x\n", iqk->version);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->phy = %x\n", iqk->phy);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->fwk_status = %x\n", iqk->fwk_status);
+
+ for (i = 0; i < 2; i++) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] ======== Path %x ========\n", i);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_band[%d] = %x\n",
+ i, iqk->iqk_band[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_ch[%d] = %x\n",
+ i, iqk->iqk_ch[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_bw[%d] = %x\n",
+ i, iqk->iqk_bw[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_idac[%d] = %x\n",
+ i, le32_to_cpu(iqk->lok_idac[i]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_vbuf[%d] = %x\n",
+ i, le32_to_cpu(iqk->lok_vbuf[i]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_tx_fail[%d] = %x\n",
+ i, iqk->iqk_tx_fail[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_rx_fail[%d] = %x\n",
+ i, iqk->iqk_rx_fail[i]);
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rftxgain[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rftxgain[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->tx_xym[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->tx_xym[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rfrxgain[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rfrxgain[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rx_xym[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rx_xym[i][j]));
+ }
+ return;
case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
if (len != sizeof(*dpk))
goto out;
@@ -2716,8 +2883,23 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
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]FWDACK SUMMARY!!!!!\n");
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]FWDACK ver = 0x%x, FWDACK rpt_ver = 0x%x, driver rpt_ver = 0x%x\n",
+ dack->fwdack_ver, dack->fwdack_info_ver, 0x2);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]timeout code = [0x%x 0x%x 0x%x 0x%x 0x%x]\n",
+ dack->addck_timeout, dack->cdack_timeout, dack->dadck_timeout,
+ dack->adgaink_timeout, dack->msbk_timeout);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]DACK fail = 0x%x\n", dack->dack_fail);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]S0 WBADCK = [0x%x]\n", dack->wbdck_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]S1 WBADCK = [0x%x]\n", dack->wbdck_d[1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]DRCK = [0x%x]\n", dack->rck_d);
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",
@@ -2728,13 +2910,17 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
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]);
+ ((u32)dack->addck2_hd[0][0][0] << 8) | dack->addck2_ld[0][0][0],
+ ((u32)dack->addck2_hd[0][0][1] << 8) | dack->addck2_ld[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]);
+ ((u32)dack->addck2_hd[0][1][0] << 8) | dack->addck2_ld[0][1][0],
+ ((u32)dack->addck2_hd[0][1][1] << 8) | dack->addck2_ld[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]);
+ ((u32)dack->addck2_hd[1][0][0] << 8) | dack->addck2_ld[1][0][0],
+ ((u32)dack->addck2_hd[1][0][1] << 8) | dack->addck2_ld[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]);
+ ((u32)dack->addck2_hd[1][1][0] << 8) | dack->addck2_ld[1][1][0],
+ ((u32)dack->addck2_hd[1][1][1] << 8) | dack->addck2_ld[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]);
@@ -2747,18 +2933,29 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
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]);
+ ((u32)dack->biask_hd[0][0] << 8) | dack->biask_ld[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]);
+ ((u32)dack->biask_hd[1][0] << 8) | dack->biask_ld[1][0]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[0][0][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[0][1][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[1][0][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[1][1][i]);
return;
case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
if (len != sizeof(*rxdck))
@@ -2770,6 +2967,39 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch,
rxdck->timeout);
return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI:
+ if (len != sizeof(*tssi))
+ goto out;
+
+ tssi = content;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 4; k++) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw_h[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power_cw_h[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw_l[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power_cw_l[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw[%d][%d][%d]=%d\n",
+ i, j, k,
+ (tssi->alignment_power_cw_h[i][j][k] << 8) +
+ tssi->alignment_power_cw_l[i][j][k]);
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] tssi_alimk_state[%d][%d]=%d\n",
+ i, j, tssi->tssi_alimk_state[i][j]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] default_txagc_offset[%d]=%d\n",
+ j, tssi->default_txagc_offset[0][j]);
+ }
+ }
+ return;
case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
if (len != sizeof(*txgapk))
goto out;
@@ -3171,13 +3401,13 @@ EXPORT_SYMBOL(rtw89_phy_rfk_dack_and_wait);
int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx,
const struct rtw89_chan *chan,
- unsigned int ms)
+ bool is_chl_k, unsigned int ms)
{
int ret;
rtw89_phy_rfk_report_prep(rtwdev);
- ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan);
+ ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan, is_chl_k);
if (ret)
return ret;
@@ -4290,33 +4520,33 @@ void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val,
cfo->packet_count++;
}
-void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
- rtwvif->chanctx_idx);
+ rtwvif_link->chanctx_idx);
struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
if (!chip->ul_tb_waveform_ctrl)
return;
- rtwvif->def_tri_idx =
+ rtwvif_link->def_tri_idx =
rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG);
if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV)
- rtwvif->dyn_tb_bedge_en = false;
+ rtwvif_link->dyn_tb_bedge_en = false;
else if (chan->band_type >= RTW89_BAND_5G &&
chan->band_width >= RTW89_CHANNEL_WIDTH_40)
- rtwvif->dyn_tb_bedge_en = true;
+ rtwvif_link->dyn_tb_bedge_en = true;
else
- rtwvif->dyn_tb_bedge_en = false;
+ rtwvif_link->dyn_tb_bedge_en = false;
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n",
- ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx);
+ ul_tb_info->def_if_bandedge, rtwvif_link->def_tri_idx);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n",
- rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en);
+ rtwvif_link->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en);
}
struct rtw89_phy_ul_tb_check_data {
@@ -4338,7 +4568,7 @@ struct rtw89_phy_power_diff {
};
static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
static const struct rtw89_phy_power_diff table[2] = {
{0x0, 0x0, 0x0, 0x0, 0xf4, 0x3, 0x3},
@@ -4350,13 +4580,13 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev,
if (!rtwdev->chip->ul_tb_pwr_diff)
return;
- if (rtwvif->pwr_diff_en == rtwvif->pre_pwr_diff_en) {
- rtwvif->pwr_diff_en = false;
+ if (rtwvif_link->pwr_diff_en == rtwvif_link->pre_pwr_diff_en) {
+ rtwvif_link->pwr_diff_en = false;
return;
}
- rtwvif->pre_pwr_diff_en = rtwvif->pwr_diff_en;
- param = &table[rtwvif->pwr_diff_en];
+ rtwvif_link->pre_pwr_diff_en = rtwvif_link->pwr_diff_en;
+ param = &table[rtwvif_link->pwr_diff_en];
rtw89_phy_write32_mask(rtwdev, R_Q_MATRIX_00, B_Q_MATRIX_00_REAL,
param->q_00);
@@ -4365,32 +4595,32 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev,
rtw89_phy_write32_mask(rtwdev, R_CUSTOMIZE_Q_MATRIX,
B_CUSTOMIZE_Q_MATRIX_EN, param->q_matrix_en);
- reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_NORM_BW160,
param->ultb_1t_norm_160);
- reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_NORM_BW160,
param->ultb_2t_norm_160);
- reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM1_NORM_1STS,
param->com1_norm_1sts);
- reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif->mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM2_RESP_1STS_PATH,
param->com2_resp_1sts_path);
}
static
void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct rtw89_phy_ul_tb_check_data *ul_tb_data)
{
struct rtw89_traffic_stats *stats = &rtwdev->stats;
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
return;
if (!vif->cfg.assoc)
@@ -4403,11 +4633,11 @@ void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev,
ul_tb_data->low_tf_client = true;
ul_tb_data->valid = true;
- ul_tb_data->def_tri_idx = rtwvif->def_tri_idx;
- ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en;
+ ul_tb_data->def_tri_idx = rtwvif_link->def_tri_idx;
+ ul_tb_data->dyn_tb_bedge_en = rtwvif_link->dyn_tb_bedge_en;
}
- rtw89_phy_ofdma_power_diff(rtwdev, rtwvif);
+ rtw89_phy_ofdma_power_diff(rtwdev, rtwvif_link);
}
static void rtw89_phy_ul_tb_waveform_ctrl(struct rtw89_dev *rtwdev,
@@ -4453,7 +4683,9 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_phy_ul_tb_check_data ul_tb_data = {};
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
if (!chip->ul_tb_waveform_ctrl && !chip->ul_tb_pwr_diff)
return;
@@ -4462,7 +4694,8 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
return;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif_link, &ul_tb_data);
if (!ul_tb_data.valid)
return;
@@ -4603,11 +4836,36 @@ static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev)
rtw89_phy_antdiv_reg_init(rtwdev);
}
+static void rtw89_phy_thermal_protect(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 th_max = phystat->last_thermal_max;
+ u8 lv = hal->thermal_prot_lv;
+
+ if (!hal->thermal_prot_th ||
+ (hal->disabled_dm_bitmap & BIT(RTW89_DM_THERMAL_PROTECT)))
+ return;
+
+ if (th_max > hal->thermal_prot_th && lv < RTW89_THERMAL_PROT_LV_MAX)
+ lv++;
+ else if (th_max < hal->thermal_prot_th - 2 && lv > 0)
+ lv--;
+ else
+ return;
+
+ hal->thermal_prot_lv = lv;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "thermal protection lv=%d\n", lv);
+
+ rtw89_fw_h2c_tx_duty(rtwdev, hal->thermal_prot_lv);
+}
+
static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ u8 th, th_max = 0;
int i;
- u8 th;
for (i = 0; i < rtwdev->chip->rf_path_num; i++) {
th = rtw89_chip_get_thermal(rtwdev, i);
@@ -4617,7 +4875,11 @@ static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev)
rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
"path(%d) thermal cur=%u avg=%ld", i, th,
ewma_thermal_read(&phystat->avg_thermal[i]));
+
+ th_max = max(th_max, th);
}
+
+ phystat->last_thermal_max = th_max;
}
struct rtw89_phy_iter_rssi_data {
@@ -4626,30 +4888,42 @@ struct rtw89_phy_iter_rssi_data {
bool rssi_changed;
};
-static void rtw89_phy_stat_rssi_update_iter(void *data,
- struct ieee80211_sta *sta)
+static
+void __rtw89_phy_stat_rssi_update_iter(struct rtw89_sta_link *rtwsta_link,
+ struct rtw89_phy_iter_rssi_data *rssi_data)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_phy_iter_rssi_data *rssi_data =
- (struct rtw89_phy_iter_rssi_data *)data;
struct rtw89_phy_ch_info *ch_info = rssi_data->ch_info;
unsigned long rssi_curr;
- rssi_curr = ewma_rssi_read(&rtwsta->avg_rssi);
+ rssi_curr = ewma_rssi_read(&rtwsta_link->avg_rssi);
if (rssi_curr < ch_info->rssi_min) {
ch_info->rssi_min = rssi_curr;
- ch_info->rssi_min_macid = rtwsta->mac_id;
+ ch_info->rssi_min_macid = rtwsta_link->mac_id;
}
- if (rtwsta->prev_rssi == 0) {
- rtwsta->prev_rssi = rssi_curr;
- } else if (abs((int)rtwsta->prev_rssi - (int)rssi_curr) > (3 << RSSI_FACTOR)) {
- rtwsta->prev_rssi = rssi_curr;
+ if (rtwsta_link->prev_rssi == 0) {
+ rtwsta_link->prev_rssi = rssi_curr;
+ } else if (abs((int)rtwsta_link->prev_rssi - (int)rssi_curr) >
+ (3 << RSSI_FACTOR)) {
+ rtwsta_link->prev_rssi = rssi_curr;
rssi_data->rssi_changed = true;
}
}
+static void rtw89_phy_stat_rssi_update_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_phy_iter_rssi_data *rssi_data =
+ (struct rtw89_phy_iter_rssi_data *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
+ __rtw89_phy_stat_rssi_update_iter(rtwsta_link, rssi_data);
+}
+
static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_iter_rssi_data rssi_data = {0};
@@ -4676,6 +4950,10 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat));
+
+ ewma_rssi_init(&phystat->bcn_rssi);
+
+ rtwdev->hal.thermal_prot_lv = 0;
}
void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
@@ -4683,6 +4961,7 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
rtw89_phy_stat_thermal_update(rtwdev);
+ rtw89_phy_thermal_protect(rtwdev);
rtw89_phy_stat_rssi_update(rtwdev);
phystat->last_pkt_stat = phystat->cur_pkt_stat;
@@ -5188,7 +5467,8 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page)
}
static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev,
- enum rtw89_phy_status_bitmap ie_page)
+ enum rtw89_phy_status_bitmap ie_page,
+ enum rtw89_phy_idx phy_idx)
{
u32 addr;
@@ -5197,12 +5477,12 @@ static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev,
addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
- return rtw89_phy_read32(rtwdev, addr);
+ return rtw89_phy_read32_idx(rtwdev, addr, MASKDWORD, phy_idx);
}
static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev,
enum rtw89_phy_status_bitmap ie_page,
- u32 val)
+ u32 val, enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 addr;
@@ -5214,22 +5494,22 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev,
val &= B_PHY_STS_BITMAP_MSK_52A;
addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
- rtw89_phy_write32(rtwdev, addr, val);
+ rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx);
}
static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev,
enum rtw89_phy_status_bitmap bitmap,
enum rtw89_phy_status_ie_type ie,
- bool enable)
+ bool enable, enum rtw89_phy_idx phy_idx)
{
- u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap);
+ u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap, phy_idx);
if (enable)
val |= BIT(ie);
else
val &= ~BIT(ie);
- rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val);
+ rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val, phy_idx);
}
static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev,
@@ -5240,44 +5520,52 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev,
const struct rtw89_physts_regs *physts = phy->physts;
if (enable) {
- rtw89_phy_write32_clr(rtwdev, physts->setting_addr,
- physts->dis_trigger_fail_mask);
- rtw89_phy_write32_clr(rtwdev, physts->setting_addr,
- physts->dis_trigger_brk_mask);
+ rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr,
+ physts->dis_trigger_fail_mask, phy_idx);
+ rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr,
+ physts->dis_trigger_brk_mask, phy_idx);
} else {
- rtw89_phy_write32_set(rtwdev, physts->setting_addr,
- physts->dis_trigger_fail_mask);
- rtw89_phy_write32_set(rtwdev, physts->setting_addr,
- physts->dis_trigger_brk_mask);
+ rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr,
+ physts->dis_trigger_fail_mask, phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr,
+ physts->dis_trigger_brk_mask, phy_idx);
}
}
-static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev)
+static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
u8 i;
- rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0);
+ rtw89_physts_enable_fail_report(rtwdev, false, phy_idx);
for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) {
if (i >= RTW89_CCK_PKT)
rtw89_physts_enable_ie_bitmap(rtwdev, i,
RTW89_PHYSTS_IE09_FTR_0,
- true);
+ true, phy_idx);
if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) ||
(i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT))
continue;
rtw89_physts_enable_ie_bitmap(rtwdev, i,
RTW89_PHYSTS_IE24_OFDM_TD_PATH_A,
- true);
+ true, phy_idx);
}
rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT,
- RTW89_PHYSTS_IE13_DL_MU_DEF, true);
+ RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx);
rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT,
- RTW89_PHYSTS_IE13_DL_MU_DEF, true);
+ RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx);
/* force IE01 for channel index, only channel field is valid */
rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT,
- RTW89_PHYSTS_IE01_CMN_OFDM, true);
+ RTW89_PHYSTS_IE01_CMN_OFDM, true, phy_idx);
+}
+
+static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev)
+{
+ __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_1);
}
static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type)
@@ -5753,26 +6041,15 @@ void rtw89_phy_dig(struct rtw89_dev *rtwdev)
rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false);
}
-static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta)
+static void __rtw89_phy_tx_path_div_sta_iter(struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_dev *rtwdev = rtwsta->rtwdev;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_hal *hal = &rtwdev->hal;
- bool *done = data;
u8 rssi_a, rssi_b;
u32 candidate;
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || sta->tdls)
- return;
-
- if (*done)
- return;
-
- *done = true;
-
- rssi_a = ewma_rssi_read(&rtwsta->rssi[RF_PATH_A]);
- rssi_b = ewma_rssi_read(&rtwsta->rssi[RF_PATH_B]);
+ rssi_a = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_A]);
+ rssi_b = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_B]);
if (rssi_a > rssi_b + RTW89_TX_DIV_RSSI_RAW_TH)
candidate = RF_A;
@@ -5785,7 +6062,7 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta
return;
hal->antenna_tx = candidate;
- rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta);
+ rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta_link);
if (hal->antenna_tx == RF_A) {
rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x12);
@@ -5796,6 +6073,37 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta
}
}
+static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ bool *done = data;
+
+ if (WARN(ieee80211_vif_is_mld(vif), "MLD mix path_div\n"))
+ return;
+
+ if (sta->tdls)
+ return;
+
+ if (*done)
+ return;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
+ continue;
+
+ *done = true;
+ __rtw89_phy_tx_path_div_sta_iter(rtwdev, rtwsta_link);
+ return;
+ }
+}
+
void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -6002,17 +6310,27 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
rtw89_chip_cfg_txrx_path(rtwdev);
}
-void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_reg_def *bss_clr_vld = &chip->bss_clr_vld;
- enum rtw89_phy_idx phy_idx = RTW89_PHY_0;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+ struct ieee80211_bss_conf *bss_conf;
u8 bss_color;
- if (!vif->bss_conf.he_support || !vif->cfg.assoc)
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ if (!bss_conf->he_support || !vif->cfg.assoc) {
+ rcu_read_unlock();
return;
+ }
+
+ bss_color = bss_conf->he_bss_color.color;
- bss_color = vif->bss_conf.he_bss_color.color;
+ rcu_read_unlock();
rtw89_phy_write32_idx(rtwdev, bss_clr_vld->addr, bss_clr_vld->mask, 0x1,
phy_idx);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 6dd8ec46939a..c683f4d7d29b 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -815,6 +815,10 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
void rtw89_phy_dm_init(struct rtw89_dev *rtwdev);
void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
u32 data, enum rtw89_phy_idx phy_idx);
+void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx);
+void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx);
u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
enum rtw89_phy_idx phy_idx);
s8 *rtw89_phy_raw_byr_seek(struct rtw89_dev *rtwdev,
@@ -892,7 +896,7 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
phy->set_txpwr_limit_ru(rtwdev, chan, phy_idx);
}
-void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta);
+void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link);
void rtw89_phy_ra_update(struct rtw89_dev *rtwdev);
void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
u32 changed);
@@ -929,7 +933,7 @@ int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev,
int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx,
const struct rtw89_chan *chan,
- unsigned int ms);
+ bool is_chl_k, unsigned int ms);
void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy,
const struct rtw89_chan *chan,
@@ -953,11 +957,12 @@ void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu);
void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev);
void rtw89_phy_antdiv_work(struct work_struct *work);
-void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link);
void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
enum rtw89_mac_idx mac_idx,
enum rtw89_tssi_bandedge_cfg bandedge_cfg);
-void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev);
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,
diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
index 72eda9bbd3ae..37d8f254ae32 100644
--- a/drivers/net/wireless/realtek/rtw89/phy_be.c
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -398,10 +398,9 @@ static void rtw89_phy_bb_wrap_ul_pwr(struct rtw89_dev *rtwdev)
}
}
-static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev)
+static void __rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev,
+ enum rtw89_mac_idx mac_idx)
{
- enum rtw89_mac_idx mac_idx = RTW89_MAC_0;
-
rtw89_phy_bb_wrap_pwr_by_macid_init(rtwdev);
rtw89_phy_bb_wrap_tx_path_by_macid_init(rtwdev);
rtw89_phy_bb_wrap_listen_path_en_init(rtwdev);
@@ -411,6 +410,13 @@ static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev)
rtw89_phy_bb_wrap_ul_pwr(rtwdev);
}
+static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev)
+{
+ __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_1);
+}
+
static void rtw89_phy_ch_info_init_be(struct rtw89_dev *rtwdev)
{
rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG_LEN, 0x0);
diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c
index aebd6404f802..c1c12abc2ea9 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.c
+++ b/drivers/net/wireless/realtek/rtw89/ps.c
@@ -62,9 +62,9 @@ static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
rtw89_mac_power_mode_change(rtwdev, enter);
}
-void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
- if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
+ if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
return;
if (!rtwdev->ps_mode)
@@ -85,23 +85,25 @@ void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
rtw89_ps_power_mode_change(rtwdev, false);
}
-static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void __rtw89_enter_lps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_lps_parm lps_param = {
- .macid = rtwvif->mac_id,
+ .macid = rtwvif_link->mac_id,
.psmode = RTW89_MAC_AX_PS_MODE_LEGACY,
.lastrpwm = RTW89_LAST_RPWM_PS,
};
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL);
rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
- rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif);
+ rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif_link);
}
-static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void __rtw89_leave_lps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_lps_parm lps_param = {
- .macid = rtwvif->mac_id,
+ .macid = rtwvif_link->mac_id,
.psmode = RTW89_MAC_AX_PS_MODE_ACTIVE,
.lastrpwm = RTW89_LAST_RPWM_ACTIVE,
};
@@ -109,7 +111,7 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
rtw89_fw_h2c_lps_parm(rtwdev, &lps_param);
rtw89_fw_leave_lps_check(rtwdev, 0);
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
- rtw89_chip_digital_pwr_comp(rtwdev, rtwvif->phy_idx);
+ rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx);
}
void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
@@ -119,7 +121,7 @@ void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
__rtw89_leave_ps_mode(rtwdev);
}
-void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool ps_mode)
{
lockdep_assert_held(&rtwdev->mutex);
@@ -127,23 +129,26 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags))
return;
- __rtw89_enter_lps(rtwdev, rtwvif);
+ __rtw89_enter_lps(rtwdev, rtwvif_link);
if (ps_mode)
- __rtw89_enter_ps_mode(rtwdev, rtwvif);
+ __rtw89_enter_ps_mode(rtwdev, rtwvif_link);
}
-static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION &&
- rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION &&
+ rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT)
return;
- __rtw89_leave_lps(rtwdev, rtwvif);
+ __rtw89_leave_lps(rtwdev, rtwvif_link);
}
void rtw89_leave_lps(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
lockdep_assert_held(&rtwdev->mutex);
@@ -153,12 +158,15 @@ void rtw89_leave_lps(struct rtw89_dev *rtwdev)
__rtw89_leave_ps_mode(rtwdev);
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_leave_lps_vif(rtwdev, rtwvif);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_leave_lps_vif(rtwdev, rtwvif_link);
}
void rtw89_enter_ips(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
@@ -166,14 +174,17 @@ void rtw89_enter_ips(struct rtw89_dev *rtwdev)
return;
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_mac_vif_deinit(rtwdev, rtwvif);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_mac_vif_deinit(rtwdev, rtwvif_link);
rtw89_core_stop(rtwdev);
}
void rtw89_leave_ips(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
int ret;
if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags))
@@ -186,7 +197,8 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev)
rtw89_set_channel(rtwdev);
rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_mac_vif_init(rtwdev, rtwvif);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_mac_vif_init(rtwdev, rtwvif_link);
clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags);
}
@@ -197,48 +209,50 @@ void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl)
rtw89_leave_lps(rtwdev);
}
-static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
enum rtw89_p2pps_action act)
{
if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE)
return;
if (act == RTW89_P2P_ACT_INIT)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, true);
else if (act == RTW89_P2P_ACT_TERMINATE)
- rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false);
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, false);
}
static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif)
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
enum rtw89_p2pps_action act;
u8 noa_id;
- if (rtwvif->last_noa_nr == 0)
+ if (rtwvif_link->last_noa_nr == 0)
return;
- for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) {
- if (noa_id == rtwvif->last_noa_nr - 1)
+ for (noa_id = 0; noa_id < rtwvif_link->last_noa_nr; noa_id++) {
+ if (noa_id == rtwvif_link->last_noa_nr - 1)
act = RTW89_P2P_ACT_TERMINATE;
else
act = RTW89_P2P_ACT_REMOVE;
- rtw89_tsf32_toggle(rtwdev, rtwvif, act);
- rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id);
+ rtw89_tsf32_toggle(rtwdev, rtwvif_link, act);
+ rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf,
+ NULL, act, noa_id);
}
}
static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif)
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf)
{
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct ieee80211_p2p_noa_desc *desc;
enum rtw89_p2pps_action act;
u8 noa_id;
for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) {
- desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id];
+ desc = &bss_conf->p2p_noa_attr.desc[noa_id];
if (!desc->count || !desc->duration)
break;
@@ -246,16 +260,19 @@ static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev,
act = RTW89_P2P_ACT_INIT;
else
act = RTW89_P2P_ACT_UPDATE;
- rtw89_tsf32_toggle(rtwdev, rtwvif, act);
- rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id);
+ rtw89_tsf32_toggle(rtwdev, rtwvif_link, act);
+ rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf,
+ desc, act, noa_id);
}
- rtwvif->last_noa_nr = noa_id;
+ rtwvif_link->last_noa_nr = noa_id;
}
-void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf)
{
- rtw89_p2p_disable_all_noa(rtwdev, vif);
- rtw89_p2p_update_noa(rtwdev, vif);
+ rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, bss_conf);
+ rtw89_p2p_update_noa(rtwdev, rtwvif_link, bss_conf);
}
void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
@@ -265,6 +282,12 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
enum rtw89_entity_mode mode;
int count = 0;
+ /* FIXME: Fix rtw89_enter_lps() and __rtw89_enter_ps_mode()
+ * to take MLO cases into account before doing the following.
+ */
+ if (rtwdev->support_mlo)
+ goto disable_lps;
+
mode = rtw89_get_entity_mode(rtwdev);
if (mode == RTW89_ENTITY_MODE_MCC)
goto disable_lps;
@@ -291,9 +314,9 @@ disable_lps:
rtwdev->lps_enabled = false;
}
-void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)
+void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link)
{
- struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+ struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa;
struct rtw89_p2p_noa_ie *ie = &setter->ie;
struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
@@ -318,10 +341,10 @@ void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif)
noa_head->oppps_ctwindow = 0;
}
-void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link,
const struct ieee80211_p2p_noa_desc *desc)
{
- struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+ struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa;
struct rtw89_p2p_noa_ie *ie = &setter->ie;
struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head;
struct rtw89_noa_attr_head *noa_head = &ie->noa_head;
@@ -338,9 +361,9 @@ void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
ie->noa_desc[setter->noa_count++] = *desc;
}
-u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data)
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data)
{
- struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa;
+ struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa;
struct rtw89_p2p_noa_ie *ie = &setter->ie;
void *tail;
diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h
index 54486e4550b6..cdd712966b09 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.h
+++ b/drivers/net/wireless/realtek/rtw89/ps.h
@@ -5,21 +5,23 @@
#ifndef __RTW89_PS_H_
#define __RTW89_PS_H_
-void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool ps_mode);
void rtw89_leave_lps(struct rtw89_dev *rtwdev);
void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev);
-void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link);
void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev);
void rtw89_enter_ips(struct rtw89_dev *rtwdev);
void rtw89_leave_ips(struct rtw89_dev *rtwdev);
void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl);
-void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_bss_conf *bss_conf);
void rtw89_recalc_lps(struct rtw89_dev *rtwdev);
-void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif);
-void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif,
+void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link);
+void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link,
const struct ieee80211_p2p_noa_desc *desc);
-u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data);
+u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data);
static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev)
{
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 69678eab2309..18ec7c0252fb 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -196,6 +196,8 @@
#define R_AX_HALT_C2H 0x016C
#define R_AX_WCPU_FW_CTRL 0x01E0
+#define B_AX_IDMEM_SHARE_MODE_RECORD_MASK GENMASK(27, 24)
+#define B_AX_IDMEM_SHARE_MODE_RECORD_VALID BIT(23)
#define B_AX_WCPU_FWDL_STS_MASK GENMASK(7, 5)
#define B_AX_FWDL_PATH_RDY BIT(2)
#define B_AX_H2C_PATH_RDY BIT(1)
diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
index a7720a1f17a7..cad5189708e7 100644
--- a/drivers/net/wireless/realtek/rtw89/regd.c
+++ b/drivers/net/wireless/realtek/rtw89/regd.c
@@ -646,22 +646,44 @@ static void rtw89_regd_apply_policy_unii4(struct rtw89_dev *rtwdev,
sband->channels[i].flags |= IEEE80211_CHAN_DISABLED;
}
-static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev,
- struct wiphy *wiphy)
+static bool regd_is_6ghz_blocked(struct rtw89_dev *rtwdev)
{
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 &&
!test_bit(index, regulatory->block_6ghz))
- return;
+ return false;
rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n",
regd->alpha2[0], regd->alpha2[1]);
+ return true;
+}
+
+static bool regd_is_6ghz_not_applicable(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ const struct rtw89_regd *regd = regulatory->regd;
+
+ if (regd->txpwr_regd[RTW89_BAND_6G] != RTW89_NA)
+ return false;
+
+ rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is N/A in regd map\n",
+ regd->alpha2[0], regd->alpha2[1]);
+ return true;
+}
+
+static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev,
+ struct wiphy *wiphy)
+{
+ struct ieee80211_supported_band *sband;
+ int i;
+
+ if (!regd_is_6ghz_blocked(rtwdev) &&
+ !regd_is_6ghz_not_applicable(rtwdev))
+ return;
sband = wiphy->bands[NL80211_BAND_6GHZ];
if (!sband)
@@ -793,22 +815,26 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev)
{
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
struct rtw89_reg_6ghz_tpe new = {};
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
bool changed = false;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
const struct rtw89_reg_6ghz_tpe *tmp;
const struct rtw89_chan *chan;
- chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
- if (chan->band_type != RTW89_BAND_6G)
- continue;
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ if (chan->band_type != RTW89_BAND_6G)
+ continue;
- tmp = &rtwvif->reg_6ghz_tpe;
- if (!tmp->valid)
- continue;
+ tmp = &rtwvif_link->reg_6ghz_tpe;
+ if (!tmp->valid)
+ continue;
- tpe_intersect_constraint(&new, tmp->constraint);
+ tpe_intersect_constraint(&new, tmp->constraint);
+ }
}
if (memcmp(&regulatory->reg_6ghz_tpe, &new,
@@ -831,19 +857,24 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev)
}
static int rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool active,
+ struct rtw89_vif_link *rtwvif_link, bool active,
unsigned int *changed)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- struct rtw89_reg_6ghz_tpe *tpe = &rtwvif->reg_6ghz_tpe;
+ struct rtw89_reg_6ghz_tpe *tpe = &rtwvif_link->reg_6ghz_tpe;
+ struct ieee80211_bss_conf *bss_conf;
memset(tpe, 0, sizeof(*tpe));
- if (!active || rtwvif->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD)
+ if (!active || rtwvif_link->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD)
goto bottom;
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
rtw89_calculate_tpe(rtwdev, tpe, &bss_conf->tpe);
+
+ rcu_read_unlock();
+
if (!tpe->valid)
goto bottom;
@@ -867,20 +898,24 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev)
const struct rtw89_regd *regd = regulatory->regd;
enum rtw89_reg_6ghz_power sel;
const struct rtw89_chan *chan;
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
+ unsigned int link_id;
int count = 0;
u8 index;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx);
- if (chan->band_type != RTW89_BAND_6G)
- continue;
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ if (chan->band_type != RTW89_BAND_6G)
+ continue;
- if (count != 0 && rtwvif->reg_6ghz_power == sel)
- continue;
+ if (count != 0 && rtwvif_link->reg_6ghz_power == sel)
+ continue;
- sel = rtwvif->reg_6ghz_power;
- count++;
+ sel = rtwvif_link->reg_6ghz_power;
+ count++;
+ }
}
if (count != 1)
@@ -908,35 +943,41 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev)
}
static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool active,
+ struct rtw89_vif_link *rtwvif_link, bool active,
unsigned int *changed)
{
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_bss_conf *bss_conf;
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
if (active) {
- switch (vif->bss_conf.power_type) {
+ switch (bss_conf->power_type) {
case IEEE80211_REG_VLP_AP:
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP;
break;
case IEEE80211_REG_LPI_AP:
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI;
break;
case IEEE80211_REG_SP_AP:
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD;
break;
default:
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
break;
}
} else {
- rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
+ rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
}
+ rcu_read_unlock();
+
*changed += __rtw89_reg_6ghz_power_recalc(rtwdev);
return 0;
}
-int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool active)
{
unsigned int changed = 0;
@@ -948,11 +989,11 @@ int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
* so must do reg_6ghz_tpe_recalc() after reg_6ghz_power_recalc().
*/
- ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, active, &changed);
+ ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif_link, active, &changed);
if (ret)
return ret;
- ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif, active, &changed);
+ ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif_link, active, &changed);
if (ret)
return ret;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index 1679bd408ef3..68c67a763f4d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -282,7 +282,7 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev)
{
u32 val32;
u8 val8;
- u32 ret;
+ int ret;
rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN |
B_AX_AFSM_PCIE_SUS_EN);
@@ -401,7 +401,7 @@ static void rtw8851b_patch_swr_pfm2pwm(struct rtw89_dev *rtwdev)
static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF,
XTAL_SI_RFC2RF);
@@ -1590,10 +1590,11 @@ static void rtw8851b_rfk_init(struct rtw89_dev *rtwdev)
rtw8851b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0);
}
-static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
rtw8851b_rx_dck(rtwdev, phy_idx, chanctx_idx);
rtw8851b_iqk(rtwdev, phy_idx, chanctx_idx);
@@ -1608,10 +1609,12 @@ static void rtw8851b_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw8851b_tssi_scan(rtwdev, phy_idx, chan);
}
-static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
- rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx);
+ rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx,
+ rtwvif_link->chanctx_idx);
}
static void rtw8851b_rfk_track(struct rtw89_dev *rtwdev)
@@ -2451,6 +2454,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.wde_qempty_acq_grpnum = 4,
.wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000},
+ .thermal_th = {0x32, 0x35},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = &rtw89_8851b_phy_bb_table,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
index d334924faec8..651cbce1dd7e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
@@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
.enable_intr = rtw89_pci_enable_intr,
.disable_intr = rtw89_pci_disable_intr,
.recognize_intrs = rtw89_pci_recognize_intrs,
+
+ .ssid_quirks = NULL,
};
static const struct rtw89_driver_info rtw89_8851be_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index dde96bd63021..e647759ebd69 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -1350,10 +1350,11 @@ static void rtw8852a_rfk_init(struct rtw89_dev *rtwdev)
rtw8852a_rx_dck(rtwdev, RTW89_PHY_0, true, RTW89_CHANCTX_0);
}
-static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
rtw8852a_rx_dck(rtwdev, phy_idx, true, chanctx_idx);
rtw8852a_iqk(rtwdev, phy_idx, chanctx_idx);
@@ -1368,10 +1369,11 @@ static void rtw8852a_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw8852a_tssi_scan(rtwdev, phy_idx, chan);
}
-static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
- rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx);
+ rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx);
}
static void rtw8852a_rfk_track(struct rtw89_dev *rtwdev)
@@ -2168,6 +2170,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.wde_qempty_acq_grpnum = 16,
.wde_qempty_mgq_grpsel = 16,
.rf_base_addr = {0xc000, 0xd000},
+ .thermal_th = {0x32, 0x35},
.pwr_on_seq = pwr_on_seq_8852a,
.pwr_off_seq = pwr_off_seq_8852a,
.bb_table = &rtw89_8852a_phy_bb_table,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index 9a675e2193bc..701187d69e14 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -58,6 +58,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
.enable_intr = rtw89_pci_enable_intr,
.disable_intr = rtw89_pci_disable_intr,
.recognize_intrs = rtw89_pci_recognize_intrs,
+
+ .ssid_quirks = NULL,
};
static const struct rtw89_driver_info rtw89_8852ae_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 12be52f76427..49a319128316 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -254,7 +254,7 @@ static void rtw8852b_pwr_sps_ana(struct rtw89_dev *rtwdev)
static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
rtw8852b_pwr_sps_ana(rtwdev);
@@ -383,7 +383,7 @@ func_en:
static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
rtw8852b_pwr_sps_ana(rtwdev);
@@ -562,10 +562,11 @@ static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev)
rtw8852b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0);
}
-static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx);
rtw8852b_iqk(rtwdev, phy_idx, chanctx_idx);
@@ -580,10 +581,12 @@ static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw8852b_tssi_scan(rtwdev, phy_idx, chan);
}
-static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
- rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx);
+ rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx,
+ rtwvif_link->chanctx_idx);
}
static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev)
@@ -805,6 +808,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.wde_qempty_acq_grpnum = 4,
.wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000, 0xf000},
+ .thermal_th = {0x32, 0x35},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = &rtw89_8852b_phy_bb_table,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
index ede0ca5426ae..f4aa4437fb75 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
@@ -905,7 +905,6 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw,
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 rx_path_0;
- u32 val;
rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, phy_idx);
@@ -985,12 +984,11 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw,
rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH,
pri_ch, phy_idx);
- /*Set RF mode at A */
- val = chip_id == RTL8852BT ? 0x333 : 0xaaa;
+ /*Set RF mode at 3 */
rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX,
- B_P0_RFMODE_ORI_RX_ALL, val, phy_idx);
+ B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx);
rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX,
- B_P1_RFMODE_ORI_RX_ALL, val, phy_idx);
+ B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx);
break;
default:
rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
index d8f9d92ca0fb..a13ea1cce4a7 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
@@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
.enable_intr = rtw89_pci_enable_intr,
.disable_intr = rtw89_pci_disable_intr,
.recognize_intrs = rtw89_pci_recognize_intrs,
+
+ .ssid_quirks = NULL,
};
static const struct rtw89_driver_info rtw89_8852be_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index 7dfdcb5964e1..876725133228 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -244,7 +244,7 @@ static const u8 rtw89_btc_8852bt_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30,
static int rtw8852bt_pwr_on_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
rtw89_write32_set(rtwdev, R_AX_LDO_AON_CTRL0, B_AX_PD_REGU_L);
rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN |
@@ -357,7 +357,7 @@ func_en:
static int rtw8852bt_pwr_off_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF,
XTAL_SI_RFC2RF);
@@ -535,10 +535,11 @@ static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev)
rtw8852bt_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0);
}
-static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx);
rtw8852bt_iqk(rtwdev, phy_idx, chanctx_idx);
@@ -553,10 +554,12 @@ static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw8852bt_tssi_scan(rtwdev, phy_idx, chan);
}
-static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
- rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx);
+ rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx,
+ rtwvif_link->chanctx_idx);
}
static void rtw8852bt_rfk_track(struct rtw89_dev *rtwdev)
@@ -739,6 +742,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.wde_qempty_acq_grpnum = 4,
.wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000, 0xf000},
+ .thermal_th = {0x32, 0x35},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = NULL,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
index 702948119646..e4f40c2e287d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c
@@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = {
.enable_intr = rtw89_pci_enable_intr,
.disable_intr = rtw89_pci_disable_intr,
.recognize_intrs = rtw89_pci_recognize_intrs,
+
+ .ssid_quirks = NULL,
};
static const struct rtw89_driver_info rtw89_8852bte_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 1c6e89ab0f4b..cde34f8e1e67 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -203,7 +203,7 @@ static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path,
static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
val32 = rtw89_read32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_PAD_HCI_SEL_V2_MASK);
if (val32 == MAC_AX_HCI_SEL_PCIE_USB)
@@ -324,7 +324,7 @@ static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev)
static int rtw8852c_pwr_off_func(struct rtw89_dev *rtwdev)
{
u32 val32;
- u32 ret;
+ int ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF,
XTAL_SI_RFC2RF);
@@ -1846,10 +1846,11 @@ static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev)
rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false);
}
-static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
rtw8852c_mcc_get_ch_info(rtwdev, phy_idx);
rtw8852c_rx_dck(rtwdev, phy_idx, false);
@@ -1866,10 +1867,11 @@ static void rtw8852c_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw8852c_tssi_scan(rtwdev, phy_idx, chan);
}
-static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
- rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx);
+ rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx);
}
static void rtw8852c_rfk_track(struct rtw89_dev *rtwdev)
@@ -2945,6 +2947,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.wde_qempty_acq_grpnum = 16,
.wde_qempty_mgq_grpsel = 16,
.rf_base_addr = {0xe000, 0xf000},
+ .thermal_th = {0x32, 0x35},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = &rtw89_8852c_phy_bb_table,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
index 211c051c2967..bd17c0a1c684 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
@@ -1065,7 +1065,7 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev,
static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path)
{
- struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
struct rtw89_iqk_info *iqk_info = &rtwdev->iqk;
u8 idx = rfk_mcc->table_idx;
bool is_fail1, is_fail2;
@@ -1408,7 +1408,7 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev,
static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path)
{
- struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
u8 idx = 0;
idx = rfk_mcc->table_idx;
@@ -2350,7 +2350,7 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
if (dgain > 0x5fc || dgain < 0x556) {
_dpk_one_shot(rtwdev, phy, path, D_SYNC);
- dgain = _dpk_dgain_read(rtwdev);
+ _dpk_dgain_read(rtwdev);
}
if (agc_cnt == 0) {
@@ -4105,7 +4105,7 @@ void rtw8852c_set_channel_rf(struct rtw89_dev *rtwdev,
void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
{
- struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {};
const struct rtw89_chan *chan;
enum rtw89_entity_mode mode;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 8aaad7d58c0d..1a46878be96b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -67,6 +67,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
.enable_intr = rtw89_pci_enable_intr_v1,
.disable_intr = rtw89_pci_disable_intr_v1,
.recognize_intrs = rtw89_pci_recognize_intrs_v1,
+
+ .ssid_quirks = NULL,
};
static const struct dmi_system_id rtw8852c_pci_quirks[] = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 63b1ff2f98ed..9a4db04a1967 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2023 Realtek Corporation
*/
+#include "chan.h"
#include "coex.h"
#include "debug.h"
#include "efuse.h"
@@ -13,7 +14,7 @@
#include "rtw8922a_rfk.h"
#include "util.h"
-#define RTW8922A_FW_FORMAT_MAX 1
+#define RTW8922A_FW_FORMAT_MAX 2
#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw"
#define RTW8922A_MODULE_FIRMWARE \
RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin"
@@ -398,9 +399,6 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev)
rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN |
B_BE_FEN_BBPLAT_RSTB);
- if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags))
- rtw89_efuse_read_fw_secure_be(rtwdev);
-
return 0;
}
@@ -965,6 +963,42 @@ static const struct rtw8922a_bb_gain bb_gain_tia[TIA_GAIN_NUM] = {
.gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 },
};
+static const struct rtw8922a_bb_gain bb_op1db_lna[LNA_GAIN_NUM] = {
+ { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x4078, 0x4478},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00},
+};
+
+static const struct rtw8922a_bb_gain bb_op1db_tia_lna[TIA_LNA_OP1DB_NUM] = {
+ { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4080, 0x4480},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4084, 0x4484},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4088, 0x4488},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000},
+};
+
struct rtw8922a_bb_gain_bypass {
u32 gain_g[BB_PATH_NUM_8922A];
u32 gain_a[BB_PATH_NUM_8922A];
@@ -1056,6 +1090,30 @@ static void rtw8922a_set_lna_tia_gain(struct rtw89_dev *rtwdev,
val = gain->tia_gain[gain_band][bw_type][path][i];
rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
}
+
+ for (i = 0; i < LNA_GAIN_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_op1db_lna[i].gain_g[path];
+ mask = bb_op1db_lna[i].gain_g_mask;
+ } else {
+ reg = bb_op1db_lna[i].gain_a[path];
+ mask = bb_op1db_lna[i].gain_a_mask;
+ }
+ val = gain->lna_op1db[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < TIA_LNA_OP1DB_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_op1db_tia_lna[i].gain_g[path];
+ mask = bb_op1db_tia_lna[i].gain_g_mask;
+ } else {
+ reg = bb_op1db_tia_lna[i].gain_a[path];
+ mask = bb_op1db_tia_lna[i].gain_a_mask;
+ }
+ val = gain->tia_lna_op1db[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
}
static void rtw8922a_set_gain(struct rtw89_dev *rtwdev,
@@ -1745,7 +1803,7 @@ static void rtw8922a_digital_pwr_comp(struct rtw89_dev *rtwdev,
static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+ const struct rtw89_chan *chan0, *chan1;
if (mode == MLO_1_PLUS_1_1RF || mode == DBCC_LEGACY) {
rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x1);
@@ -1758,13 +1816,20 @@ static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode
return -EOPNOTSUPP;
}
- if (mode == MLO_2_PLUS_0_1RF) {
- rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_A);
- rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_B);
+ if (mode == MLO_1_PLUS_1_1RF) {
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ chan0 = chan1;
} else {
- rtw89_warn(rtwdev, "unsupported MLO mode %d\n", mode);
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = chan0;
}
+ rtw8922a_ctrl_afe_dac(rtwdev, chan0->band_width, RF_PATH_A);
+ rtw8922a_ctrl_afe_dac(rtwdev, chan1->band_width, RF_PATH_B);
+
rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180);
if (mode == MLO_2_PLUS_0_1RF) {
@@ -1991,14 +2056,23 @@ static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev)
memset(rfk_mcc, 0, sizeof(*rfk_mcc));
}
+static void __rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan)
+{
+ rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+
+ rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58);
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 32);
+}
+
static void rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
- rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, RTW89_PHY_0, 5);
-
- rtw89_phy_rfk_dack_and_wait(rtwdev, RTW89_PHY_0, chan, 58);
- rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32);
+ __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_0, chan);
+ if (rtwdev->dbcc_en)
+ __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_1, chan);
}
static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath)
@@ -2020,11 +2094,12 @@ static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath)
}
}
-static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
- enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx;
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx);
- enum rtw89_phy_idx phy_idx = rtwvif->phy_idx;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx);
u32 tx_en;
@@ -2035,9 +2110,9 @@ static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtw
rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54);
rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84);
- rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 6);
+ rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20);
rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 34);
- rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32);
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32);
rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en);
rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP);
@@ -2050,7 +2125,8 @@ static void rtw8922a_rfk_band_changed(struct rtw89_dev *rtwdev,
rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_SCAN, 6);
}
-static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
bool start)
{
}
@@ -2207,10 +2283,12 @@ static void rtw8922a_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path)
{
struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ struct rtw89_hal *hal = &rtwdev->hal;
int th;
- /* read thermal only if debugging */
- if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK))
+ /* read thermal only if debugging or thermal protection enabled */
+ if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK) &&
+ !hal->thermal_prot_th)
return 80;
rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1);
@@ -2641,6 +2719,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.wde_qempty_acq_grpnum = 4,
.wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000, 0xf000},
+ .thermal_th = {0xad, 0xb4},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
.bb_table = NULL,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c
index 28907df7407d..c4c93f836a2f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c
@@ -252,49 +252,58 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx)
}
}
-static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev)
+static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 path)
{
struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {};
- enum rtw89_chanctx_idx chanctx_idx;
- const struct rtw89_chan *chan;
- enum rtw89_entity_mode mode;
- u8 s0_tbl, s1_tbl;
u8 tbl_sel;
- mode = rtw89_get_entity_mode(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- chanctx_idx = RTW89_CHANCTX_1;
- break;
- default:
- chanctx_idx = RTW89_CHANCTX_0;
- break;
- }
-
- chan = rtw89_chan_get(rtwdev, chanctx_idx);
-
for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) {
struct rtw89_rfk_chan_desc *p = &desc[tbl_sel];
- p->ch = rfk_mcc->ch[tbl_sel];
+ p->ch = rfk_mcc->data[path].ch[tbl_sel];
p->has_band = true;
- p->band = rfk_mcc->band[tbl_sel];
+ p->band = rfk_mcc->data[path].band[tbl_sel];
p->has_bw = true;
- p->bw = rfk_mcc->bw[tbl_sel];
+ p->bw = rfk_mcc->data[path].bw[tbl_sel];
}
tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan);
- rfk_mcc->ch[tbl_sel] = chan->channel;
- rfk_mcc->band[tbl_sel] = chan->band_type;
- rfk_mcc->bw[tbl_sel] = chan->band_width;
- rfk_mcc->table_idx = tbl_sel;
+ rfk_mcc->data[path].ch[tbl_sel] = chan->channel;
+ rfk_mcc->data[path].band[tbl_sel] = chan->band_type;
+ rfk_mcc->data[path].bw[tbl_sel] = chan->band_width;
+ rfk_mcc->data[path].table_idx = tbl_sel;
+
+ return tbl_sel;
+}
+
+static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan0, *chan1;
+ u8 s0_tbl, s1_tbl;
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ default:
+ case MLO_2_PLUS_0_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = chan0;
+ break;
+ case MLO_0_PLUS_2_1RF:
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ chan0 = chan1;
+ break;
+ case MLO_1_PLUS_1_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ break;
+ }
- s0_tbl = tbl_sel;
- s1_tbl = tbl_sel;
+ s0_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan0, 0);
+ s1_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan1, 1);
rtw8922a_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl);
rtw8922a_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
index 47f855a7a268..edfb1f220af0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
@@ -9,6 +9,12 @@
#include "reg.h"
#include "rtw8922a.h"
+static const struct rtw89_pci_ssid_quirk rtw8922a_pci_ssid_quirks[] = {
+ {RTW89_PCI_SSID(PCI_VENDOR_ID_REALTEK, 0x8922, 0x10EC, 0xA891, DELL),
+ .bitmap = BIT(RTW89_QUIRK_THERMAL_PROT_120C)},
+ {},
+};
+
static const struct rtw89_pci_info rtw8922a_pci_info = {
.gen_def = &rtw89_pci_gen_be,
.txbd_trunc_mode = MAC_AX_BD_TRUNC,
@@ -58,6 +64,8 @@ static const struct rtw89_pci_info rtw8922a_pci_info = {
.enable_intr = rtw89_pci_enable_intr_v2,
.disable_intr = rtw89_pci_disable_intr_v2,
.recognize_intrs = rtw89_pci_recognize_intrs_v2,
+
+ .ssid_quirks = rtw8922a_pci_ssid_quirks,
};
static const struct rtw89_driver_info rtw89_8922ae_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c
index 27826d909785..bcc287771b2a 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.c
+++ b/drivers/net/wireless/realtek/rtw89/sar.c
@@ -27,8 +27,8 @@ static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
return RTW89_SAR_5GHZ_SUBBAND_1_2;
case 5500 ... 5720:
return RTW89_SAR_5GHZ_SUBBAND_2_E;
- case 5745 ... 5825:
- return RTW89_SAR_5GHZ_SUBBAND_3;
+ case 5745 ... 5885:
+ return RTW89_SAR_5GHZ_SUBBAND_3_4;
case 5955 ... 6155:
return RTW89_SAR_6GHZ_SUBBAND_5_L;
case 6175 ... 6415:
@@ -295,7 +295,7 @@ static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = {
{ .start_freq = 2412, .end_freq = 2484, },
{ .start_freq = 5180, .end_freq = 5320, },
{ .start_freq = 5500, .end_freq = 5720, },
- { .start_freq = 5745, .end_freq = 5825, },
+ { .start_freq = 5745, .end_freq = 5885, },
{ .start_freq = 5955, .end_freq = 6155, },
{ .start_freq = 6175, .end_freq = 6415, },
{ .start_freq = 6435, .end_freq = 6515, },
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
index 5fc2faa9ba5a..7b203bb7f151 100644
--- a/drivers/net/wireless/realtek/rtw89/ser.c
+++ b/drivers/net/wireless/realtek/rtw89/ser.c
@@ -300,37 +300,54 @@ static void drv_resume_rx(struct rtw89_ser *ser)
static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
- rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
- rtwvif->net_type = RTW89_NET_TYPE_NO_LINK;
- rtwvif->trigger = false;
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
rtwvif->tdls_peer = 0;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) {
+ rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif_link->port);
+ rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK;
+ rtwvif_link->trigger = false;
+ }
}
static void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_vif *target_rtwvif = (struct rtw89_vif *)data;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_dev *rtwdev = rtwvif->rtwdev;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
if (rtwvif != target_rtwvif)
return;
- if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls)
- rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam);
- if (sta->tdls)
- rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam);
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
- INIT_LIST_HEAD(&rtwsta->ba_cam_list);
+ if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls)
+ rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam);
+ if (sta->tdls)
+ rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam);
+
+ INIT_LIST_HEAD(&rtwsta_link->ba_cam_list);
+ }
}
static void ser_deinit_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
ieee80211_iterate_stations_atomic(rtwdev->hw,
ser_sta_deinit_cam_iter,
rtwvif);
- rtw89_cam_deinit(rtwdev, rtwvif);
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_cam_deinit(rtwdev, rtwvif_link);
bitmap_zero(rtwdev->cam_info.ba_cam_map, RTW89_MAX_BA_CAM_NUM);
}
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 86e24e07780d..3e81fd974ec1 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -421,7 +421,8 @@ static void rtw89_wow_construct_key_info(struct rtw89_dev *rtwdev)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_wow_key_info *key_info = &rtw_wow->key_info;
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
bool err = false;
rcu_read_lock();
@@ -596,7 +597,8 @@ static int rtw89_wow_get_aoac_rpt(struct rtw89_dev *rtwdev, bool rx_ready)
static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev,
u32 cipher, u8 keyidx, u8 *gtk)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
const struct rtw89_cipher_info *cipher_info;
struct ieee80211_key_conf *rekey_conf;
struct ieee80211_key_conf *key;
@@ -632,11 +634,13 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev,
static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt;
struct rtw89_set_key_info_iter_data data = {.error = false,
.rx_ready = rx_ready};
+ struct ieee80211_bss_conf *bss_conf;
struct ieee80211_key_conf *key;
rcu_read_lock();
@@ -669,9 +673,15 @@ static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready)
return;
rtw89_rx_pn_set_pmf(rtwdev, key, aoac_rpt->igtk_ipn);
- ieee80211_gtk_rekey_notify(wow_vif, wow_vif->bss_conf.bssid,
+
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ ieee80211_gtk_rekey_notify(wow_vif, bss_conf->bssid,
aoac_rpt->eapol_key_replay_count,
- GFP_KERNEL);
+ GFP_ATOMIC);
+
+ rcu_read_unlock();
}
static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev)
@@ -681,27 +691,24 @@ static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev)
static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
- __rtw89_enter_ps_mode(rtwdev, rtwvif);
+ __rtw89_enter_ps_mode(rtwdev, rtwvif_link);
}
static void rtw89_wow_enter_ps(struct rtw89_dev *rtwdev)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
if (rtw89_wow_mgd_linked(rtwdev))
- rtw89_enter_lps(rtwdev, rtwvif, false);
+ rtw89_enter_lps(rtwdev, rtwvif_link, false);
else if (rtw89_wow_no_link(rtwdev))
- rtw89_fw_h2c_fwips(rtwdev, rtwvif, true);
+ rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, true);
}
static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
if (rtw89_wow_mgd_linked(rtwdev)) {
rtw89_leave_lps(rtwdev);
@@ -709,7 +716,7 @@ static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow)
if (enable_wow)
rtw89_leave_ips(rtwdev);
else
- rtw89_fw_h2c_fwips(rtwdev, rtwvif, false);
+ rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, false);
}
}
@@ -734,6 +741,8 @@ static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable)
static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev)
{
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt;
struct cfg80211_wowlan_nd_info nd_info;
@@ -780,35 +789,34 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev)
break;
default:
rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason);
- ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL,
- GFP_KERNEL);
+ ieee80211_report_wowlan_wakeup(wow_vif, NULL, GFP_KERNEL);
return;
}
- ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup,
- GFP_KERNEL);
+ ieee80211_report_wowlan_wakeup(wow_vif, &wakeup, GFP_KERNEL);
}
-static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
/* Current WoWLAN function support setting of only vif in
* infra mode or no link mode. When one suitable vif is found,
* stop the iteration.
*/
- if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION)
+ if (rtw_wow->rtwvif_link || vif->type != NL80211_IFTYPE_STATION)
return;
- switch (rtwvif->net_type) {
+ switch (rtwvif_link->net_type) {
case RTW89_NET_TYPE_INFRA:
if (rtw_wow_has_mgd_features(rtwdev))
- rtw_wow->wow_vif = vif;
+ rtw_wow->rtwvif_link = rtwvif_link;
break;
case RTW89_NET_TYPE_NO_LINK:
if (rtw_wow->pno_inited)
- rtw_wow->wow_vif = vif;
+ rtw_wow->rtwvif_link = rtwvif_link;
break;
default:
break;
@@ -865,7 +873,7 @@ static u16 rtw89_calc_crc(u8 *pdata, int length)
return ~crc;
}
-static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif,
+static int rtw89_wow_pattern_get_type(struct rtw89_vif_link *rtwvif_link,
struct rtw89_wow_cam_info *rtw_pattern,
const u8 *pattern, u8 da_mask)
{
@@ -885,7 +893,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif,
rtw_pattern->bc = true;
else if (is_multicast_ether_addr(da))
rtw_pattern->mc = true;
- else if (ether_addr_equal(da, rtwvif->mac_addr) &&
+ else if (ether_addr_equal(da, rtwvif_link->mac_addr) &&
da_mask == GENMASK(5, 0))
rtw_pattern->uc = true;
else if (!da_mask) /*da_mask == 0 mean wildcard*/
@@ -897,7 +905,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif,
}
static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
const struct cfg80211_pkt_pattern *pkt_pattern,
struct rtw89_wow_cam_info *rtw_pattern)
{
@@ -916,7 +924,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev,
mask_len = DIV_ROUND_UP(len, 8);
memset(rtw_pattern, 0, sizeof(*rtw_pattern));
- ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern,
+ ret = rtw89_wow_pattern_get_type(rtwvif_link, rtw_pattern, pattern,
mask[0] & GENMASK(5, 0));
if (ret)
return ret;
@@ -970,7 +978,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev,
}
static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct cfg80211_wowlan *wowlan)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
@@ -983,7 +991,7 @@ static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev,
for (i = 0; i < wowlan->n_patterns; i++) {
rtw_pattern = &rtw_wow->patterns[i];
- ret = rtw89_wow_pattern_generate(rtwdev, rtwvif,
+ ret = rtw89_wow_pattern_generate(rtwdev, rtwvif_link,
&wowlan->patterns[i],
rtw_pattern);
if (ret) {
@@ -1040,7 +1048,7 @@ static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- rtw_wow->wow_vif = NULL;
+ rtw_wow->rtwvif_link = NULL;
rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM);
rtw_wow->pattern_cnt = 0;
rtw_wow->pno_inited = false;
@@ -1066,6 +1074,7 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev,
struct cfg80211_wowlan *wowlan)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ struct rtw89_vif_link *rtwvif_link;
struct rtw89_vif *rtwvif;
if (wowlan->disconnect)
@@ -1078,36 +1087,40 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev,
if (wowlan->nd_config)
rtw89_wow_init_pno(rtwdev, wowlan->nd_config);
- rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_wow_vif_iter(rtwdev, rtwvif);
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ /* use the link on HW-0 to do wow flow */
+ rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+ if (!rtwvif_link)
+ continue;
+
+ rtw89_wow_vif_iter(rtwdev, rtwvif_link);
+ }
- if (!rtw_wow->wow_vif)
+ rtwvif_link = rtw_wow->rtwvif_link;
+ if (!rtwvif_link)
return -EPERM;
- rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv;
- return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan);
+ return rtw89_wow_parse_patterns(rtwdev, rtwvif_link, wowlan);
}
static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow)
{
- struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
int ret;
- ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, true);
+ ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_err(rtwdev, "failed to config pno\n");
return ret;
}
- ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow);
+ ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow);
if (ret) {
rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n");
return ret;
}
- ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow);
+ ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow);
if (ret) {
rtw89_err(rtwdev, "failed to fw wow global\n");
return ret;
@@ -1119,34 +1132,39 @@ static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow)
static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
struct ieee80211_sta *wow_sta;
- struct rtw89_sta *rtwsta = NULL;
+ struct rtw89_sta_link *rtwsta_link = NULL;
+ struct rtw89_sta *rtwsta;
int ret;
- wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid);
- if (wow_sta)
- rtwsta = (struct rtw89_sta *)wow_sta->drv_priv;
+ wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr);
+ if (wow_sta) {
+ rtwsta = sta_to_rtwsta(wow_sta);
+ rtwsta_link = rtwsta->links[rtwvif_link->link_id];
+ if (!rtwsta_link)
+ return -ENOLINK;
+ }
if (wow) {
if (rtw_wow->pattern_cnt)
- rtwvif->wowlan_pattern = true;
+ rtwvif_link->wowlan_pattern = true;
if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags))
- rtwvif->wowlan_magic = true;
+ rtwvif_link->wowlan_magic = true;
} else {
- rtwvif->wowlan_pattern = false;
- rtwvif->wowlan_magic = false;
+ rtwvif_link->wowlan_pattern = false;
+ rtwvif_link->wowlan_magic = false;
}
- ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow);
+ ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow);
if (ret) {
rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n");
return ret;
}
if (wow) {
- ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
+ ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link);
if (ret) {
rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n",
ret);
@@ -1154,13 +1172,13 @@ static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow)
}
}
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cam\n");
return ret;
}
- ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow);
+ ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow);
if (ret) {
rtw89_err(rtwdev, "failed to fw wow global\n");
return ret;
@@ -1190,25 +1208,30 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow)
enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL;
enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link;
+ struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link);
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
const struct rtw89_chip_info *chip = rtwdev->chip;
bool include_bb = !!chip->bbmcu_nr;
bool disable_intr_for_dlfw = false;
struct ieee80211_sta *wow_sta;
- struct rtw89_sta *rtwsta = NULL;
+ struct rtw89_sta_link *rtwsta_link = NULL;
+ struct rtw89_sta *rtwsta;
bool is_conn = true;
int ret;
if (chip_id == RTL8852C || chip_id == RTL8922A)
disable_intr_for_dlfw = true;
- wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid);
- if (wow_sta)
- rtwsta = (struct rtw89_sta *)wow_sta->drv_priv;
- else
+ wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr);
+ if (wow_sta) {
+ rtwsta = sta_to_rtwsta(wow_sta);
+ rtwsta_link = rtwsta->links[rtwvif_link->link_id];
+ if (!rtwsta_link)
+ return -ENOLINK;
+ } else {
is_conn = false;
+ }
if (disable_intr_for_dlfw)
rtw89_hci_disable_intr(rtwdev);
@@ -1224,14 +1247,14 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow)
rtw89_phy_init_rf_reg(rtwdev, true);
- ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
+ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link,
RTW89_ROLE_FW_RESTORE);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c role maintain\n");
return ret;
}
- ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta);
+ ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n");
return ret;
@@ -1240,27 +1263,27 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow)
if (!is_conn)
rtw89_cam_reset_keys(rtwdev);
- ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn);
+ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, !is_conn);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c join info\n");
return ret;
}
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cam\n");
return ret;
}
if (is_conn) {
- ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
+ ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c general packet\n");
return ret;
}
- rtw89_phy_ra_assoc(rtwdev, wow_sta);
- rtw89_phy_set_bss_color(rtwdev, wow_vif);
- rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif);
+ rtw89_phy_ra_assoc(rtwdev, rtwsta_link);
+ rtw89_phy_set_bss_color(rtwdev, rtwvif_link);
+ rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link);
}
if (chip_gen == RTW89_CHIP_BE)
@@ -1363,21 +1386,20 @@ static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev)
static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev)
{
- struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *vif = rtw_wow->wow_vif;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
int ret;
ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
if (ret)
rtw89_err(rtwdev, "cfg ppdu status\n");
- rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
return ret;
}
static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct list_head *pkt_list = &rtw_wow->pno_pkt_list;
@@ -1391,7 +1413,7 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev,
}
static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config;
@@ -1401,7 +1423,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev,
int ret;
for (i = 0; i < num; i++) {
- skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr,
+ skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr,
nd_config->match_sets[i].ssid.ssid,
nd_config->match_sets[i].ssid.ssid_len,
nd_config->ie_len);
@@ -1413,7 +1435,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev,
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
kfree_skb(skb);
- rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif);
+ rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link);
return -ENOMEM;
}
@@ -1421,7 +1443,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev,
if (ret) {
kfree_skb(skb);
kfree(info);
- rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif);
+ rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link);
return ret;
}
@@ -1436,20 +1458,19 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
int interval = rtw_wow->nd_config->scan_plans[0].interval;
struct rtw89_scan_option opt = {};
int ret;
if (enable) {
- ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif);
+ ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif_link);
if (ret) {
rtw89_err(rtwdev, "Update probe request failed\n");
return ret;
}
- ret = mac->add_chan_list_pno(rtwdev, rtwvif);
+ ret = mac->add_chan_list_pno(rtwdev, rtwvif_link);
if (ret) {
rtw89_err(rtwdev, "Update channel list failed\n");
return ret;
@@ -1471,7 +1492,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable)
opt.opch_end = RTW89_CHAN_INVALID;
}
- mac->scan_offload(rtwdev, &opt, rtwvif, true);
+ mac->scan_offload(rtwdev, &opt, rtwvif_link, true);
return 0;
}
@@ -1479,8 +1500,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable)
static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link;
int ret;
if (rtw89_wow_no_link(rtwdev)) {
@@ -1499,25 +1519,25 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev)
rtw89_wow_pattern_write(rtwdev);
rtw89_wow_construct_key_info(rtwdev);
- ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true);
+ ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_err(rtwdev, "wow: failed to enable keep alive\n");
return ret;
}
- ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true);
+ ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n");
return ret;
}
- ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, true);
+ ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_err(rtwdev, "wow: failed to enable GTK offload\n");
return ret;
}
- ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, true);
+ ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, true);
if (ret)
rtw89_warn(rtwdev, "wow: failed to enable arp offload\n");
}
@@ -1548,8 +1568,7 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev)
static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
- struct ieee80211_vif *wow_vif = rtw_wow->wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link;
int ret;
if (rtw89_wow_no_link(rtwdev)) {
@@ -1559,35 +1578,35 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev)
return ret;
}
- ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, false);
+ ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, false);
if (ret) {
rtw89_err(rtwdev, "wow: failed to disable pno\n");
return ret;
}
- rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif);
+ rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link);
} else {
rtw89_wow_pattern_clear(rtwdev);
- ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false);
+ ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, false);
if (ret) {
rtw89_err(rtwdev, "wow: failed to disable keep alive\n");
return ret;
}
- ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false);
+ ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, false);
if (ret) {
rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n");
return ret;
}
- ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, false);
+ ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, false);
if (ret) {
rtw89_err(rtwdev, "wow: failed to disable GTK offload\n");
return ret;
}
- ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, false);
+ ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, false);
if (ret)
rtw89_warn(rtwdev, "wow: failed to disable arp offload\n");
diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h
index 3fbc2b87c058..f91991e8f2e3 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.h
+++ b/drivers/net/wireless/realtek/rtw89/wow.h
@@ -97,18 +97,16 @@ static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev)
#ifdef CONFIG_PM
static inline bool rtw89_wow_mgd_linked(struct rtw89_dev *rtwdev)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
- return rtwvif->net_type == RTW89_NET_TYPE_INFRA;
+ return rtwvif_link->net_type == RTW89_NET_TYPE_INFRA;
}
static inline bool rtw89_wow_no_link(struct rtw89_dev *rtwdev)
{
- struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv;
+ struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link;
- return rtwvif->net_type == RTW89_NET_TYPE_NO_LINK;
+ return rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK;
}
static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
index e7198520bdff..64441c8bc460 100644
--- a/drivers/net/wireless/silabs/wfx/main.c
+++ b/drivers/net/wireless/silabs/wfx/main.c
@@ -480,10 +480,23 @@ static int __init wfx_core_init(void)
{
int ret = 0;
- if (IS_ENABLED(CONFIG_SPI))
+ if (IS_ENABLED(CONFIG_SPI)) {
ret = spi_register_driver(&wfx_spi_driver);
- if (IS_ENABLED(CONFIG_MMC) && !ret)
+ if (ret)
+ goto out;
+ }
+ if (IS_ENABLED(CONFIG_MMC)) {
ret = sdio_register_driver(&wfx_sdio_driver);
+ if (ret)
+ goto unregister_spi;
+ }
+
+ return 0;
+
+unregister_spi:
+ if (IS_ENABLED(CONFIG_SPI))
+ spi_unregister_driver(&wfx_spi_driver);
+out:
return ret;
}
module_init(wfx_core_init);
diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c
index 4f346fb977a9..862964a8cc87 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c
@@ -450,7 +450,7 @@ static int __maybe_unused cw1200_spi_suspend(struct device *dev)
{
struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
- if (!cw1200_can_suspend(self->core))
+ if (self && !cw1200_can_suspend(self->core))
return -EAGAIN;
/* XXX notify host that we have to keep CW1200 powered on? */
diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c
index 805a3c1bf8fe..259739e53fc1 100644
--- a/drivers/net/wireless/st/cw1200/queue.c
+++ b/drivers/net/wireless/st/cw1200/queue.c
@@ -411,33 +411,6 @@ int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id)
return ret;
}
-int cw1200_queue_requeue_all(struct cw1200_queue *queue)
-{
- struct cw1200_queue_item *item, *tmp;
- struct cw1200_queue_stats *stats = queue->stats;
- spin_lock_bh(&queue->lock);
-
- list_for_each_entry_safe_reverse(item, tmp, &queue->pending, head) {
- --queue->num_pending;
- ++queue->link_map_cache[item->txpriv.link_id];
-
- spin_lock_bh(&stats->lock);
- ++stats->num_queued;
- ++stats->link_map_cache[item->txpriv.link_id];
- spin_unlock_bh(&stats->lock);
-
- ++item->generation;
- item->packet_id = cw1200_queue_mk_packet_id(queue->generation,
- queue->queue_id,
- item->generation,
- item - queue->pool);
- list_move(&item->head, &queue->queue);
- }
- spin_unlock_bh(&queue->lock);
-
- return 0;
-}
-
int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id)
{
int ret = 0;
diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h
index 96ac69ae97de..d46304b58747 100644
--- a/drivers/net/wireless/st/cw1200/queue.h
+++ b/drivers/net/wireless/st/cw1200/queue.h
@@ -85,7 +85,6 @@ int cw1200_queue_get(struct cw1200_queue *queue,
struct ieee80211_tx_info **tx_info,
const struct cw1200_txpriv **txpriv);
int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id);
-int cw1200_queue_requeue_all(struct cw1200_queue *queue);
int cw1200_queue_remove(struct cw1200_queue *queue,
u32 packet_id);
int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id,
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index c705081249d6..b45050243129 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -233,8 +233,8 @@ static int wl1251_sdio_probe(struct sdio_func *func,
}
if (wl->irq) {
- irq_set_status_flags(wl->irq, IRQ_NOAUTOEN);
- ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
+ ret = request_irq(wl->irq, wl1251_line_irq, IRQF_NO_AUTOEN,
+ "wl1251", wl);
if (ret < 0) {
wl1251_error("request_irq() failed: %d", ret);
goto disable;
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index b26d42b4e3cc..ffbf54776330 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1939,7 +1939,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
static struct platform_driver wl12xx_driver = {
.probe = wl12xx_probe,
- .remove_new = wl12xx_remove,
+ .remove = wl12xx_remove,
.id_table = wl12xx_id_table,
.driver = {
.name = "wl12xx_driver",
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 39d8eebb9b6e..4be1110bac88 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -2097,9 +2097,9 @@ MODULE_DEVICE_TABLE(platform, wl18xx_id_table);
static struct platform_driver wl18xx_driver = {
.probe = wl18xx_probe,
- .remove_new = wlcore_remove,
+ .remove = wlcore_remove,
.id_table = wl18xx_id_table,
- .driver = {
+ .driver = {
.name = "wl18xx_driver",
}
};
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 0c77b8524160..986b07bfa0ee 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5789,9 +5789,10 @@ static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
+ struct ieee80211_sta *sta = link_sta->sta;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update");
@@ -6052,7 +6053,7 @@ static const struct ieee80211_ops wl1271_ops = {
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
.switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
- .sta_rc_update = wlcore_op_sta_rc_update,
+ .link_sta_rc_update = wlcore_op_sta_rc_update,
.sta_statistics = wlcore_op_sta_statistics,
.get_expected_throughput = wlcore_op_get_expected_throughput,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index 92fb5b8dcdae..a73207bbe5d7 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -323,17 +323,12 @@ static int wl1271_probe(struct sdio_func *func,
memset(res, 0x00, sizeof(res));
- res[0].start = irq;
- res[0].flags = IORESOURCE_IRQ |
- irqd_get_trigger_type(irq_get_irq_data(irq));
- res[0].name = "irq";
-
+ res[0] = DEFINE_RES_IRQ_NAMED(irq, "irq");
+ res[0].flags |= irq_get_trigger_type(irq);
if (wakeirq > 0) {
- res[1].start = wakeirq;
- res[1].flags = IORESOURCE_IRQ |
- irqd_get_trigger_type(irq_get_irq_data(wakeirq));
- res[1].name = "wakeirq";
+ res[1] = DEFINE_RES_IRQ_NAMED(wakeirq, "wakeirq");
+ res[1].flags |= irq_get_trigger_type(wakeirq);
num_irqs = 2;
} else {
num_irqs = 1;
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index f0e528abb1b4..347a15544afe 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -763,7 +763,7 @@ static const struct rhashtable_params hwsim_rht_params = {
};
struct hwsim_radiotap_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
__le64 rt_tsft;
u8 rt_flags;
u8 rt_rate;
@@ -772,7 +772,7 @@ struct hwsim_radiotap_hdr {
} __packed;
struct hwsim_radiotap_ack_hdr {
- struct ieee80211_radiotap_header hdr;
+ struct ieee80211_radiotap_header_fixed hdr;
u8 rt_flags;
u8 pad;
__le16 rt_channel;
@@ -2442,7 +2442,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
if (!data->started || !link_data->beacon_int) {
hrtimer_cancel(&link_data->beacon_timer);
- } else if (!hrtimer_is_queued(&link_data->beacon_timer)) {
+ } else if (!hrtimer_active(&link_data->beacon_timer)) {
u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
u32 bcn_int = link_data->beacon_int;
u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
@@ -2537,7 +2537,7 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
info->enable_beacon, info->beacon_int);
vp->bcn_en = info->enable_beacon;
if (data->started &&
- !hrtimer_is_queued(&link_data->beacon_timer) &&
+ !hrtimer_active(&link_data->beacon_timer) &&
info->enable_beacon) {
u64 tsf, until_tbtt;
u32 bcn_int;
@@ -2594,10 +2594,11 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
static void
mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
+ struct ieee80211_sta *sta = link_sta->sta;
u32 bw = U32_MAX;
int link_id;
@@ -2607,7 +2608,6 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,
link_id++) {
enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
struct ieee80211_bss_conf *vif_conf;
- struct ieee80211_link_sta *link_sta;
link_sta = rcu_dereference(sta->link[link_id]);
@@ -2659,7 +2659,7 @@ static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
hwsim_check_magic(vif);
hwsim_set_sta_magic(sta);
- mac80211_hwsim_sta_rc_update(hw, vif, sta, 0);
+ mac80211_hwsim_sta_rc_update(hw, vif, &sta->deflink, 0);
if (sta->valid_links) {
WARN(hweight16(sta->valid_links) > 1,
@@ -3961,7 +3961,7 @@ out:
.link_info_changed = mac80211_hwsim_link_info_changed, \
.tx_last_beacon = mac80211_hwsim_tx_last_beacon, \
.sta_notify = mac80211_hwsim_sta_notify, \
- .sta_rc_update = mac80211_hwsim_sta_rc_update, \
+ .link_sta_rc_update = mac80211_hwsim_sta_rc_update, \
.conf_tx = mac80211_hwsim_conf_tx, \
.get_survey = mac80211_hwsim_get_survey, \
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
index 210d84c67ef9..7a9c09cd4fdc 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
@@ -226,7 +226,7 @@ int t7xx_dpmaif_rx_buf_alloc(struct dpmaif_ctrl *dpmaif_ctrl,
return 0;
err_unmap_skbs:
- while (--i > 0)
+ while (i--)
t7xx_unmap_bat_skb(dpmaif_ctrl->dev, bat_req->bat_skb, i);
return ret;
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index 79f17100f70b..7968e208dd37 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -198,6 +198,7 @@ int t7xx_reset_device(struct t7xx_pci_dev *t7xx_dev, enum reset_type type)
pci_save_state(t7xx_dev->pdev);
t7xx_pci_reprobe_early(t7xx_dev);
t7xx_mode_update(t7xx_dev, T7XX_RESET);
+ WRITE_ONCE(t7xx_dev->debug_ports_show, false);
if (type == FLDR) {
ret = t7xx_acpi_reset(t7xx_dev, "_RST");
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c
index e556e5bd49ab..7b8c17b029c7 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.c
+++ b/drivers/net/wwan/t7xx/t7xx_pci.c
@@ -41,6 +41,7 @@
#include "t7xx_pcie_mac.h"
#include "t7xx_reg.h"
#include "t7xx_state_monitor.h"
+#include "t7xx_port_proxy.h"
#define T7XX_PCI_IREG_BASE 0
#define T7XX_PCI_EREG_BASE 2
@@ -120,13 +121,58 @@ static ssize_t t7xx_mode_show(struct device *dev,
static DEVICE_ATTR_RW(t7xx_mode);
-static struct attribute *t7xx_mode_attr[] = {
+static ssize_t t7xx_debug_ports_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct t7xx_pci_dev *t7xx_dev;
+ struct pci_dev *pdev;
+ bool show;
+ int ret;
+
+ pdev = to_pci_dev(dev);
+ t7xx_dev = pci_get_drvdata(pdev);
+ if (!t7xx_dev)
+ return -ENODEV;
+
+ ret = kstrtobool(buf, &show);
+ if (ret < 0)
+ return ret;
+
+ t7xx_proxy_debug_ports_show(t7xx_dev, show);
+ WRITE_ONCE(t7xx_dev->debug_ports_show, show);
+
+ return count;
+};
+
+static ssize_t t7xx_debug_ports_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct t7xx_pci_dev *t7xx_dev;
+ struct pci_dev *pdev;
+ bool show;
+
+ pdev = to_pci_dev(dev);
+ t7xx_dev = pci_get_drvdata(pdev);
+ if (!t7xx_dev)
+ return -ENODEV;
+
+ show = READ_ONCE(t7xx_dev->debug_ports_show);
+
+ return sysfs_emit(buf, "%d\n", show);
+}
+
+static DEVICE_ATTR_RW(t7xx_debug_ports);
+
+static struct attribute *t7xx_attr[] = {
&dev_attr_t7xx_mode.attr,
+ &dev_attr_t7xx_debug_ports.attr,
NULL
};
-static const struct attribute_group t7xx_mode_attribute_group = {
- .attrs = t7xx_mode_attr,
+static const struct attribute_group t7xx_attribute_group = {
+ .attrs = t7xx_attr,
};
void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode)
@@ -839,7 +885,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
t7xx_pcie_mac_interrupts_dis(t7xx_dev);
ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj,
- &t7xx_mode_attribute_group);
+ &t7xx_attribute_group);
if (ret)
goto err_md_exit;
@@ -855,7 +901,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_remove_group:
sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
- &t7xx_mode_attribute_group);
+ &t7xx_attribute_group);
err_md_exit:
t7xx_md_exit(t7xx_dev);
@@ -870,7 +916,7 @@ static void t7xx_pci_remove(struct pci_dev *pdev)
t7xx_dev = pci_get_drvdata(pdev);
sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
- &t7xx_mode_attribute_group);
+ &t7xx_attribute_group);
t7xx_md_exit(t7xx_dev);
for (i = 0; i < EXT_INT_NUM; i++) {
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h
index cd8ea17c2644..b25d867e72d2 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.h
+++ b/drivers/net/wwan/t7xx/t7xx_pci.h
@@ -94,6 +94,7 @@ struct t7xx_pci_dev {
struct dentry *debugfs_dir;
#endif
u32 mode;
+ bool debug_ports_show;
};
enum t7xx_pm_id {
diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index f74d3bab810d..9f5d6d288c97 100644
--- a/drivers/net/wwan/t7xx/t7xx_port.h
+++ b/drivers/net/wwan/t7xx/t7xx_port.h
@@ -42,6 +42,8 @@ enum port_ch {
/* to AP */
PORT_CH_AP_CONTROL_RX = 0x1000,
PORT_CH_AP_CONTROL_TX = 0x1001,
+ PORT_CH_AP_ADB_RX = 0x100a,
+ PORT_CH_AP_ADB_TX = 0x100b,
/* to MD */
PORT_CH_CONTROL_RX = 0x2000,
@@ -100,6 +102,7 @@ struct t7xx_port_conf {
struct port_ops *ops;
char *name;
enum wwan_port_type port_type;
+ bool debug;
};
struct t7xx_port {
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index 35743e7de0c3..4fc131f9632f 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -38,7 +38,8 @@
#include "t7xx_state_monitor.h"
#define Q_IDX_CTRL 0
-#define Q_IDX_MBIM 2
+#define Q_IDX_MBIM_MIPC 2
+#define Q_IDX_ADB 3
#define Q_IDX_AT_CMD 5
#define INVALID_SEQ_NUM GENMASK(15, 0)
@@ -66,8 +67,8 @@ static const struct t7xx_port_conf t7xx_port_conf[] = {
}, {
.tx_ch = PORT_CH_MBIM_TX,
.rx_ch = PORT_CH_MBIM_RX,
- .txq_index = Q_IDX_MBIM,
- .rxq_index = Q_IDX_MBIM,
+ .txq_index = Q_IDX_MBIM_MIPC,
+ .rxq_index = Q_IDX_MBIM_MIPC,
.path_id = CLDMA_ID_MD,
.ops = &wwan_sub_port_ops,
.name = "MBIM",
@@ -100,7 +101,27 @@ static const struct t7xx_port_conf t7xx_port_conf[] = {
.path_id = CLDMA_ID_AP,
.ops = &ctl_port_ops,
.name = "t7xx_ap_ctrl",
- },
+ }, {
+ .tx_ch = PORT_CH_AP_ADB_TX,
+ .rx_ch = PORT_CH_AP_ADB_RX,
+ .txq_index = Q_IDX_ADB,
+ .rxq_index = Q_IDX_ADB,
+ .path_id = CLDMA_ID_AP,
+ .ops = &wwan_sub_port_ops,
+ .name = "adb",
+ .port_type = WWAN_PORT_ADB,
+ .debug = true,
+ }, {
+ .tx_ch = PORT_CH_MIPC_TX,
+ .rx_ch = PORT_CH_MIPC_RX,
+ .txq_index = Q_IDX_MBIM_MIPC,
+ .rxq_index = Q_IDX_MBIM_MIPC,
+ .path_id = CLDMA_ID_MD,
+ .ops = &wwan_sub_port_ops,
+ .name = "mipc",
+ .port_type = WWAN_PORT_MIPC,
+ .debug = true,
+ }
};
static const struct t7xx_port_conf t7xx_early_port_conf[] = {
@@ -505,13 +526,33 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
spin_lock_init(&port->port_update_lock);
port->chan_enable = false;
- if (port_conf->ops && port_conf->ops->init)
+ if (!port_conf->debug &&
+ port_conf->ops &&
+ port_conf->ops->init)
port_conf->ops->init(port);
}
t7xx_proxy_setup_ch_mapping(port_prox);
}
+void t7xx_proxy_debug_ports_show(struct t7xx_pci_dev *t7xx_dev, bool show)
+{
+ struct port_proxy *port_prox = t7xx_dev->md->port_prox;
+ struct t7xx_port *port;
+ int i;
+
+ for_each_proxy_port(i, port, port_prox) {
+ const struct t7xx_port_conf *port_conf = port->port_conf;
+
+ if (port_conf->debug && port_conf->ops) {
+ if (show && port_conf->ops->init)
+ port_conf->ops->init(port);
+ else if (!show && port_conf->ops->uninit)
+ port_conf->ops->uninit(port);
+ }
+ }
+}
+
void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id)
{
struct port_proxy *port_prox = md->port_prox;
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index 7f5706811445..f0918b36e899 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -98,6 +98,7 @@ extern struct port_ops ctl_port_ops;
extern struct port_ops t7xx_trace_port_ops;
#endif
+void t7xx_proxy_debug_ports_show(struct t7xx_pci_dev *t7xx_dev, bool show);
void t7xx_port_proxy_reset(struct port_proxy *port_prox);
void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
int t7xx_port_proxy_init(struct t7xx_modem *md);
diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
index 4b23ba693f3f..7fc569565ff9 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -169,7 +169,9 @@ static int t7xx_port_wwan_init(struct t7xx_port *port)
{
const struct t7xx_port_conf *port_conf = port->port_conf;
- if (port_conf->port_type == WWAN_PORT_FASTBOOT)
+ if (port_conf->port_type == WWAN_PORT_FASTBOOT ||
+ port_conf->port_type == WWAN_PORT_ADB ||
+ port_conf->port_type == WWAN_PORT_MIPC)
t7xx_port_wwan_create(port);
port->rx_length_th = RX_QUEUE_MAXLEN;
@@ -224,7 +226,9 @@ static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int
{
const struct t7xx_port_conf *port_conf = port->port_conf;
- if (port_conf->port_type == WWAN_PORT_FASTBOOT)
+ if (port_conf->port_type == WWAN_PORT_FASTBOOT ||
+ port_conf->port_type == WWAN_PORT_ADB ||
+ port_conf->port_type == WWAN_PORT_MIPC)
return;
if (state != MD_STATE_READY)
diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index 65a7ed4d6766..a51e2755991a 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -334,6 +334,14 @@ static const struct {
.name = "FASTBOOT",
.devsuf = "fastboot",
},
+ [WWAN_PORT_ADB] = {
+ .name = "ADB",
+ .devsuf = "adb",
+ },
+ [WWAN_PORT_MIPC] = {
+ .name = "MIPC",
+ .devsuf = "mipc",
+ },
};
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
@@ -431,7 +439,7 @@ static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt)
return -ENFILE;
}
- return dev_set_name(&port->dev, buf);
+ return dev_set_name(&port->dev, "%s", buf);
}
struct wwan_port *wwan_create_port(struct device *parent,
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 84cb859a911d..855b42c92284 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -92,6 +92,17 @@ MODULE_PARM_DESC(apst_secondary_latency_tol_us,
"secondary APST latency tolerance in us");
/*
+ * Older kernels didn't enable protection information if it was at an offset.
+ * Newer kernels do, so it breaks reads on the upgrade if such formats were
+ * used in prior kernels since the metadata written did not contain a valid
+ * checksum.
+ */
+static bool disable_pi_offsets = false;
+module_param(disable_pi_offsets, bool, 0444);
+MODULE_PARM_DESC(disable_pi_offsets,
+ "disable protection information if it has an offset");
+
+/*
* nvme_wq - hosts nvme related works that are not reset or delete
* nvme_reset_wq - hosts nvme reset works
* nvme_delete_wq - hosts nvme delete works
@@ -1390,17 +1401,30 @@ static void nvme_update_keep_alive(struct nvme_ctrl *ctrl,
nvme_start_keep_alive(ctrl);
}
-/*
- * In NVMe 1.0 the CNS field was just a binary controller or namespace
- * flag, thus sending any new CNS opcodes has a big chance of not working.
- * Qemu unfortunately had that bug after reporting a 1.1 version compliance
- * (but not for any later version).
- */
-static bool nvme_ctrl_limited_cns(struct nvme_ctrl *ctrl)
+static bool nvme_id_cns_ok(struct nvme_ctrl *ctrl, u8 cns)
{
- if (ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)
- return ctrl->vs < NVME_VS(1, 2, 0);
- return ctrl->vs < NVME_VS(1, 1, 0);
+ /*
+ * The CNS field occupies a full byte starting with NVMe 1.2
+ */
+ if (ctrl->vs >= NVME_VS(1, 2, 0))
+ return true;
+
+ /*
+ * NVMe 1.1 expanded the CNS value to two bits, which means values
+ * larger than that could get truncated and treated as an incorrect
+ * value.
+ *
+ * Qemu implemented 1.0 behavior for controllers claiming 1.1
+ * compliance, so they need to be quirked here.
+ */
+ if (ctrl->vs >= NVME_VS(1, 1, 0) &&
+ !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS))
+ return cns <= 3;
+
+ /*
+ * NVMe 1.0 used a single bit for the CNS value.
+ */
+ return cns <= 1;
}
static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
@@ -1913,8 +1937,12 @@ static void nvme_configure_metadata(struct nvme_ctrl *ctrl,
if (head->pi_size && head->ms >= head->pi_size)
head->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
- if (!(id->dps & NVME_NS_DPS_PI_FIRST))
- info->pi_offset = head->ms - head->pi_size;
+ if (!(id->dps & NVME_NS_DPS_PI_FIRST)) {
+ if (disable_pi_offsets)
+ head->pi_type = 0;
+ else
+ info->pi_offset = head->ms - head->pi_size;
+ }
if (ctrl->ops->flags & NVME_F_FABRICS) {
/*
@@ -3104,7 +3132,7 @@ static int nvme_init_non_mdts_limits(struct nvme_ctrl *ctrl)
ctrl->max_zeroes_sectors = 0;
if (ctrl->subsys->subtype != NVME_NQN_NVME ||
- nvme_ctrl_limited_cns(ctrl) ||
+ !nvme_id_cns_ok(ctrl, NVME_ID_CNS_CS_CTRL) ||
test_bit(NVME_CTRL_SKIP_ID_CNS_CS, &ctrl->flags))
return 0;
@@ -3767,7 +3795,8 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu)) {
if (ns->head->ns_id == nsid) {
if (!nvme_get_ns(ns))
continue;
@@ -4200,7 +4229,7 @@ static void nvme_scan_work(struct work_struct *work)
}
mutex_lock(&ctrl->scan_lock);
- if (nvme_ctrl_limited_cns(ctrl)) {
+ if (!nvme_id_cns_ok(ctrl, NVME_ID_CNS_NS_ACTIVE_LIST)) {
nvme_scan_ns_sequential(ctrl);
} else {
/*
@@ -4851,7 +4880,8 @@ void nvme_mark_namespaces_dead(struct nvme_ctrl *ctrl)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu))
blk_mark_disk_dead(ns->disk);
srcu_read_unlock(&ctrl->srcu, srcu_idx);
}
@@ -4863,7 +4893,8 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu))
blk_mq_unfreeze_queue(ns->queue);
srcu_read_unlock(&ctrl->srcu, srcu_idx);
clear_bit(NVME_CTRL_FROZEN, &ctrl->flags);
@@ -4876,7 +4907,8 @@ int nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list) {
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu)) {
timeout = blk_mq_freeze_queue_wait_timeout(ns->queue, timeout);
if (timeout <= 0)
break;
@@ -4892,7 +4924,8 @@ void nvme_wait_freeze(struct nvme_ctrl *ctrl)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu))
blk_mq_freeze_queue_wait(ns->queue);
srcu_read_unlock(&ctrl->srcu, srcu_idx);
}
@@ -4905,7 +4938,8 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl)
set_bit(NVME_CTRL_FROZEN, &ctrl->flags);
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu))
blk_freeze_queue_start(ns->queue);
srcu_read_unlock(&ctrl->srcu, srcu_idx);
}
@@ -4953,7 +4987,8 @@ void nvme_sync_io_queues(struct nvme_ctrl *ctrl)
int srcu_idx;
srcu_idx = srcu_read_lock(&ctrl->srcu);
- list_for_each_entry_rcu(ns, &ctrl->namespaces, list)
+ list_for_each_entry_srcu(ns, &ctrl->namespaces, list,
+ srcu_read_lock_held(&ctrl->srcu))
blk_sync_queue(ns->queue);
srcu_read_unlock(&ctrl->srcu, srcu_idx);
}
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index b9b79ccfabf8..a96976b22fa7 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -421,10 +421,13 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
struct io_uring_cmd *ioucmd = req->end_io_data;
struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
- if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
+ if (nvme_req(req)->flags & NVME_REQ_CANCELLED) {
pdu->status = -EINTR;
- else
+ } else {
pdu->status = nvme_req(req)->status;
+ if (!pdu->status)
+ pdu->status = blk_status_to_errno(err);
+ }
pdu->result = le64_to_cpu(nvme_req(req)->result.u64);
/*
diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c
index 29f8639cfe7f..b47d675232d2 100644
--- a/drivers/nvme/target/auth.c
+++ b/drivers/nvme/target/auth.c
@@ -115,6 +115,7 @@ int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id)
pr_debug("%s: ctrl %d failed to generate private key, err %d\n",
__func__, ctrl->cntlid, ret);
kfree_sensitive(ctrl->dh_key);
+ ctrl->dh_key = NULL;
return ret;
}
ctrl->dh_keysize = crypto_kpp_maxsize(ctrl->dh_tfm);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 7d85c04fbba2..225a6cd2e9ca 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1067,8 +1067,15 @@ static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps)
static void pci_enable_acs(struct pci_dev *dev)
{
struct pci_acs caps;
+ bool enable_acs = false;
int pos;
+ /* If an iommu is present we start with kernel default caps */
+ if (pci_acs_enable) {
+ if (pci_dev_specific_enable_acs(dev))
+ enable_acs = true;
+ }
+
pos = dev->acs_cap;
if (!pos)
return;
@@ -1077,11 +1084,8 @@ static void pci_enable_acs(struct pci_dev *dev)
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &caps.ctrl);
caps.fw_ctrl = caps.ctrl;
- /* If an iommu is present we start with kernel default caps */
- if (pci_acs_enable) {
- if (pci_dev_specific_enable_acs(dev))
- pci_std_enable_acs(dev, &caps);
- }
+ if (enable_acs)
+ pci_std_enable_acs(dev, &caps);
/*
* Always apply caps from the command line, even if there is no iommu.
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4f68414c3086..f1615805f5b0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -3105,7 +3105,9 @@ int pci_host_probe(struct pci_host_bridge *bridge)
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
+ pci_lock_rescan_remove();
pci_bus_add_devices(bus);
+ pci_unlock_rescan_remove();
return 0;
}
EXPORT_SYMBOL_GPL(pci_host_probe);
diff --git a/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c b/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
index a23a4312574b..0e6bd47671c2 100644
--- a/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
+++ b/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c
@@ -6,9 +6,9 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/pci-pwrctl.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/pwrseq/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -18,6 +18,40 @@ struct pci_pwrctl_pwrseq_data {
struct pwrseq_desc *pwrseq;
};
+struct pci_pwrctl_pwrseq_pdata {
+ const char *target;
+ /*
+ * Called before doing anything else to perform device-specific
+ * verification between requesting the power sequencing handle.
+ */
+ int (*validate_device)(struct device *dev);
+};
+
+static int pci_pwrctl_pwrseq_qcm_wcn_validate_device(struct device *dev)
+{
+ /*
+ * Old device trees for some platforms already define wifi nodes for
+ * the WCN family of chips since before power sequencing was added
+ * upstream.
+ *
+ * These nodes don't consume the regulator outputs from the PMU, and
+ * if we allow this driver to bind to one of such "incomplete" nodes,
+ * we'll see a kernel log error about the indefinite probe deferral.
+ *
+ * Check the existence of the regulator supply that exists on all
+ * WCN models before moving forward.
+ */
+ if (!device_property_present(dev, "vddaon-supply"))
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct pci_pwrctl_pwrseq_pdata pci_pwrctl_pwrseq_qcom_wcn_pdata = {
+ .target = "wlan",
+ .validate_device = pci_pwrctl_pwrseq_qcm_wcn_validate_device,
+};
+
static void devm_pci_pwrctl_pwrseq_power_off(void *data)
{
struct pwrseq_desc *pwrseq = data;
@@ -27,15 +61,26 @@ static void devm_pci_pwrctl_pwrseq_power_off(void *data)
static int pci_pwrctl_pwrseq_probe(struct platform_device *pdev)
{
+ const struct pci_pwrctl_pwrseq_pdata *pdata;
struct pci_pwrctl_pwrseq_data *data;
struct device *dev = &pdev->dev;
int ret;
+ pdata = device_get_match_data(dev);
+ if (!pdata || !pdata->target)
+ return -EINVAL;
+
+ if (pdata->validate_device) {
+ ret = pdata->validate_device(dev);
+ if (ret)
+ return ret;
+ }
+
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->pwrseq = devm_pwrseq_get(dev, of_device_get_match_data(dev));
+ data->pwrseq = devm_pwrseq_get(dev, pdata->target);
if (IS_ERR(data->pwrseq))
return dev_err_probe(dev, PTR_ERR(data->pwrseq),
"Failed to get the power sequencer\n");
@@ -64,17 +109,17 @@ static const struct of_device_id pci_pwrctl_pwrseq_of_match[] = {
{
/* ATH11K in QCA6390 package. */
.compatible = "pci17cb,1101",
- .data = "wlan",
+ .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata,
},
{
/* ATH11K in WCN6855 package. */
.compatible = "pci17cb,1103",
- .data = "wlan",
+ .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata,
},
{
/* ATH12K in WCN7850 package. */
.compatible = "pci17cb,1107",
- .data = "wlan",
+ .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata,
},
{ }
};
diff --git a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
index 4c10cafded4e..950b7ae1d1a8 100644
--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
+++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
@@ -153,7 +153,9 @@ static void xhci_soft_reset(struct brcm_usb_init_params *params,
} else {
USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
/* Required for COMMONONN to be set */
- USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG, U2_FREECLK_EXISTS);
+ if (params->supported_port_modes != USB_CTLR_MODE_DRD)
+ USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG,
+ U2_FREECLK_EXISTS);
}
}
@@ -328,8 +330,12 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params)
/* 1 millisecond - for USB clocks to settle down */
usleep_range(1000, 2000);
- /* Disable PHY when port is suspended */
- USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN);
+ /*
+ * Disable PHY when port is suspended
+ * Does not work in DRD mode
+ */
+ if (params->supported_port_modes != USB_CTLR_MODE_DRD)
+ USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN);
usb_wake_enable_7216(params, false);
usb_init_common(params);
diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.c b/drivers/phy/broadcom/phy-brcm-usb-init.c
index 39536b6d96a9..5ebb3a616115 100644
--- a/drivers/phy/broadcom/phy-brcm-usb-init.c
+++ b/drivers/phy/broadcom/phy-brcm-usb-init.c
@@ -220,6 +220,8 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
0, /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
+ 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */
+ 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */
0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c
index aeec6eb6be23..dfc4f55d112e 100644
--- a/drivers/phy/cadence/phy-cadence-sierra.c
+++ b/drivers/phy/cadence/phy-cadence-sierra.c
@@ -174,8 +174,9 @@
#define SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG 0x150
#define SIERRA_DEQ_TAU_CTRL2_PREG 0x151
#define SIERRA_DEQ_TAU_CTRL3_PREG 0x152
-#define SIERRA_DEQ_OPENEYE_CTRL_PREG 0x158
+#define SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG 0x158
#define SIERRA_DEQ_CONCUR_EPIOFFSET_MODE_PREG 0x159
+#define SIERRA_DEQ_OPENEYE_CTRL_PREG 0x15C
#define SIERRA_DEQ_PICTRL_PREG 0x161
#define SIERRA_CPICAL_TMRVAL_MODE1_PREG 0x170
#define SIERRA_CPICAL_TMRVAL_MODE0_PREG 0x171
@@ -1733,7 +1734,7 @@ static const struct cdns_reg_pairs ml_pcie_100_no_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -1797,7 +1798,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_no_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -1874,7 +1875,7 @@ static const struct cdns_reg_pairs ml_pcie_100_int_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -1941,7 +1942,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_int_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -2012,7 +2013,7 @@ static const struct cdns_reg_pairs ml_pcie_100_ext_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -2079,7 +2080,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_ext_ssc_ln_regs[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -2140,7 +2141,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_no_ssc[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -2215,7 +2216,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_int_ssc[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
@@ -2284,7 +2285,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_ext_ssc[] = {
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
- {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
+ {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG},
{0x002B, SIERRA_CPI_TRIM_PREG},
{0x0003, SIERRA_EPI_CTRL_PREG},
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
index 11fcb1867118..e98361dcdead 100644
--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
@@ -141,11 +141,6 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
IMX8MM_GPR_PCIE_REF_CLK_PLL);
usleep_range(100, 200);
- /* Do the PHY common block reset */
- regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
- IMX8MM_GPR_PCIE_CMN_RST,
- IMX8MM_GPR_PCIE_CMN_RST);
-
switch (imx8_phy->drvdata->variant) {
case IMX8MP:
reset_control_deassert(imx8_phy->perst);
@@ -156,6 +151,11 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
break;
}
+ /* Do the PHY common block reset */
+ regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
+ IMX8MM_GPR_PCIE_CMN_RST,
+ IMX8MM_GPR_PCIE_CMN_RST);
+
/* Polling to check the phy is ready or not. */
ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG075,
val, val == ANA_PLL_DONE, 10, 20000);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index a8adc3214bfe..643045c9024e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -3673,6 +3673,7 @@ static int qmp_combo_probe(struct platform_device *pdev)
return -ENOMEM;
qmp->dev = dev;
+ dev_set_drvdata(dev, qmp);
qmp->orientation = TYPEC_ORIENTATION_NORMAL;
@@ -3749,8 +3750,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
phy_set_drvdata(qmp->dp_phy, qmp);
- dev_set_drvdata(dev, qmp);
-
if (usb_np == dev->of_node)
phy_provider = devm_of_phy_provider_register(dev, qmp_combo_phy_xlate);
else
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index f71787fb4d7e..36aaac34e6c6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -3661,8 +3661,8 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x2_pciephy_cfg = {
.reset_list = sdm845_pciephy_reset_l,
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
- .vreg_list = sm8550_qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = pciephy_v6_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
@@ -3695,8 +3695,8 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x4_pciephy_cfg = {
.reset_list = sdm845_pciephy_reset_l,
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
- .vreg_list = sm8550_qmp_phy_vreg_l,
- .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = pciephy_v6_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
index 6d0ba39c1943..8bf951b0490c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c
@@ -1248,6 +1248,7 @@ static int qmp_usb_legacy_probe(struct platform_device *pdev)
return -ENOMEM;
qmp->dev = dev;
+ dev_set_drvdata(dev, qmp);
qmp->cfg = of_device_get_match_data(dev);
if (!qmp->cfg)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index 2fd49355aa37..1246d3bc8b92 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -2179,6 +2179,7 @@ static int qmp_usb_probe(struct platform_device *pdev)
return -ENOMEM;
qmp->dev = dev;
+ dev_set_drvdata(dev, qmp);
qmp->cfg = of_device_get_match_data(dev);
if (!qmp->cfg)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index d4fa1063ea61..cf12a6f12134 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -1050,6 +1050,7 @@ static int qmp_usbc_probe(struct platform_device *pdev)
return -ENOMEM;
qmp->dev = dev;
+ dev_set_drvdata(dev, qmp);
qmp->orientation = TYPEC_ORIENTATION_NORMAL;
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 490263375057..2f7a05f21dc5 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -86,6 +86,7 @@ config PHY_ROCKCHIP_PCIE
config PHY_ROCKCHIP_SAMSUNG_HDPTX
tristate "Rockchip Samsung HDMI/eDP Combo PHY driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
+ depends on COMMON_CLK
depends on HAS_IOMEM
select GENERIC_PHY
select MFD_SYSCON
diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c
index 633912f8a05d..cb5454fbe2c8 100644
--- a/drivers/phy/starfive/phy-jh7110-usb.c
+++ b/drivers/phy/starfive/phy-jh7110-usb.c
@@ -10,18 +10,24 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/usb/of.h>
#define USB_125M_CLK_RATE 125000000
#define USB_LS_KEEPALIVE_OFF 0x4
#define USB_LS_KEEPALIVE_ENABLE BIT(4)
+#define USB_PDRSTN_SPLIT BIT(17)
+#define SYSCON_USB_SPLIT_OFFSET 0x18
+
struct jh7110_usb2_phy {
struct phy *phy;
void __iomem *regs;
+ struct regmap *sys_syscon;
struct clk *usb_125m_clk;
struct clk *app_125m;
enum phy_mode mode;
@@ -61,6 +67,10 @@ static int usb2_phy_set_mode(struct phy *_phy,
usb2_set_ls_keepalive(phy, (mode != PHY_MODE_USB_DEVICE));
}
+ /* Connect usb 2.0 phy mode */
+ regmap_update_bits(phy->sys_syscon, SYSCON_USB_SPLIT_OFFSET,
+ USB_PDRSTN_SPLIT, USB_PDRSTN_SPLIT);
+
return 0;
}
@@ -129,6 +139,12 @@ static int jh7110_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy->phy, phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ phy->sys_syscon =
+ syscon_regmap_lookup_by_compatible("starfive,jh7110-sys-syscon");
+ if (IS_ERR(phy->sys_syscon))
+ return dev_err_probe(dev, PTR_ERR(phy->sys_syscon),
+ "Failed to get sys-syscon\n");
+
return PTR_ERR_OR_ZERO(phy_provider);
}
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index cfdb54b6070a..342f5ccf611d 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -699,6 +699,8 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
return -ENOMEM;
lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
+ if (IS_ERR(lane))
+ return PTR_ERR(lane);
/*
* Assign phy dev to usb-phy dev. Host/device drivers can use phy
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index a6c0c5607ffd..c6e846d385d2 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -450,8 +450,8 @@ static int wiz_mode_select(struct wiz *wiz)
} else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) {
ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3);
ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3);
- ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3);
- mode = LANE_MODE_GEN1;
+ ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x2);
+ mode = LANE_MODE_GEN2;
} else {
continue;
}
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
index bbb8edb62e00..5669f94c3d06 100644
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -998,6 +998,11 @@ static int amd_pmc_s2d_init(struct amd_pmc_dev *dev)
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->s2d_msg_id, true);
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->s2d_msg_id, true);
+ if (!phys_addr_hi && !phys_addr_low) {
+ dev_err(dev->dev, "STB is not enabled on the system; disable enable_stb or contact system vendor\n");
+ return -EINVAL;
+ }
+
stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);
/* Clear msg_port for other SMU operation */
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index d6af0ca036f1..347bb43a5f2b 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -261,6 +261,7 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
dev->mtable_size = sizeof(dev->m_table);
break;
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
dev->mtable_size = sizeof(dev->m_table_v2);
break;
default:
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index b5183969f9bf..06226eb0eab3 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -86,6 +86,7 @@ static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ta
ARRAY_SIZE(dev->m_table.avg_core_c0residency), in);
break;
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
in->ev_info.socket_power = dev->m_table_v2.apu_power + dev->m_table_v2.dgpu_power;
in->ev_info.skin_temperature = dev->m_table_v2.skin_temp;
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 7a48220b4f5a..abdca3f05c5c 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -3908,6 +3908,16 @@ static int platform_profile_setup(struct asus_wmi *asus)
if (!asus->throttle_thermal_policy_dev)
return 0;
+ /*
+ * We need to set the default thermal profile during probe or otherwise
+ * the system will often remain in silent mode, causing low performance.
+ */
+ err = throttle_thermal_policy_set_default(asus);
+ if (err < 0) {
+ pr_warn("Failed to set default thermal profile\n");
+ return err;
+ }
+
dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n");
asus->platform_profile_handler.profile_get = asus_wmi_platform_profile_get;
diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c
index 73e41eb69cb5..01c72b91a50d 100644
--- a/drivers/platform/x86/dell/dell-smbios-base.c
+++ b/drivers/platform/x86/dell/dell-smbios-base.c
@@ -576,6 +576,7 @@ static int __init dell_smbios_init(void)
int ret, wmi, smm;
if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
+ !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Alienware", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
pr_err("Unable to run on non-Dell system\n");
return -ENODEV;
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 502783a7adb1..841a5414d28a 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -80,6 +80,12 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
static const struct key_entry dell_wmi_keymap_type_0000[] = {
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
+ /* Meta key lock */
+ { KE_IGNORE, 0xe000, { KEY_RIGHTMETA } },
+
+ /* Meta key unlock */
+ { KE_IGNORE, 0xe001, { KEY_RIGHTMETA } },
+
/* Key code is followed by brightness level */
{ KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
@@ -264,6 +270,15 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
/*Speaker Mute*/
{ KE_KEY, 0x109, { KEY_MUTE} },
+ /* S2Idle screen off */
+ { KE_IGNORE, 0x120, { KEY_RESERVED }},
+
+ /* Leaving S4 or S2Idle suspend */
+ { KE_IGNORE, 0x130, { KEY_RESERVED }},
+
+ /* Entering S2Idle suspend */
+ { KE_IGNORE, 0x140, { KEY_RESERVED }},
+
/* Mic mute */
{ KE_KEY, 0x150, { KEY_MICMUTE } },
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index c64dfc56651d..c908f52ed717 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1294,6 +1294,9 @@ static const struct key_entry ideapad_keymap[] = {
{ KE_KEY, 0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } },
/* Refresh Rate Toggle */
{ KE_KEY, 0x0a | IDEAPAD_WMI_KEY, { KEY_REFRESH_RATE_TOGGLE } },
+ /* Specific to some newer models */
+ { KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } },
+ { KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } },
{ KE_END },
};
diff --git a/drivers/platform/x86/intel/pmc/adl.c b/drivers/platform/x86/intel/pmc/adl.c
index 9d9c07f44ff6..e7878558fd90 100644
--- a/drivers/platform/x86/intel/pmc/adl.c
+++ b/drivers/platform/x86/intel/pmc/adl.c
@@ -295,8 +295,6 @@ const struct pmc_reg_map adl_reg_map = {
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
- .acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
.ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
.lpm_num_modes = ADL_LPM_NUM_MODES,
.lpm_num_maps = ADL_LPM_NUM_MAPS,
diff --git a/drivers/platform/x86/intel/pmc/cnp.c b/drivers/platform/x86/intel/pmc/cnp.c
index 513c02670c5a..dd72974bf71e 100644
--- a/drivers/platform/x86/intel/pmc/cnp.c
+++ b/drivers/platform/x86/intel/pmc/cnp.c
@@ -200,8 +200,6 @@ const struct pmc_reg_map cnp_reg_map = {
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
- .acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
.ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
.etr3_offset = ETR3_OFFSET,
};
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index ecb47f8b4f83..4e9c8c96c8cc 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -11,7 +11,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/acpi_pmtmr.h>
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -1258,39 +1257,6 @@ static bool pmc_core_is_pson_residency_enabled(struct pmc_dev *pmcdev)
return val == 1;
}
-/*
- * Enable or disable ACPI PM Timer
- *
- * This function is intended to be a callback for ACPI PM suspend/resume event.
- * The ACPI PM Timer is enabled on resume only if it was enabled during suspend.
- */
-static void pmc_core_acpi_pm_timer_suspend_resume(void *data, bool suspend)
-{
- struct pmc_dev *pmcdev = data;
- struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
- const struct pmc_reg_map *map = pmc->map;
- bool enabled;
- u32 reg;
-
- if (!map->acpi_pm_tmr_ctl_offset)
- return;
-
- guard(mutex)(&pmcdev->lock);
-
- if (!suspend && !pmcdev->enable_acpi_pm_timer_on_resume)
- return;
-
- reg = pmc_core_reg_read(pmc, map->acpi_pm_tmr_ctl_offset);
- enabled = !(reg & map->acpi_pm_tmr_disable_bit);
- if (suspend)
- reg |= map->acpi_pm_tmr_disable_bit;
- else
- reg &= ~map->acpi_pm_tmr_disable_bit;
- pmc_core_reg_write(pmc, map->acpi_pm_tmr_ctl_offset, reg);
-
- pmcdev->enable_acpi_pm_timer_on_resume = suspend && enabled;
-}
-
static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
{
debugfs_remove_recursive(pmcdev->dbgfs_dir);
@@ -1486,7 +1452,6 @@ static int pmc_core_probe(struct platform_device *pdev)
struct pmc_dev *pmcdev;
const struct x86_cpu_id *cpu_id;
int (*core_init)(struct pmc_dev *pmcdev);
- const struct pmc_reg_map *map;
struct pmc *primary_pmc;
int ret;
@@ -1545,11 +1510,6 @@ static int pmc_core_probe(struct platform_device *pdev)
pm_report_max_hw_sleep(FIELD_MAX(SLP_S0_RES_COUNTER_MASK) *
pmc_core_adjust_slp_s0_step(primary_pmc, 1));
- map = primary_pmc->map;
- if (map->acpi_pm_tmr_ctl_offset)
- acpi_pmtmr_register_suspend_resume_callback(pmc_core_acpi_pm_timer_suspend_resume,
- pmcdev);
-
device_initialized = true;
dev_info(&pdev->dev, " initialized\n");
@@ -1559,12 +1519,6 @@ static int pmc_core_probe(struct platform_device *pdev)
static void pmc_core_remove(struct platform_device *pdev)
{
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
- const struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
- const struct pmc_reg_map *map = pmc->map;
-
- if (map->acpi_pm_tmr_ctl_offset)
- acpi_pmtmr_unregister_suspend_resume_callback();
-
pmc_core_dbgfs_unregister(pmcdev);
pmc_core_clean_structure(pdev);
}
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 75fd593a7b0f..b9d3291d0bf2 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -68,8 +68,6 @@ struct telem_endpoint;
#define SPT_PMC_LTR_SCC 0x3A0
#define SPT_PMC_LTR_ISH 0x3A4
-#define SPT_PMC_ACPI_PM_TMR_CTL_OFFSET 0x18FC
-
/* Sunrise Point: PGD PFET Enable Ack Status Registers */
enum ppfear_regs {
SPT_PMC_XRAM_PPFEAR0A = 0x590,
@@ -150,8 +148,6 @@ enum ppfear_regs {
#define SPT_PMC_VRIC1_SLPS0LVEN BIT(13)
#define SPT_PMC_VRIC1_XTALSDQDIS BIT(22)
-#define SPT_PMC_BIT_ACPI_PM_TMR_DISABLE BIT(1)
-
/* Cannonlake Power Management Controller register offsets */
#define CNP_PMC_SLPS0_DBG_OFFSET 0x10B4
#define CNP_PMC_PM_CFG_OFFSET 0x1818
@@ -355,8 +351,6 @@ struct pmc_reg_map {
const u8 *lpm_reg_index;
const u32 pson_residency_offset;
const u32 pson_residency_counter_step;
- const u32 acpi_pm_tmr_ctl_offset;
- const u32 acpi_pm_tmr_disable_bit;
};
/**
@@ -432,8 +426,6 @@ struct pmc_dev {
u32 die_c6_offset;
struct telem_endpoint *punit_ep;
struct pmc_info *regmap_list;
-
- bool enable_acpi_pm_timer_on_resume;
};
enum pmc_index {
diff --git a/drivers/platform/x86/intel/pmc/core_ssram.c b/drivers/platform/x86/intel/pmc/core_ssram.c
index c259c96b7dfd..8504154b649f 100644
--- a/drivers/platform/x86/intel/pmc/core_ssram.c
+++ b/drivers/platform/x86/intel/pmc/core_ssram.c
@@ -29,7 +29,7 @@
#define LPM_REG_COUNT 28
#define LPM_MODE_OFFSET 1
-DEFINE_FREE(pmc_core_iounmap, void __iomem *, iounmap(_T));
+DEFINE_FREE(pmc_core_iounmap, void __iomem *, if (_T) iounmap(_T))
static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
{
@@ -262,6 +262,8 @@ pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, int pmc_idx, u32 offset)
ssram_base = ssram_pcidev->resource[0].start;
tmp_ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
+ if (!tmp_ssram)
+ return -ENOMEM;
if (pmc_idx != PMC_IDX_MAIN) {
/*
diff --git a/drivers/platform/x86/intel/pmc/icl.c b/drivers/platform/x86/intel/pmc/icl.c
index cbbd44054468..71b0fd6cb7d8 100644
--- a/drivers/platform/x86/intel/pmc/icl.c
+++ b/drivers/platform/x86/intel/pmc/icl.c
@@ -46,8 +46,6 @@ const struct pmc_reg_map icl_reg_map = {
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
- .acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
.ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
.etr3_offset = ETR3_OFFSET,
};
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
index 91f2fa728f5c..c7d15d864039 100644
--- a/drivers/platform/x86/intel/pmc/mtl.c
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -462,8 +462,6 @@ const struct pmc_reg_map mtl_socm_reg_map = {
.ppfear_buckets = MTL_SOCM_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
- .acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
.lpm_num_maps = ADL_LPM_NUM_MAPS,
.ltr_ignore_max = MTL_SOCM_NUM_IP_IGN_ALLOWED,
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c
index 371b4e30f142..e0580de18077 100644
--- a/drivers/platform/x86/intel/pmc/tgl.c
+++ b/drivers/platform/x86/intel/pmc/tgl.c
@@ -197,8 +197,6 @@ const struct pmc_reg_map tgl_reg_map = {
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
- .acpi_pm_tmr_ctl_offset = SPT_PMC_ACPI_PM_TMR_CTL_OFFSET,
- .acpi_pm_tmr_disable_bit = SPT_PMC_BIT_ACPI_PM_TMR_DISABLE,
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
.lpm_num_maps = TGL_LPM_NUM_MAPS,
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 4c1b0553f872..6371a9f765c1 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -7936,6 +7936,7 @@ static u8 fan_control_resume_level;
static int fan_watchdog_maxinterval;
static bool fan_with_ns_addr;
+static bool ecfw_with_fan_dec_rpm;
static struct mutex fan_mutex;
@@ -8682,7 +8683,11 @@ static ssize_t fan_fan1_input_show(struct device *dev,
if (res < 0)
return res;
- return sysfs_emit(buf, "%u\n", speed);
+ /* Check for fan speeds displayed in hexadecimal */
+ if (!ecfw_with_fan_dec_rpm)
+ return sysfs_emit(buf, "%u\n", speed);
+ else
+ return sysfs_emit(buf, "%x\n", speed);
}
static DEVICE_ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL);
@@ -8699,7 +8704,11 @@ static ssize_t fan_fan2_input_show(struct device *dev,
if (res < 0)
return res;
- return sysfs_emit(buf, "%u\n", speed);
+ /* Check for fan speeds displayed in hexadecimal */
+ if (!ecfw_with_fan_dec_rpm)
+ return sysfs_emit(buf, "%u\n", speed);
+ else
+ return sysfs_emit(buf, "%x\n", speed);
}
static DEVICE_ATTR(fan2_input, S_IRUGO, fan_fan2_input_show, NULL);
@@ -8775,6 +8784,7 @@ static const struct attribute_group fan_driver_attr_group = {
#define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */
#define TPACPI_FAN_NOFAN 0x0008 /* no fan available */
#define TPACPI_FAN_NS 0x0010 /* For EC with non-Standard register addresses */
+#define TPACPI_FAN_DECRPM 0x0020 /* For ECFW's with RPM in register as decimal */
static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
@@ -8803,6 +8813,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_Q_LNV3('R', '1', 'D', TPACPI_FAN_NS), /* 11e Gen5 GL-R */
TPACPI_Q_LNV3('R', '0', 'V', TPACPI_FAN_NS), /* 11e Gen5 KL-Y */
TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
+ TPACPI_Q_LNV3('R', '0', 'Q', TPACPI_FAN_DECRPM),/* L480 */
};
static int __init fan_init(struct ibm_init_struct *iibm)
@@ -8847,6 +8858,13 @@ static int __init fan_init(struct ibm_init_struct *iibm)
tp_features.fan_ctrl_status_undef = 1;
}
+ /* Check for the EC/BIOS with RPM reported in decimal*/
+ if (quirks & TPACPI_FAN_DECRPM) {
+ pr_info("ECFW with fan RPM as decimal in EC register\n");
+ ecfw_with_fan_dec_rpm = 1;
+ tp_features.fan_ctrl_status_undef = 1;
+ }
+
if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -9067,7 +9085,11 @@ static int fan_read(struct seq_file *m)
if (rc < 0)
return rc;
- seq_printf(m, "speed:\t\t%d\n", speed);
+ /* Check for fan speeds displayed in hexadecimal */
+ if (!ecfw_with_fan_dec_rpm)
+ seq_printf(m, "speed:\t\t%d\n", speed);
+ else
+ seq_printf(m, "speed:\t\t%x\n", speed);
if (fan_status_access_mode == TPACPI_FAN_RD_TPEC_NS) {
/*
diff --git a/drivers/powercap/dtpm_devfreq.c b/drivers/powercap/dtpm_devfreq.c
index f40bce8176df..d1dff6ccab12 100644
--- a/drivers/powercap/dtpm_devfreq.c
+++ b/drivers/powercap/dtpm_devfreq.c
@@ -178,7 +178,7 @@ static int __dtpm_devfreq_setup(struct devfreq *devfreq, struct dtpm *parent)
ret = dev_pm_qos_add_request(dev, &dtpm_devfreq->qos_req,
DEV_PM_QOS_MAX_FREQUENCY,
PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
- if (ret) {
+ if (ret < 0) {
pr_err("Failed to add QoS request: %d\n", ret);
goto out_dtpm_unregister;
}
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index e98c9767e0ef..07bf7f9aae01 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -135,12 +135,16 @@ config PTP_1588_CLOCK_VMCLOCK
tristate "Virtual machine PTP clock"
depends on X86_TSC || ARM_ARCH_TIMER
depends on PTP_1588_CLOCK && ACPI && ARCH_SUPPORTS_INT128
- default y
+ default PTP_1588_CLOCK_KVM
help
This driver adds support for using a virtual precision clock
advertised by the hypervisor. This clock is only useful in virtual
machines where such a device is present.
+ Unlike the KVM virtual PTP clock, the VMCLOCK device offers support
+ for reliable timekeeping even across live migration. So this driver
+ is enabled by default whenever the KVM PTP clock is.
+
To compile this driver as a module, choose M here: the module
will be called ptp_vmclock.
@@ -237,4 +241,15 @@ config PTP_DFL_TOD
To compile this driver as a module, choose M here: the module
will be called ptp_dfl_tod.
+config PTP_S390
+ tristate "S390 PTP driver"
+ depends on PTP_1588_CLOCK
+ depends on S390
+ help
+ This driver adds support for S390 time steering via the PtP
+ interface. This works by adding a in-kernel clock delta value,
+ which is always added to time values used in the kernel. The PtP
+ driver provides the raw clock value without the delta to
+ userspace. That way userspace programs like chrony could steer
+ the kernel clock.
endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 01b5cd91eb61..25f846fe48c9 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o
obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o
obj-$(CONFIG_PTP_1588_CLOCK_OCP) += ptp_ocp.o
obj-$(CONFIG_PTP_DFL_TOD) += ptp_dfl_tod.o
+obj-$(CONFIG_PTP_S390) += ptp_s390.o
diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c
index e14e149b746e..879b82f03535 100644
--- a/drivers/ptp/ptp_fc3.c
+++ b/drivers/ptp/ptp_fc3.c
@@ -986,11 +986,6 @@ static int idtfc3_probe(struct platform_device *pdev)
mutex_unlock(idtfc3->lock);
- if (err) {
- ptp_clock_unregister(idtfc3->ptp_clock);
- return err;
- }
-
platform_set_drvdata(pdev, idtfc3);
return 0;
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
index 33355d5eb033..b8a9a54a176c 100644
--- a/drivers/ptp/ptp_pch.c
+++ b/drivers/ptp/ptp_pch.c
@@ -462,14 +462,14 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
}
- ret = pcim_iomap_regions(pdev, BIT(IO_MEM_BAR), "1588_regs");
+ /* get the virtual address to the 1588 registers */
+ chip->regs = pcim_iomap_region(pdev, IO_MEM_BAR, KBUILD_MODNAME);
+ ret = PTR_ERR_OR_ZERO(chip->regs);
if (ret) {
dev_err(&pdev->dev, "could not locate IO memory address\n");
return ret;
}
- /* get the virtual address to the 1588 registers */
- chip->regs = pcim_iomap_table(pdev)[IO_MEM_BAR];
chip->caps = ptp_pch_caps;
chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev);
if (IS_ERR(chip->ptp_clock))
diff --git a/drivers/ptp/ptp_s390.c b/drivers/ptp/ptp_s390.c
new file mode 100644
index 000000000000..29618eb9bf44
--- /dev/null
+++ b/drivers/ptp/ptp_s390.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * s390 PTP clock driver
+ *
+ */
+
+#include "ptp_private.h"
+#include <linux/time.h>
+#include <asm/stp.h>
+
+static struct ptp_clock *ptp_stcke_clock, *ptp_qpt_clock;
+
+static int ptp_s390_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ return -EOPNOTSUPP;
+}
+
+static int ptp_s390_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct timespec64 eitod_to_timespec64(union tod_clock *clk)
+{
+ return ns_to_timespec64(eitod_to_ns(clk->eitod - TOD_UNIX_EPOCH));
+}
+
+static struct timespec64 tod_to_timespec64(unsigned long tod)
+{
+ return ns_to_timespec64(tod_to_ns(tod - TOD_UNIX_EPOCH));
+}
+
+static int ptp_s390_stcke_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ union tod_clock tod;
+
+ if (!stp_enabled())
+ return -EOPNOTSUPP;
+
+ store_tod_clock_ext(&tod);
+ *ts = eitod_to_timespec64(&tod);
+ return 0;
+}
+
+static int ptp_s390_qpt_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ unsigned long tod;
+
+ ptff(&tod, sizeof(tod), PTFF_QPT);
+ *ts = tod_to_timespec64(tod);
+ return 0;
+}
+
+static int ptp_s390_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ return -EOPNOTSUPP;
+}
+
+static int s390_arch_ptp_get_crosststamp(ktime_t *device_time,
+ struct system_counterval_t *system_counter,
+ void *ctx)
+{
+ union tod_clock clk;
+
+ store_tod_clock_ext(&clk);
+ *device_time = ns_to_ktime(tod_to_ns(clk.tod - TOD_UNIX_EPOCH));
+ system_counter->cycles = clk.tod;
+ system_counter->cs_id = CSID_S390_TOD;
+ return 0;
+}
+
+static int ptp_s390_getcrosststamp(struct ptp_clock_info *ptp,
+ struct system_device_crosststamp *xtstamp)
+{
+ if (!stp_enabled())
+ return -EOPNOTSUPP;
+ return get_device_system_crosststamp(s390_arch_ptp_get_crosststamp, NULL, NULL, xtstamp);
+}
+
+static struct ptp_clock_info ptp_s390_stcke_info = {
+ .owner = THIS_MODULE,
+ .name = "s390 STCKE Clock",
+ .max_adj = 0,
+ .adjfine = ptp_s390_adjfine,
+ .adjtime = ptp_s390_adjtime,
+ .gettime64 = ptp_s390_stcke_gettime,
+ .settime64 = ptp_s390_settime,
+ .getcrosststamp = ptp_s390_getcrosststamp,
+};
+
+static struct ptp_clock_info ptp_s390_qpt_info = {
+ .owner = THIS_MODULE,
+ .name = "s390 Physical Clock",
+ .max_adj = 0,
+ .adjfine = ptp_s390_adjfine,
+ .adjtime = ptp_s390_adjtime,
+ .gettime64 = ptp_s390_qpt_gettime,
+ .settime64 = ptp_s390_settime,
+};
+
+static __init int ptp_s390_init(void)
+{
+ ptp_stcke_clock = ptp_clock_register(&ptp_s390_stcke_info, NULL);
+ if (IS_ERR(ptp_stcke_clock))
+ return PTR_ERR(ptp_stcke_clock);
+
+ ptp_qpt_clock = ptp_clock_register(&ptp_s390_qpt_info, NULL);
+ if (IS_ERR(ptp_qpt_clock)) {
+ ptp_clock_unregister(ptp_stcke_clock);
+ return PTR_ERR(ptp_qpt_clock);
+ }
+ return 0;
+}
+
+static __exit void ptp_s390_exit(void)
+{
+ ptp_clock_unregister(ptp_qpt_clock);
+ ptp_clock_unregister(ptp_stcke_clock);
+}
+
+module_init(ptp_s390_init);
+module_exit(ptp_s390_exit);
+
+MODULE_AUTHOR("Sven Schnelle <svens@linux.ibm.com>");
+MODULE_DESCRIPTION("s390 Physical/STCKE Clock PtP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index 96ea343856f0..7ee7b65b9b90 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -106,7 +106,9 @@ static int pwm_imx_tpm_round_state(struct pwm_chip *chip,
p->prescale = prescale;
period_count = (clock_unit + ((1 << prescale) >> 1)) >> prescale;
- p->mod = period_count;
+ if (period_count == 0)
+ return -EINVAL;
+ p->mod = period_count - 1;
/* calculate real period HW can support */
tmp = (u64)period_count << prescale;
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 14b60abd6afc..01a8d0487918 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -1379,6 +1379,8 @@ static const struct regulator_desc rk809_reg[] = {
.n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
.vsel_reg = RK817_BUCK3_ON_VSEL_REG,
.vsel_mask = RK817_BUCK_VSEL_MASK,
+ .apply_reg = RK817_POWER_CONFIG,
+ .apply_bit = RK817_BUCK3_FB_RES_INTER,
.enable_reg = RK817_POWER_EN_REG(0),
.enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
.enable_val = ENABLE_MASK(RK817_ID_DCDC3),
diff --git a/drivers/regulator/rtq2208-regulator.c b/drivers/regulator/rtq2208-regulator.c
index a5c126afc648..5925fa7a9a06 100644
--- a/drivers/regulator/rtq2208-regulator.c
+++ b/drivers/regulator/rtq2208-regulator.c
@@ -568,7 +568,7 @@ static int rtq2208_probe(struct i2c_client *i2c)
struct regmap *regmap;
struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX];
struct regulator_dev *rdev;
- struct regulator_config cfg;
+ struct regulator_config cfg = {};
struct rtq2208_rdev_map *rdev_map;
int i, ret = 0, idx, n_regulator = 0;
unsigned int regulator_idx_table[RTQ2208_LDO_MAX],
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 0b2f29006908..d3af1dfa3c7d 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -1440,14 +1440,18 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
goto unlock;
ret = wait_event_timeout(channel->intent_req_wq,
- READ_ONCE(channel->intent_req_result) >= 0 &&
- READ_ONCE(channel->intent_received),
+ READ_ONCE(channel->intent_req_result) == 0 ||
+ (READ_ONCE(channel->intent_req_result) > 0 &&
+ READ_ONCE(channel->intent_received)) ||
+ glink->abort_tx,
10 * HZ);
if (!ret) {
dev_err(glink->dev, "intent request timed out\n");
ret = -ETIMEDOUT;
+ } else if (glink->abort_tx) {
+ ret = -ECANCELED;
} else {
- ret = READ_ONCE(channel->intent_req_result) ? 0 : -ECANCELED;
+ ret = READ_ONCE(channel->intent_req_result) ? 0 : -EAGAIN;
}
unlock:
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index de15fc0df104..b52513eeeafa 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -3651,7 +3651,7 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
enum dma_data_direction dir;
struct scsi_data_buffer *sdb = &scp->sdb;
u8 *fsp;
- int i;
+ int i, total = 0;
/*
* Even though reads are inherently atomic (in this driver), we expect
@@ -3688,18 +3688,16 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
fsp + (block * sdebug_sector_size),
sdebug_sector_size, sg_skip, do_write);
sdeb_data_sector_unlock(sip, do_write);
- if (ret != sdebug_sector_size) {
- ret += (i * sdebug_sector_size);
+ total += ret;
+ if (ret != sdebug_sector_size)
break;
- }
sg_skip += sdebug_sector_size;
if (++block >= sdebug_store_sectors)
block = 0;
}
- ret = num * sdebug_sector_size;
sdeb_data_unlock(sip, atomic);
- return ret;
+ return total;
}
/* Returns number of bytes copied or -1 if error. */
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index ee2b74238758..6ab27f4f4878 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -188,8 +188,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
while (bufsize >= SECTOR_SIZE) {
- buf = __vmalloc(bufsize,
- GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY);
+ buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
if (buf) {
*buflen = bufsize;
return buf;
diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c
index b811446e0fa5..0b60ed16297c 100644
--- a/drivers/soc/fsl/dpio/dpio-service.c
+++ b/drivers/soc/fsl/dpio/dpio-service.c
@@ -891,7 +891,7 @@ void dpaa2_io_update_net_dim(struct dpaa2_io *d, __u64 frames, __u64 bytes)
d->frames += frames;
dim_update_sample(d->event_ctr, d->frames, d->bytes, &dim_sample);
- net_dim(&d->rx_dim, dim_sample);
+ net_dim(&d->rx_dim, &dim_sample);
spin_unlock(&d->dim_lock);
}
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 8fa4ffd3a9b5..28bcc65e91be 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -139,6 +139,7 @@ struct qcom_llcc_config {
int size;
bool need_llcc_cfg;
bool no_edac;
+ bool irq_configured;
};
struct qcom_sct_config {
@@ -718,6 +719,7 @@ static const struct qcom_llcc_config x1e80100_cfg[] = {
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
+ .irq_configured = true,
},
};
@@ -1345,6 +1347,7 @@ static int qcom_llcc_probe(struct platform_device *pdev)
drv_data->cfg = llcc_cfg;
drv_data->cfg_size = sz;
drv_data->edac_reg_offset = cfg->edac_reg_offset;
+ drv_data->ecc_irq_configured = cfg->irq_configured;
mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data);
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
index 9606222993fd..baa4ac6704a9 100644
--- a/drivers/soc/qcom/pmic_glink.c
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -4,6 +4,7 @@
* Copyright (c) 2022, Linaro Ltd
*/
#include <linux/auxiliary_bus.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -13,6 +14,8 @@
#include <linux/soc/qcom/pmic_glink.h>
#include <linux/spinlock.h>
+#define PMIC_GLINK_SEND_TIMEOUT (5 * HZ)
+
enum {
PMIC_GLINK_CLIENT_BATT = 0,
PMIC_GLINK_CLIENT_ALTMODE,
@@ -112,13 +115,29 @@ EXPORT_SYMBOL_GPL(pmic_glink_client_register);
int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
{
struct pmic_glink *pg = client->pg;
+ bool timeout_reached = false;
+ unsigned long start;
int ret;
mutex_lock(&pg->state_lock);
- if (!pg->ept)
+ if (!pg->ept) {
ret = -ECONNRESET;
- else
- ret = rpmsg_send(pg->ept, data, len);
+ } else {
+ start = jiffies;
+ for (;;) {
+ ret = rpmsg_send(pg->ept, data, len);
+ if (ret != -EAGAIN)
+ break;
+
+ if (timeout_reached) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ usleep_range(1000, 5000);
+ timeout_reached = time_after(jiffies, start + PMIC_GLINK_SEND_TIMEOUT);
+ }
+ }
mutex_unlock(&pg->state_lock);
return ret;
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 64fc4f41da77..ecfd3da9d5e8 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -786,10 +786,16 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
SOCINFO_MAJOR(le32_to_cpu(info->ver)),
SOCINFO_MINOR(le32_to_cpu(info->ver)));
- if (offsetof(struct socinfo, serial_num) <= item_size)
+ if (!qs->attr.soc_id || !qs->attr.revision)
+ return -ENOMEM;
+
+ if (offsetof(struct socinfo, serial_num) <= item_size) {
qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%u",
le32_to_cpu(info->serial_num));
+ if (!qs->attr.serial_number)
+ return -ENOMEM;
+ }
qs->soc_dev = soc_device_register(&qs->attr);
if (IS_ERR(qs->soc_dev))
diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c
index fff312c6968d..4f3dd70d6a1a 100644
--- a/drivers/soundwire/intel_ace2x.c
+++ b/drivers/soundwire/intel_ace2x.c
@@ -376,11 +376,12 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
static int intel_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_cdns_dai_runtime *dai_runtime;
+ struct snd_pcm_hw_params *hw_params;
int ch, dir;
- int ret = 0;
dai_runtime = cdns->dai_runtime_array[dai->id];
if (!dai_runtime) {
@@ -389,12 +390,8 @@ static int intel_prepare(struct snd_pcm_substream *substream,
return -EIO;
}
+ hw_params = &rtd->dpcm[substream->stream].hw_params;
if (dai_runtime->suspended) {
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct snd_pcm_hw_params *hw_params;
-
- hw_params = &rtd->dpcm[substream->stream].hw_params;
-
dai_runtime->suspended = false;
/*
@@ -415,15 +412,11 @@ static int intel_prepare(struct snd_pcm_substream *substream,
/* the SHIM will be configured in the callback functions */
sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
-
- /* Inform DSP about PDI stream number */
- ret = intel_params_stream(sdw, substream, dai,
- hw_params,
- sdw->instance,
- dai_runtime->pdi->intel_alh_id);
}
- return ret;
+ /* Inform DSP about PDI stream number */
+ return intel_params_stream(sdw, substream, dai, hw_params, sdw->instance,
+ dai_runtime->pdi->intel_alh_id);
}
static int
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 191de1917f83..3fa990fb59c7 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -1003,6 +1003,7 @@ static int dspi_setup(struct spi_device *spi)
u32 cs_sck_delay = 0, sck_cs_delay = 0;
struct fsl_dspi_platform_data *pdata;
unsigned char pasc = 0, asc = 0;
+ struct gpio_desc *gpio_cs;
struct chip_data *chip;
unsigned long clkrate;
bool cs = true;
@@ -1077,7 +1078,10 @@ static int dspi_setup(struct spi_device *spi)
chip->ctar_val |= SPI_CTAR_LSBFE;
}
- gpiod_direction_output(spi_get_csgpiod(spi, 0), false);
+ gpio_cs = spi_get_csgpiod(spi, 0);
+ if (gpio_cs)
+ gpiod_direction_output(gpio_cs, false);
+
dspi_deassert_cs(spi, &cs);
spi_set_ctldata(spi, chip);
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index f6e40f90418f..768d7482102a 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -1116,6 +1116,11 @@ static int spi_geni_probe(struct platform_device *pdev)
init_completion(&mas->tx_reset_done);
init_completion(&mas->rx_reset_done);
spin_lock_init(&mas->lock);
+
+ ret = geni_icc_get(&mas->se, NULL);
+ if (ret)
+ return ret;
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
ret = devm_pm_runtime_enable(dev);
@@ -1125,9 +1130,6 @@ static int spi_geni_probe(struct platform_device *pdev)
if (device_property_read_bool(&pdev->dev, "spi-slave"))
spi->target = true;
- ret = geni_icc_get(&mas->se, NULL);
- if (ret)
- return ret;
/* Set the bus quota to a reasonable value for register access */
mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ);
mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index ddd98ddb7913..c5677fd94e5e 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -1187,7 +1187,7 @@ cleanup:
/**
* mtk_snand_is_page_ops() - check if the op is a controller supported page op.
- * @op spi-mem op to check
+ * @op: spi-mem op to check
*
* Check whether op can be executed with read_from_cache or program_load
* mode in the controller.
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 4c4ff074e3f6..fc72a89fb3a7 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -2044,6 +2044,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
.has_fifo = true,
.prevent_dma_burst = true,
+ .has_device_mode = true,
};
static const struct of_device_id stm32_spi_of_match[] = {
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 3fb68d60dfc1..fcdd559a8acf 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -26,8 +26,6 @@ if STAGING
source "drivers/staging/olpc_dcon/Kconfig"
-source "drivers/staging/rtl8192e/Kconfig"
-
source "drivers/staging/rtl8723bs/Kconfig"
source "drivers/staging/rtl8712/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index c977aa13fad4..4a84c4848664 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -3,7 +3,6 @@
obj-y += media/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
-obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_RTL8723BS) += rtl8723bs/
obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_RTS5208) += rts5208/
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 6c390c4eb26d..492612e8f8ba 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -129,12 +129,15 @@ static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout)
static int ad9832_write_frequency(struct ad9832_state *st,
unsigned int addr, unsigned long fout)
{
+ unsigned long clk_freq;
unsigned long regval;
- if (fout > (clk_get_rate(st->mclk) / 2))
+ clk_freq = clk_get_rate(st->mclk);
+
+ if (!clk_freq || fout > (clk_freq / 2))
return -EINVAL;
- regval = ad9832_calc_freqreg(clk_get_rate(st->mclk), fout);
+ regval = ad9832_calc_freqreg(clk_freq, fout);
st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
(addr << ADD_SHIFT) |
diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h
index ec461fd187af..b584754f4be0 100644
--- a/drivers/staging/media/av7110/av7110.h
+++ b/drivers/staging/media/av7110/av7110.h
@@ -88,6 +88,8 @@ struct infrared {
u32 ir_config;
};
+#define MAX_CI_SLOTS 2
+
/* place to store all the necessary device information */
struct av7110 {
/* devices */
@@ -163,7 +165,7 @@ struct av7110 {
/* CA */
- struct ca_slot_info ci_slot[2];
+ struct ca_slot_info ci_slot[MAX_CI_SLOTS];
enum av7110_video_mode vidmode;
struct dmxdev dmxdev;
diff --git a/drivers/staging/media/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c
index 6ce212c64e5d..fce4023c9dea 100644
--- a/drivers/staging/media/av7110/av7110_ca.c
+++ b/drivers/staging/media/av7110/av7110_ca.c
@@ -26,23 +26,28 @@
void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
{
+ unsigned slot_num;
+
dprintk(8, "av7110:%p\n", av7110);
if (len < 3)
return;
switch (data[0]) {
case CI_MSG_CI_INFO:
- if (data[2] != 1 && data[2] != 2)
+ if (data[2] != 1 && data[2] != MAX_CI_SLOTS)
break;
+
+ slot_num = array_index_nospec(data[2] - 1, MAX_CI_SLOTS);
+
switch (data[1]) {
case 0:
- av7110->ci_slot[data[2] - 1].flags = 0;
+ av7110->ci_slot[slot_num].flags = 0;
break;
case 1:
- av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT;
+ av7110->ci_slot[slot_num].flags |= CA_CI_MODULE_PRESENT;
break;
case 2:
- av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY;
+ av7110->ci_slot[slot_num].flags |= CA_CI_MODULE_READY;
break;
}
break;
@@ -262,15 +267,19 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
case CA_GET_SLOT_INFO:
{
struct ca_slot_info *info = (struct ca_slot_info *)parg;
+ unsigned int slot_num;
if (info->num < 0 || info->num > 1) {
mutex_unlock(&av7110->ioctl_mutex);
return -EINVAL;
}
- av7110->ci_slot[info->num].num = info->num;
- av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
- CA_CI_LINK : CA_CI;
- memcpy(info, &av7110->ci_slot[info->num], sizeof(struct ca_slot_info));
+ slot_num = array_index_nospec(info->num, MAX_CI_SLOTS);
+
+ av7110->ci_slot[slot_num].num = info->num;
+ av7110->ci_slot[slot_num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
+ CA_CI_LINK : CA_CI;
+ memcpy(info, &av7110->ci_slot[slot_num],
+ sizeof(struct ca_slot_info));
break;
}
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
deleted file mode 100644
index e06c189b4ce4..000000000000
--- a/drivers/staging/rtl8192e/Kconfig
+++ /dev/null
@@ -1,61 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config RTLLIB
- tristate "Support for rtllib wireless devices"
- depends on WLAN && m
- select LIB80211
- select CRC32
- help
- If you have a wireless card that uses rtllib, say
- Y. Currently the only card is the rtl8192e.
-
- If unsure, say N.
-
- This driver adds support for rtllib wireless cards.
- Only the rtl8192e is supported as of now.
-
-if RTLLIB
-
-config RTLLIB_CRYPTO_CCMP
- tristate "Support for rtllib CCMP crypto"
- depends on RTLLIB
- select CRYPTO
- select CRYPTO_AES
- select CRYPTO_CCM
- default y
- help
- CCMP crypto driver for rtllib.
-
- If you enabled RTLLIB, you want this.
- Adds support for the CCM mode Protocol crypto driver for
- use in wireless cards (including rtllib cards).
-
-config RTLLIB_CRYPTO_TKIP
- tristate "Support for rtllib TKIP crypto"
- depends on RTLLIB
- select CRYPTO
- select CRYPTO_LIB_ARC4
- select CRYPTO_MICHAEL_MIC
- default y
- help
- TKIP crypto driver for rtllib.
-
- If you enabled RTLLIB, you want this.
- Adds support for the Temporal Key Integrity Protocol for
- the IEEE 802.11i standard for use on wireless cards.
-
-config RTLLIB_CRYPTO_WEP
- tristate "Support for rtllib WEP crypto"
- select CRYPTO_LIB_ARC4
- depends on RTLLIB
- default y
- help
- WEP crypto driver for rtllib.
-
- If you enabled RTLLIB, you want this.
- Adds support for the (now weak) Wired Equivalent Privacy
- (WEP) crypto protocol for wireless cards.
- NOTE: This protocol is now considered insecure.
-
-source "drivers/staging/rtl8192e/rtl8192e/Kconfig"
-
-endif
diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile
deleted file mode 100644
index a1492215dab1..000000000000
--- a/drivers/staging/rtl8192e/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-rtllib-objs := \
- rtllib_module.o \
- rtllib_rx.o \
- rtllib_tx.o \
- rtllib_wx.o \
- rtllib_softmac.o \
- rtllib_softmac_wx.o \
- rtl819x_BAProc.o \
- rtl819x_HTProc.o \
- rtl819x_TSProc.o
-
-obj-$(CONFIG_RTLLIB) += rtllib.o
-
-obj-$(CONFIG_RTLLIB_CRYPTO_CCMP) += rtllib_crypt_ccmp.o
-obj-$(CONFIG_RTLLIB_CRYPTO_TKIP) += rtllib_crypt_tkip.o
-obj-$(CONFIG_RTLLIB_CRYPTO_WEP) += rtllib_crypt_wep.o
-
-obj-$(CONFIG_RTL8192E) += rtl8192e/
diff --git a/drivers/staging/rtl8192e/TODO b/drivers/staging/rtl8192e/TODO
deleted file mode 100644
index 7221ae65d63e..000000000000
--- a/drivers/staging/rtl8192e/TODO
+++ /dev/null
@@ -1,18 +0,0 @@
-To-do list:
-
-* merge into drivers/net/wireless/realtek/rtlwifi/rtl8192*
-* clean up function naming
-* Correct the coding style according to Linux guidelines; please read the document
- at https://www.kernel.org/doc/html/latest/process/coding-style.html.
-* Remove unnecessary debugging/printing macros; for those that are still needed
- use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()).
-* Remove dead code such as unusued functions, variables, fields, etc..
-* Use in-kernel API and remove unnecessary wrappers where possible.
-* Fix bugs due to code that sleeps in atomic context.
-* Remove the HAL layer and migrate its functionality into the relevant parts of
- the driver.
-* Switch to use LIB80211.
-* Switch to use MAC80211.
-* Switch to use CFG80211.
-* Improve the error handling of various functions, particularly those that use
- existing kernel APIs.
diff --git a/drivers/staging/rtl8192e/rtl8192e/Kconfig b/drivers/staging/rtl8192e/rtl8192e/Kconfig
deleted file mode 100644
index f8f774a16295..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config RTL8192E
- tristate "RealTek RTL8192E Wireless LAN NIC driver"
- depends on PCI && WLAN && RTLLIB
- depends on m
- select CFG80211
- select WIRELESS_EXT
- select WEXT_PRIV
- select CRYPTO
- select FW_LOADER
diff --git a/drivers/staging/rtl8192e/rtl8192e/Makefile b/drivers/staging/rtl8192e/rtl8192e/Makefile
deleted file mode 100644
index a442d79ea71e..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-r8192e_pci-objs := \
- r8192E_dev.o \
- r8192E_phy.o \
- r8192E_firmware.o \
- r8192E_cmdpkt.o \
- table.o \
- r8190P_rtl8256.o \
- rtl_cam.o \
- rtl_core.o \
- rtl_dm.o \
- rtl_eeprom.o \
- rtl_ethtool.o \
- rtl_pci.o \
- rtl_pm.o \
- rtl_ps.o \
- rtl_wx.o \
-
-obj-$(CONFIG_RTL8192E) += r8192e_pci.o
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h
deleted file mode 100644
index 552fd9b6e3e5..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef R8190P_DEF_H
-#define R8190P_DEF_H
-
-#include <linux/types.h>
-#include "r8192E_phy.h"
-
-#define MAX_SILENT_RESET_RX_SLOT_NUM 10
-
-enum rtl819x_loopback {
- RTL819X_NO_LOOPBACK = 0,
- RTL819X_MAC_LOOPBACK = 1,
- RTL819X_DMA_LOOPBACK = 2,
- RTL819X_CCK_LOOPBACK = 3,
-};
-
-#define DESC90_RATE1M 0x00
-#define DESC90_RATE2M 0x01
-#define DESC90_RATE5_5M 0x02
-#define DESC90_RATE11M 0x03
-#define DESC90_RATE6M 0x04
-#define DESC90_RATE9M 0x05
-#define DESC90_RATE12M 0x06
-#define DESC90_RATE18M 0x07
-#define DESC90_RATE24M 0x08
-#define DESC90_RATE36M 0x09
-#define DESC90_RATE48M 0x0a
-#define DESC90_RATE54M 0x0b
-#define DESC90_RATEMCS0 0x00
-#define DESC90_RATEMCS1 0x01
-#define DESC90_RATEMCS2 0x02
-#define DESC90_RATEMCS3 0x03
-#define DESC90_RATEMCS4 0x04
-#define DESC90_RATEMCS5 0x05
-#define DESC90_RATEMCS6 0x06
-#define DESC90_RATEMCS7 0x07
-#define DESC90_RATEMCS8 0x08
-#define DESC90_RATEMCS9 0x09
-#define DESC90_RATEMCS10 0x0a
-#define DESC90_RATEMCS11 0x0b
-#define DESC90_RATEMCS12 0x0c
-#define DESC90_RATEMCS13 0x0d
-#define DESC90_RATEMCS14 0x0e
-#define DESC90_RATEMCS15 0x0f
-#define DESC90_RATEMCS32 0x20
-
-#define SHORT_SLOT_TIME 9
-#define NON_SHORT_SLOT_TIME 20
-
-#define RX_SMOOTH 20
-
-#define QSLT_BK 0x1
-#define QSLT_BE 0x0
-#define QSLT_VI 0x4
-#define QSLT_VO 0x6
-#define QSLT_BEACON 0x10
-#define QSLT_HIGH 0x11
-#define QSLT_MGNT 0x12
-#define QSLT_CMD 0x13
-
-#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007
-#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa
-#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024
-#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007
-#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10
-#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4
-#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd
-
-#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000
-#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00
-#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08
-#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10
-#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18
-#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10
-#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00
-#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08
-
-#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
-#define HAL_PRIME_CHNL_OFFSET_LOWER 1
-#define HAL_PRIME_CHNL_OFFSET_UPPER 2
-
-enum version_8190_loopback {
- VERSION_8190_BD = 0x3,
- VERSION_8190_BE
-};
-
-#define IC_VersionCut_D 0x3
-
-enum rf_optype {
- RF_OP_By_SW_3wire = 0,
- RF_OP_By_FW,
- RF_OP_MAX
-};
-
-struct bb_reg_definition {
- u32 rfintfs;
- u32 rfintfo;
- u32 rfintfe;
- u32 rf3wireOffset;
- u32 rfHSSIPara2;
- u32 rfLSSIReadBack;
- u32 rfLSSIReadBackPi;
-};
-
-struct tx_fwinfo_8190pci {
- u8 TxRate:7;
- u8 CtsEnable:1;
- u8 RtsRate:7;
- u8 RtsEnable:1;
- u8 TxHT:1;
- u8 Short:1;
- u8 TxBandwidth:1;
- u8 TxSubCarrier:2;
- u8 STBC:2;
- u8 AllowAggregation:1;
- u8 RtsHT:1;
- u8 RtsShort:1;
- u8 RtsBandwidth:1;
- u8 RtsSubcarrier:2;
- u8 RtsSTBC:2;
- u8 EnableCPUDur:1;
-
- u32 RxMF:2;
- u32 RxAMD:3;
- u32 TxPerPktInfoFeedback:1;
- u32 Reserved1:2;
- u32 TxAGCOffset:4;
- u32 TxAGCSign:1;
- u32 RAW_TXD:1;
- u32 Retry_Limit:4;
- u32 Reserved2:1;
- u32 PacketID:13;
-};
-
-struct phy_sts_ofdm_819xpci {
- u8 trsw_gain_X[RF90_PATH_MAX];
- u8 pwdb_all;
- u8 cfosho_X[4];
- u8 cfotail_X[4];
- u8 rxevm_X[2];
- u8 rxsnr_X[4];
- u8 pdsnr_X[2];
- u8 csi_current_X[2];
- u8 csi_target_X[2];
- u8 sigevm;
- u8 max_ex_pwr;
- u8 sgi_en;
- u8 rxsc_sgien_exflg;
-};
-
-struct phy_sts_cck_819xpci {
- u8 adc_pwdb_X[4];
- u8 sq_rpt;
- u8 cck_agc_rpt;
-};
-
-#define PHY_RSSI_SLID_WIN_MAX 100
-#define PHY_Beacon_RSSI_SLID_WIN_MAX 10
-
-struct tx_desc {
- u16 PktSize;
- u8 Offset;
- u8 Reserved1:3;
- u8 CmdInit:1;
- u8 LastSeg:1;
- u8 FirstSeg:1;
- u8 LINIP:1;
- u8 OWN:1;
-
- u8 TxFWInfoSize;
- u8 RATid:3;
- u8 DISFB:1;
- u8 USERATE:1;
- u8 MOREFRAG:1;
- u8 NoEnc:1;
- u8 PIFS:1;
- u8 QueueSelect:5;
- u8 NoACM:1;
- u8 Resv:2;
- u8 SecCAMID:5;
- u8 SecDescAssign:1;
- u8 SecType:2;
-
- u16 TxBufferSize;
- u8 PktId:7;
- u8 Resv1:1;
- u8 Reserved2;
-
- u32 TxBuffAddr;
-
- u32 NextDescAddress;
-
- u32 Reserved5;
- u32 Reserved6;
- u32 Reserved7;
-};
-
-struct tx_desc_cmd {
- u16 PktSize;
- u8 Reserved1;
- u8 CmdType:3;
- u8 CmdInit:1;
- u8 LastSeg:1;
- u8 FirstSeg:1;
- u8 LINIP:1;
- u8 OWN:1;
-
- u16 ElementReport;
- u16 Reserved2;
-
- u16 TxBufferSize;
- u16 Reserved3;
-
- u32 TxBuffAddr;
- u32 NextDescAddress;
- u32 Reserved4;
- u32 Reserved5;
- u32 Reserved6;
-};
-
-struct rx_desc {
- u16 Length:14;
- u16 CRC32:1;
- u16 ICV:1;
- u8 rx_drv_info_size;
- u8 Shift:2;
- u8 PHYStatus:1;
- u8 SWDec:1;
- u8 LastSeg:1;
- u8 FirstSeg:1;
- u8 EOR:1;
- u8 OWN:1;
-
- u32 Reserved2;
-
- u32 Reserved3;
-
- u32 BufferAddress;
-};
-
-struct rx_fwinfo {
- u16 Reserved1:12;
- u16 PartAggr:1;
- u16 FirstAGGR:1;
- u16 Reserved2:2;
-
- u8 RxRate:7;
- u8 RxHT:1;
-
- u8 BW:1;
- u8 SPLCP:1;
- u8 Reserved3:2;
- u8 PAM:1;
- u8 Mcast:1;
- u8 Bcast:1;
- u8 Reserved4:1;
-
- u32 TSFL;
-};
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
deleted file mode 100644
index 7061f1cf4d3a..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_phyreg.h"
-#include "r8192E_phy.h"
-#include "r8190P_rtl8256.h"
-
-void rtl92e_set_bandwidth(struct net_device *dev,
- enum ht_channel_width bandwidth)
-{
- u8 eRFPath;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->card_8192_version != VERSION_8190_BD &&
- priv->card_8192_version != VERSION_8190_BE) {
- netdev_warn(dev, "%s(): Unknown HW version.\n", __func__);
- return;
- }
-
- for (eRFPath = 0; eRFPath < priv->num_total_rf_path; eRFPath++) {
- switch (bandwidth) {
- case HT_CHANNEL_WIDTH_20:
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x0b, bMask12Bits, 0x100);
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x2c, bMask12Bits, 0x3d7);
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x0e, bMask12Bits, 0x021);
- break;
- case HT_CHANNEL_WIDTH_20_40:
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x0b, bMask12Bits, 0x300);
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x2c, bMask12Bits, 0x3ff);
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath,
- 0x0e, bMask12Bits, 0x0e1);
- break;
- default:
- netdev_err(dev, "%s(): Unknown bandwidth: %#X\n",
- __func__, bandwidth);
- break;
- }
- }
-}
-
-bool rtl92e_config_rf(struct net_device *dev)
-{
- u32 u4RegValue = 0;
- u8 eRFPath;
- bool rtStatus = true;
- struct bb_reg_definition *pPhyReg;
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 RegOffSetToBeCheck = 0x3;
- u32 RegValueToBeCheck = 0x7f1;
- u32 RF3_Final_Value = 0;
- u8 ConstRetryTimes = 5, RetryTimes = 5;
- u8 ret = 0;
-
- priv->num_total_rf_path = RTL819X_TOTAL_RF_PATH;
-
- for (eRFPath = (enum rf90_radio_path)RF90_PATH_A;
- eRFPath < priv->num_total_rf_path; eRFPath++) {
- pPhyReg = &priv->phy_reg_def[eRFPath];
-
- switch (eRFPath) {
- case RF90_PATH_A:
- u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs,
- bRFSI_RFENV);
- break;
- case RF90_PATH_B:
- u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs,
- bRFSI_RFENV << 16);
- break;
- }
-
- rtl92e_set_bb_reg(dev, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1);
-
- rtl92e_set_bb_reg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
-
- rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2,
- b3WireAddressLength, 0x0);
- rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2,
- b3WireDataLength, 0x0);
-
- rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, 0x0,
- bMask12Bits, 0xbf);
-
- rtStatus = rtl92e_check_bb_and_rf(dev, HW90_BLOCK_RF,
- (enum rf90_radio_path)eRFPath);
- if (!rtStatus) {
- netdev_err(dev, "%s(): Failed to check RF Path %d.\n",
- __func__, eRFPath);
- goto fail;
- }
-
- RetryTimes = ConstRetryTimes;
- RF3_Final_Value = 0;
- while (RF3_Final_Value != RegValueToBeCheck &&
- RetryTimes != 0) {
- ret = rtl92e_config_rf_path(dev,
- (enum rf90_radio_path)eRFPath);
- RF3_Final_Value = rtl92e_get_rf_reg(dev,
- (enum rf90_radio_path)eRFPath,
- RegOffSetToBeCheck,
- bMask12Bits);
- RetryTimes--;
- }
-
- switch (eRFPath) {
- case RF90_PATH_A:
- rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV,
- u4RegValue);
- break;
- case RF90_PATH_B:
- rtl92e_set_bb_reg(dev, pPhyReg->rfintfs,
- bRFSI_RFENV << 16, u4RegValue);
- break;
- }
-
- if (ret) {
- netdev_err(dev,
- "%s(): Failed to initialize RF Path %d.\n",
- __func__, eRFPath);
- goto fail;
- }
- }
- return true;
-
-fail:
- return false;
-}
-
-void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel)
-{
- u32 TxAGC = 0;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- TxAGC = powerlevel;
- if (priv->dynamic_tx_low_pwr) {
- if (priv->customer_id == RT_CID_819X_NETCORE)
- TxAGC = 0x22;
- else
- TxAGC += priv->cck_pwr_enl;
- }
- if (TxAGC > 0x24)
- TxAGC = 0x24;
- rtl92e_set_bb_reg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC);
-}
-
-void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 writeVal, powerBase0, powerBase1, writeVal_tmp;
- u8 index = 0;
- u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
- u8 byte0, byte1, byte2, byte3;
-
- powerBase0 = powerlevel + priv->legacy_ht_tx_pwr_diff;
- powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
- (powerBase0 << 8) | powerBase0;
- powerBase1 = powerlevel;
- powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) |
- (powerBase1 << 8) | powerBase1;
-
- for (index = 0; index < 6; index++) {
- writeVal = (u32)(priv->mcs_tx_pwr_level_org_offset[index] +
- ((index < 2) ? powerBase0 : powerBase1));
- byte0 = writeVal & 0x7f;
- byte1 = (writeVal & 0x7f00) >> 8;
- byte2 = (writeVal & 0x7f0000) >> 16;
- byte3 = (writeVal & 0x7f000000) >> 24;
- if (byte0 > 0x24)
- byte0 = 0x24;
- if (byte1 > 0x24)
- byte1 = 0x24;
- if (byte2 > 0x24)
- byte2 = 0x24;
- if (byte3 > 0x24)
- byte3 = 0x24;
-
- if (index == 3) {
- writeVal_tmp = (byte3 << 24) | (byte2 << 16) |
- (byte1 << 8) | byte0;
- priv->pwr_track = writeVal_tmp;
- }
-
- if (priv->dynamic_tx_high_pwr)
- writeVal = 0x03030303;
- else
- writeVal = (byte3 << 24) | (byte2 << 16) |
- (byte1 << 8) | byte0;
- rtl92e_set_bb_reg(dev, RegOffset[index], 0x7f7f7f7f, writeVal);
- }
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h
deleted file mode 100644
index 3c52e2b43095..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef RTL8225H
-#define RTL8225H
-
-#define RTL819X_TOTAL_RF_PATH 2
-void rtl92e_set_bandwidth(struct net_device *dev,
- enum ht_channel_width bandwidth);
-bool rtl92e_config_rf(struct net_device *dev);
-void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel);
-void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
deleted file mode 100644
index 533cc4e723f6..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_hw.h"
-#include "r8192E_cmdpkt.h"
-
-bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data,
- u32 len)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u16 frag_length = 0, frag_offset = 0;
- struct sk_buff *skb;
- unsigned char *seg_ptr;
- struct cb_desc *tcb_desc;
- u8 last_ini_pkt;
-
- struct tx_fwinfo_8190pci *pTxFwInfo = NULL;
-
- do {
- if ((len - frag_offset) > CMDPACKET_FRAG_SIZE) {
- frag_length = CMDPACKET_FRAG_SIZE;
- last_ini_pkt = 0;
-
- } else {
- frag_length = (u16)(len - frag_offset);
- last_ini_pkt = 1;
- }
-
- if (type == DESC_PACKET_TYPE_NORMAL)
- skb = dev_alloc_skb(frag_length +
- priv->rtllib->tx_headroom + 4);
- else
- skb = dev_alloc_skb(frag_length + 4);
-
- if (!skb)
- return false;
-
- memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
- tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- tcb_desc->queue_index = TXCMD_QUEUE;
- tcb_desc->cmd_or_init = type;
- tcb_desc->last_ini_pkt = last_ini_pkt;
-
- if (type == DESC_PACKET_TYPE_NORMAL) {
- tcb_desc->pkt_size = frag_length;
-
- seg_ptr = skb_put(skb, priv->rtllib->tx_headroom);
- pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr;
- memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
- memset(pTxFwInfo, 0x12, 8);
- } else {
- tcb_desc->txbuf_size = frag_length;
- }
-
- skb_put_data(skb, data, frag_length);
-
- if (type == DESC_PACKET_TYPE_INIT &&
- (!priv->rtllib->check_nic_enough_desc(dev, TXCMD_QUEUE) ||
- (!skb_queue_empty(&priv->rtllib->skb_waitq[TXCMD_QUEUE])) ||
- (priv->rtllib->queue_stop))) {
- skb_queue_tail(&priv->rtllib->skb_waitq[TXCMD_QUEUE],
- skb);
- } else {
- priv->rtllib->softmac_hard_start_xmit(skb, dev);
- }
-
- data += frag_length;
- frag_offset += frag_length;
-
- } while (frag_offset < len);
-
- rtl92e_writeb(dev, TP_POLL, TP_POLL_CQ);
-
- return true;
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h
deleted file mode 100644
index c63909199e93..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef R819XUSB_CMDPKT_H
-#define R819XUSB_CMDPKT_H
-
-bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data,
- u32 len);
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
deleted file mode 100644
index 2672b1ddf88e..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ /dev/null
@@ -1,1915 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_phy.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h"
-#include "r8192E_cmdpkt.h"
-#include "rtl_dm.h"
-#include "rtl_wx.h"
-
-static int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI,
- EDCAPARA_VO};
-
-static void _rtl92e_update_msr(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 msr;
-
- msr = rtl92e_readb(dev, MSR);
- msr &= ~MSR_LINK_MASK;
-
- switch (priv->rtllib->iw_mode) {
- case IW_MODE_INFRA:
- if (priv->rtllib->link_state == MAC80211_LINKED)
- msr |= MSR_LINK_MANAGED;
- break;
- default:
- break;
- }
-
- rtl92e_writeb(dev, MSR, msr);
-}
-
-void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- switch (variable) {
- case HW_VAR_BSSID:
- /* BSSIDR 2 byte alignment */
- rtl92e_writew(dev, BSSIDR, *(u16 *)val);
- rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(val + 2));
- break;
-
- case HW_VAR_MEDIA_STATUS:
- {
- enum rt_op_mode op_mode = *((enum rt_op_mode *)(val));
- u8 btMsr = rtl92e_readb(dev, MSR);
-
- btMsr &= 0xfc;
-
- switch (op_mode) {
- case RT_OP_MODE_INFRASTRUCTURE:
- btMsr |= MSR_INFRA;
- break;
-
- case RT_OP_MODE_IBSS:
- btMsr |= MSR_ADHOC;
- break;
-
- case RT_OP_MODE_AP:
- btMsr |= MSR_AP;
- break;
-
- default:
- btMsr |= MSR_NOLINK;
- break;
- }
-
- rtl92e_writeb(dev, MSR, btMsr);
- }
- break;
-
- case HW_VAR_CECHK_BSSID:
- {
- u32 RegRCR, Type;
-
- Type = val[0];
- RegRCR = rtl92e_readl(dev, RCR);
- priv->receive_config = RegRCR;
-
- if (Type)
- RegRCR |= (RCR_CBSSID);
- else
- RegRCR &= (~RCR_CBSSID);
-
- rtl92e_writel(dev, RCR, RegRCR);
- priv->receive_config = RegRCR;
- }
- break;
-
- case HW_VAR_SLOT_TIME:
-
- priv->slot_time = val[0];
- rtl92e_writeb(dev, SLOT_TIME, val[0]);
-
- break;
-
- case HW_VAR_ACK_PREAMBLE:
- {
- u32 regTmp;
-
- priv->short_preamble = (bool)*val;
- regTmp = priv->basic_rate;
- if (priv->short_preamble)
- regTmp |= BRSR_AckShortPmb;
- rtl92e_writel(dev, RRSR, regTmp);
- break;
- }
-
- case HW_VAR_CPU_RST:
- rtl92e_writel(dev, CPU_GEN, ((u32 *)(val))[0]);
- break;
-
- case HW_VAR_AC_PARAM:
- {
- u8 pAcParam = *val;
- u32 eACI = pAcParam;
- u8 u1bAIFS;
- u32 u4bAcParam;
- u8 mode = priv->rtllib->mode;
- struct rtllib_qos_parameters *qop =
- &priv->rtllib->current_network.qos_data.parameters;
-
- u1bAIFS = qop->aifs[pAcParam] *
- ((mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) ? 9 : 20) + asifs_time;
-
- rtl92e_dm_init_edca_turbo(dev);
-
- u4bAcParam = (le16_to_cpu(qop->tx_op_limit[pAcParam]) <<
- AC_PARAM_TXOP_LIMIT_OFFSET) |
- ((le16_to_cpu(qop->cw_max[pAcParam])) <<
- AC_PARAM_ECW_MAX_OFFSET) |
- ((le16_to_cpu(qop->cw_min[pAcParam])) <<
- AC_PARAM_ECW_MIN_OFFSET) |
- (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET);
-
- switch (eACI) {
- case AC1_BK:
- rtl92e_writel(dev, EDCAPARA_BK, u4bAcParam);
- break;
-
- case AC0_BE:
- rtl92e_writel(dev, EDCAPARA_BE, u4bAcParam);
- break;
-
- case AC2_VI:
- rtl92e_writel(dev, EDCAPARA_VI, u4bAcParam);
- break;
-
- case AC3_VO:
- rtl92e_writel(dev, EDCAPARA_VO, u4bAcParam);
- break;
-
- default:
- netdev_info(dev, "SetHwReg8185(): invalid ACI: %d !\n",
- eACI);
- break;
- }
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACM_CTRL,
- &pAcParam);
- break;
- }
-
- case HW_VAR_ACM_CTRL:
- {
- struct rtllib_qos_parameters *qos_parameters =
- &priv->rtllib->current_network.qos_data.parameters;
- u8 pAcParam = *val;
- u32 eACI = pAcParam;
- union aci_aifsn *pAciAifsn = (union aci_aifsn *)&
- (qos_parameters->aifs[0]);
- u8 acm = pAciAifsn->f.acm;
- u8 AcmCtrl = rtl92e_readb(dev, ACM_HW_CTRL);
-
- if (acm) {
- switch (eACI) {
- case AC0_BE:
- AcmCtrl |= ACM_HW_BEQ_EN;
- break;
-
- case AC2_VI:
- AcmCtrl |= ACM_HW_VIQ_EN;
- break;
-
- case AC3_VO:
- AcmCtrl |= ACM_HW_VOQ_EN;
- break;
- }
- } else {
- switch (eACI) {
- case AC0_BE:
- AcmCtrl &= (~ACM_HW_BEQ_EN);
- break;
-
- case AC2_VI:
- AcmCtrl &= (~ACM_HW_VIQ_EN);
- break;
-
- case AC3_VO:
- AcmCtrl &= (~ACM_HW_BEQ_EN);
- break;
-
- default:
- break;
- }
- }
- rtl92e_writeb(dev, ACM_HW_CTRL, AcmCtrl);
- break;
- }
-
- case HW_VAR_SIFS:
- rtl92e_writeb(dev, SIFS, val[0]);
- rtl92e_writeb(dev, SIFS + 1, val[0]);
- break;
-
- case HW_VAR_RF_TIMING:
- {
- u8 Rf_Timing = *val;
-
- rtl92e_writeb(dev, rFPGA0_RFTiming1, Rf_Timing);
- break;
- }
-
- default:
- break;
- }
-}
-
-static void _rtl92e_read_eeprom_info(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- const u8 bMac_Tmp_Addr[ETH_ALEN] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x01};
- u8 tempval;
- u8 ICVer8192, ICVer8256;
- u16 i, usValue, IC_Version;
- u16 EEPROMId;
-
- EEPROMId = rtl92e_eeprom_read(dev, 0);
- if (EEPROMId != RTL8190_EEPROM_ID) {
- netdev_err(dev, "%s(): Invalid EEPROM ID: %x\n", __func__,
- EEPROMId);
- priv->autoload_fail_flag = true;
- } else {
- priv->autoload_fail_flag = false;
- }
-
- if (!priv->autoload_fail_flag) {
- priv->eeprom_vid = rtl92e_eeprom_read(dev, EEPROM_VID >> 1);
- priv->eeprom_did = rtl92e_eeprom_read(dev, EEPROM_DID >> 1);
-
- usValue = rtl92e_eeprom_read(dev,
- (EEPROM_Customer_ID >> 1)) >> 8;
- priv->eeprom_customer_id = usValue & 0xff;
- usValue = rtl92e_eeprom_read(dev,
- EEPROM_ICVersion_ChannelPlan >> 1);
- IC_Version = (usValue & 0xff00) >> 8;
-
- ICVer8192 = IC_Version & 0xf;
- ICVer8256 = (IC_Version & 0xf0) >> 4;
- if (ICVer8192 == 0x2) {
- if (ICVer8256 == 0x5)
- priv->card_8192_version = VERSION_8190_BE;
- }
- switch (priv->card_8192_version) {
- case VERSION_8190_BD:
- case VERSION_8190_BE:
- break;
- default:
- priv->card_8192_version = VERSION_8190_BD;
- break;
- }
- } else {
- priv->card_8192_version = VERSION_8190_BD;
- priv->eeprom_vid = 0;
- priv->eeprom_did = 0;
- priv->eeprom_customer_id = 0;
- }
-
- if (!priv->autoload_fail_flag) {
- u8 addr[ETH_ALEN];
-
- for (i = 0; i < 6; i += 2) {
- usValue = rtl92e_eeprom_read(dev,
- (EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1);
- *(u16 *)(&addr[i]) = usValue;
- }
- eth_hw_addr_set(dev, addr);
- } else {
- eth_hw_addr_set(dev, bMac_Tmp_Addr);
- }
-
- if (priv->card_8192_version > VERSION_8190_BD)
- priv->tx_pwr_data_read_from_eeprom = true;
- else
- priv->tx_pwr_data_read_from_eeprom = false;
-
- if (priv->card_8192_version > VERSION_8190_BD) {
- if (!priv->autoload_fail_flag) {
- tempval = (rtl92e_eeprom_read(dev,
- (EEPROM_RFInd_PowerDiff >> 1))) & 0xff;
- priv->eeprom_legacy_ht_tx_pwr_diff = tempval & 0xf;
- } else {
- priv->eeprom_legacy_ht_tx_pwr_diff = 0x04;
- }
-
- if (!priv->autoload_fail_flag)
- priv->eeprom_thermal_meter = ((rtl92e_eeprom_read(dev,
- (EEPROM_ThermalMeter >> 1))) &
- 0xff00) >> 8;
- else
- priv->eeprom_thermal_meter = EEPROM_Default_ThermalMeter;
- priv->tssi_13dBm = priv->eeprom_thermal_meter * 100;
-
- if (priv->epromtype == EEPROM_93C46) {
- if (!priv->autoload_fail_flag) {
- usValue = rtl92e_eeprom_read(dev,
- EEPROM_TxPwDiff_CrystalCap >> 1);
- priv->eeprom_ant_pwr_diff = usValue & 0x0fff;
- priv->eeprom_crystal_cap = (usValue & 0xf000)
- >> 12;
- } else {
- priv->eeprom_ant_pwr_diff =
- EEPROM_Default_AntTxPowerDiff;
- priv->eeprom_crystal_cap =
- EEPROM_Default_TxPwDiff_CrystalCap;
- }
-
- for (i = 0; i < 14; i += 2) {
- if (!priv->autoload_fail_flag)
- usValue = rtl92e_eeprom_read(dev,
- (EEPROM_TxPwIndex_CCK + i) >> 1);
- else
- usValue = EEPROM_Default_TxPower;
- *((u16 *)(&priv->eeprom_tx_pwr_level_cck[i])) =
- usValue;
- }
- for (i = 0; i < 14; i += 2) {
- if (!priv->autoload_fail_flag)
- usValue = rtl92e_eeprom_read(dev,
- (EEPROM_TxPwIndex_OFDM_24G + i) >> 1);
- else
- usValue = EEPROM_Default_TxPower;
- *((u16 *)(&priv->eeprom_tx_pwr_level_ofdm24g[i]))
- = usValue;
- }
- }
- if (priv->epromtype == EEPROM_93C46) {
- for (i = 0; i < 14; i++) {
- priv->tx_pwr_level_cck[i] =
- priv->eeprom_tx_pwr_level_cck[i];
- priv->tx_pwr_level_ofdm_24g[i] =
- priv->eeprom_tx_pwr_level_ofdm24g[i];
- }
- priv->legacy_ht_tx_pwr_diff =
- priv->eeprom_legacy_ht_tx_pwr_diff;
- priv->antenna_tx_pwr_diff[0] = priv->eeprom_ant_pwr_diff & 0xf;
- priv->antenna_tx_pwr_diff[1] = (priv->eeprom_ant_pwr_diff &
- 0xf0) >> 4;
- priv->antenna_tx_pwr_diff[2] = (priv->eeprom_ant_pwr_diff &
- 0xf00) >> 8;
- priv->crystal_cap = priv->eeprom_crystal_cap;
- priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf;
- priv->thermal_meter[1] = (priv->eeprom_thermal_meter &
- 0xf0) >> 4;
- } else if (priv->epromtype == EEPROM_93C56) {
- priv->legacy_ht_tx_pwr_diff =
- priv->eeprom_legacy_ht_tx_pwr_diff;
- priv->antenna_tx_pwr_diff[0] = 0;
- priv->antenna_tx_pwr_diff[1] = 0;
- priv->antenna_tx_pwr_diff[2] = 0;
- priv->crystal_cap = priv->eeprom_crystal_cap;
- priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf;
- priv->thermal_meter[1] = (priv->eeprom_thermal_meter &
- 0xf0) >> 4;
- }
- }
-
- rtl92e_init_adaptive_rate(dev);
-
- switch (priv->eeprom_customer_id) {
- case EEPROM_CID_NetCore:
- priv->customer_id = RT_CID_819X_NETCORE;
- break;
- case EEPROM_CID_TOSHIBA:
- priv->customer_id = RT_CID_TOSHIBA;
- break;
- }
-
- if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304)
- priv->rtllib->bSupportRemoteWakeUp = true;
- else
- priv->rtllib->bSupportRemoteWakeUp = false;
-}
-
-void rtl92e_get_eeprom_size(struct net_device *dev)
-{
- u16 curCR;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- curCR = rtl92e_readw(dev, EPROM_CMD);
- priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 :
- EEPROM_93C46;
- _rtl92e_read_eeprom_info(dev);
-}
-
-static void _rtl92e_hwconfig(struct net_device *dev)
-{
- u32 regRATR = 0, regRRSR = 0;
- u8 regBwOpMode = 0, regTmp = 0;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- switch (priv->rtllib->mode) {
- case WIRELESS_MODE_B:
- regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK;
- regRRSR = RATE_ALL_CCK;
- break;
- case WIRELESS_MODE_AUTO:
- case WIRELESS_MODE_N_24G:
- regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
- RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- break;
- case WIRELESS_MODE_G:
- default:
- regBwOpMode = BW_OPMODE_20MHZ;
- regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
- break;
- }
-
- rtl92e_writeb(dev, BW_OPMODE, regBwOpMode);
- {
- u32 ratr_value;
-
- ratr_value = regRATR;
- ratr_value &= ~(RATE_ALL_OFDM_2SS);
- rtl92e_writel(dev, RATR0, ratr_value);
- rtl92e_writeb(dev, UFWP, 1);
- }
- regTmp = rtl92e_readb(dev, 0x313);
- regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff);
- rtl92e_writel(dev, RRSR, regRRSR);
-
- rtl92e_writew(dev, RETRY_LIMIT,
- priv->short_retry_limit << RETRY_LIMIT_SHORT_SHIFT |
- priv->long_retry_limit << RETRY_LIMIT_LONG_SHIFT);
-}
-
-bool rtl92e_start_adapter(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 ulRegRead;
- bool rtStatus = true;
- u8 tmpvalue;
- u8 ICVersion, SwitchingRegulatorOutput;
- bool bfirmwareok = true;
- u32 tmpRegA, TempCCk;
- int i = 0;
- u32 retry_times = 0;
-
- priv->being_init_adapter = true;
-
-start:
- rtl92e_reset_desc_ring(dev);
- priv->rf_mode = RF_OP_By_SW_3wire;
-
- rtl92e_writeb(dev, ANAPAR, 0x37);
- mdelay(500);
-
- priv->fw_info->status = FW_STATUS_0_INIT;
-
- ulRegRead = rtl92e_readl(dev, CPU_GEN);
- if (priv->fw_info->status == FW_STATUS_0_INIT)
- ulRegRead |= CPU_GEN_SYSTEM_RESET;
- else if (priv->fw_info->status == FW_STATUS_5_READY)
- ulRegRead |= CPU_GEN_FIRMWARE_RESET;
- else
- netdev_err(dev, "%s(): undefined firmware state: %d.\n",
- __func__, priv->fw_info->status);
-
- rtl92e_writel(dev, CPU_GEN, ulRegRead);
-
- ICVersion = rtl92e_readb(dev, IC_VERRSION);
- if (ICVersion >= 0x4) {
- SwitchingRegulatorOutput = rtl92e_readb(dev, SWREGULATOR);
- if (SwitchingRegulatorOutput != 0xb8) {
- rtl92e_writeb(dev, SWREGULATOR, 0xa8);
- mdelay(1);
- rtl92e_writeb(dev, SWREGULATOR, 0xb8);
- }
- }
- rtStatus = rtl92e_config_bb(dev);
- if (!rtStatus) {
- netdev_warn(dev, "%s(): Failed to configure BB\n", __func__);
- return rtStatus;
- }
-
- priv->loopback_mode = RTL819X_NO_LOOPBACK;
- ulRegRead = rtl92e_readl(dev, CPU_GEN);
- if (priv->loopback_mode == RTL819X_NO_LOOPBACK)
- ulRegRead = (ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) |
- CPU_GEN_NO_LOOPBACK_SET;
- else if (priv->loopback_mode == RTL819X_MAC_LOOPBACK)
- ulRegRead |= CPU_CCK_LOOPBACK;
- else
- netdev_err(dev, "%s: Invalid loopback mode setting.\n",
- __func__);
-
- rtl92e_writel(dev, CPU_GEN, ulRegRead);
-
- udelay(500);
-
- _rtl92e_hwconfig(dev);
- rtl92e_writeb(dev, CMDR, CR_RE | CR_TE);
-
- rtl92e_writeb(dev, PCIF, ((MXDMA2_NO_LIMIT << MXDMA2_RX_SHIFT) |
- (MXDMA2_NO_LIMIT << MXDMA2_TX_SHIFT)));
- rtl92e_writel(dev, MAC0, ((u32 *)dev->dev_addr)[0]);
- rtl92e_writew(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]);
- rtl92e_writel(dev, RCR, priv->receive_config);
-
- rtl92e_writel(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK <<
- RSVD_FW_QUEUE_PAGE_BK_SHIFT |
- NUM_OF_PAGE_IN_FW_QUEUE_BE <<
- RSVD_FW_QUEUE_PAGE_BE_SHIFT |
- NUM_OF_PAGE_IN_FW_QUEUE_VI <<
- RSVD_FW_QUEUE_PAGE_VI_SHIFT |
- NUM_OF_PAGE_IN_FW_QUEUE_VO <<
- RSVD_FW_QUEUE_PAGE_VO_SHIFT);
- rtl92e_writel(dev, RQPN2, NUM_OF_PAGE_IN_FW_QUEUE_MGNT <<
- RSVD_FW_QUEUE_PAGE_MGNT_SHIFT);
- rtl92e_writel(dev, RQPN3, APPLIED_RESERVED_QUEUE_IN_FW |
- NUM_OF_PAGE_IN_FW_QUEUE_BCN <<
- RSVD_FW_QUEUE_PAGE_BCN_SHIFT |
- NUM_OF_PAGE_IN_FW_QUEUE_PUB <<
- RSVD_FW_QUEUE_PAGE_PUB_SHIFT);
-
- rtl92e_tx_enable(dev);
- rtl92e_rx_enable(dev);
- ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) |
- RATE_ALL_OFDM_AG | RATE_ALL_CCK;
- rtl92e_writel(dev, RRSR, ulRegRead);
- rtl92e_writel(dev, RATR0 + 4 * 7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK));
-
- rtl92e_writeb(dev, ACK_TIMEOUT, 0x30);
-
- rtl92e_set_wireless_mode(dev, priv->rtllib->mode);
- rtl92e_cam_reset(dev);
- {
- u8 SECR_value = 0x0;
-
- SECR_value |= SCR_TxEncEnable;
- SECR_value |= SCR_RxDecEnable;
- SECR_value |= SCR_NoSKMC;
- rtl92e_writeb(dev, SECR, SECR_value);
- }
- rtl92e_writew(dev, ATIMWND, 2);
- rtl92e_writew(dev, BCN_INTERVAL, 100);
-
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- rtl92e_writel(dev, WDCAPARA_ADD[i], 0x005e4332);
-
- rtl92e_writeb(dev, 0xbe, 0xc0);
-
- rtl92e_config_mac(dev);
-
- if (priv->card_8192_version > VERSION_8190_BD) {
- rtl92e_get_tx_power(dev);
- rtl92e_set_tx_power(dev, priv->chan);
- }
-
- tmpvalue = rtl92e_readb(dev, IC_VERRSION);
- priv->ic_cut = tmpvalue;
-
- bfirmwareok = rtl92e_init_fw(dev);
- if (!bfirmwareok) {
- if (retry_times < 10) {
- retry_times++;
- goto start;
- } else {
- rtStatus = false;
- goto end;
- }
- }
-
- rtStatus = rtl92e_config_rf(dev);
- if (!rtStatus) {
- netdev_info(dev, "RF Config failed\n");
- return rtStatus;
- }
-
- rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn, 0x1);
- rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1);
-
- rtl92e_writeb(dev, 0x87, 0x0);
-
- if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_PS) {
- rtl92e_set_rf_state(dev, rf_off, priv->rtllib->rf_off_reason);
- } else if (priv->rtllib->rf_off_reason >= RF_CHANGE_BY_IPS) {
- rtl92e_set_rf_state(dev, rf_off, priv->rtllib->rf_off_reason);
- } else {
- priv->rtllib->rf_power_state = rf_on;
- priv->rtllib->rf_off_reason = 0;
- }
-
- if (priv->rtllib->FwRWRF)
- priv->rf_mode = RF_OP_By_FW;
- else
- priv->rf_mode = RF_OP_By_SW_3wire;
-
- rtl92e_dm_init_txpower_tracking(dev);
-
- if (priv->ic_cut >= IC_VersionCut_D) {
- tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance,
- bMaskDWord);
- rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord);
-
- for (i = 0; i < TX_BB_GAIN_TABLE_LEN; i++) {
- if (tmpRegA == dm_tx_bb_gain[i]) {
- priv->rfa_txpowertrackingindex = i;
- priv->rfa_txpowertrackingindex_real = i;
- priv->rfa_txpowertracking_default =
- priv->rfa_txpowertrackingindex;
- break;
- }
- }
-
- TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1,
- bMaskByte2);
-
- for (i = 0; i < CCK_TX_BB_GAIN_TABLE_LEN; i++) {
- if (TempCCk == dm_cck_tx_bb_gain[i][0]) {
- priv->cck_present_attn_20m_def = i;
- break;
- }
- }
- priv->cck_present_attn_40m_def = 0;
- priv->cck_present_attn_diff = 0;
- priv->cck_present_attn =
- priv->cck_present_attn_20m_def;
- priv->btxpower_tracking = false;
- }
- rtl92e_irq_enable(dev);
-end:
- priv->being_init_adapter = false;
- return rtStatus;
-}
-
-static void _rtl92e_net_update(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_network *net;
- u16 rate_config = 0;
-
- net = &priv->rtllib->current_network;
- rtl92e_config_rate(dev, &rate_config);
- priv->dot11_current_preamble_mode = PREAMBLE_AUTO;
- priv->basic_rate = rate_config &= 0x15f;
- rtl92e_writew(dev, BSSIDR, *(u16 *)net->bssid);
- rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(net->bssid + 2));
-}
-
-void rtl92e_link_change(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- if (!priv->up)
- return;
-
- if (ieee->link_state == MAC80211_LINKED) {
- _rtl92e_net_update(dev);
- rtl92e_update_ratr_table(dev);
- if ((ieee->pairwise_key_type == KEY_TYPE_WEP40) ||
- (ieee->pairwise_key_type == KEY_TYPE_WEP104))
- rtl92e_enable_hw_security_config(dev);
- } else {
- rtl92e_writeb(dev, 0x173, 0);
- }
- _rtl92e_update_msr(dev);
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- u32 reg;
-
- reg = rtl92e_readl(dev, RCR);
- if (priv->rtllib->link_state == MAC80211_LINKED)
- priv->receive_config = reg |= RCR_CBSSID;
- else
- priv->receive_config = reg &= ~RCR_CBSSID;
-
- rtl92e_writel(dev, RCR, reg);
- }
-}
-
-void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da,
- bool write_into_reg)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (allow_all_da)
- priv->receive_config |= RCR_AAP;
- else
- priv->receive_config &= ~RCR_AAP;
-
- if (write_into_reg)
- rtl92e_writel(dev, RCR, priv->receive_config);
-}
-
-static u8 _rtl92e_rate_mgn_to_hw(u8 rate)
-{
- u8 ret = DESC90_RATE1M;
-
- switch (rate) {
- case MGN_1M:
- ret = DESC90_RATE1M;
- break;
- case MGN_2M:
- ret = DESC90_RATE2M;
- break;
- case MGN_5_5M:
- ret = DESC90_RATE5_5M;
- break;
- case MGN_11M:
- ret = DESC90_RATE11M;
- break;
- case MGN_6M:
- ret = DESC90_RATE6M;
- break;
- case MGN_9M:
- ret = DESC90_RATE9M;
- break;
- case MGN_12M:
- ret = DESC90_RATE12M;
- break;
- case MGN_18M:
- ret = DESC90_RATE18M;
- break;
- case MGN_24M:
- ret = DESC90_RATE24M;
- break;
- case MGN_36M:
- ret = DESC90_RATE36M;
- break;
- case MGN_48M:
- ret = DESC90_RATE48M;
- break;
- case MGN_54M:
- ret = DESC90_RATE54M;
- break;
- case MGN_MCS0:
- ret = DESC90_RATEMCS0;
- break;
- case MGN_MCS1:
- ret = DESC90_RATEMCS1;
- break;
- case MGN_MCS2:
- ret = DESC90_RATEMCS2;
- break;
- case MGN_MCS3:
- ret = DESC90_RATEMCS3;
- break;
- case MGN_MCS4:
- ret = DESC90_RATEMCS4;
- break;
- case MGN_MCS5:
- ret = DESC90_RATEMCS5;
- break;
- case MGN_MCS6:
- ret = DESC90_RATEMCS6;
- break;
- case MGN_MCS7:
- ret = DESC90_RATEMCS7;
- break;
- case MGN_MCS8:
- ret = DESC90_RATEMCS8;
- break;
- case MGN_MCS9:
- ret = DESC90_RATEMCS9;
- break;
- case MGN_MCS10:
- ret = DESC90_RATEMCS10;
- break;
- case MGN_MCS11:
- ret = DESC90_RATEMCS11;
- break;
- case MGN_MCS12:
- ret = DESC90_RATEMCS12;
- break;
- case MGN_MCS13:
- ret = DESC90_RATEMCS13;
- break;
- case MGN_MCS14:
- ret = DESC90_RATEMCS14;
- break;
- case MGN_MCS15:
- ret = DESC90_RATEMCS15;
- break;
- case (0x80 | 0x20):
- ret = DESC90_RATEMCS32;
- break;
- default:
- break;
- }
- return ret;
-}
-
-static u8 _rtl92e_hw_queue_to_fw_queue(struct net_device *dev, u8 QueueID,
- u8 priority)
-{
- u8 QueueSelect = 0x0;
-
- switch (QueueID) {
- case BE_QUEUE:
- QueueSelect = QSLT_BE;
- break;
-
- case BK_QUEUE:
- QueueSelect = QSLT_BK;
- break;
-
- case VO_QUEUE:
- QueueSelect = QSLT_VO;
- break;
-
- case VI_QUEUE:
- QueueSelect = QSLT_VI;
- break;
- case MGNT_QUEUE:
- QueueSelect = QSLT_MGNT;
- break;
- case BEACON_QUEUE:
- QueueSelect = QSLT_BEACON;
- break;
- case TXCMD_QUEUE:
- QueueSelect = QSLT_CMD;
- break;
- case HIGH_QUEUE:
- QueueSelect = QSLT_HIGH;
- break;
- default:
- netdev_warn(dev, "%s(): Impossible Queue Selection: %d\n",
- __func__, QueueID);
- break;
- }
- return QueueSelect;
-}
-
-static u8 _rtl92e_query_is_short(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc)
-{
- u8 tmp_Short;
-
- tmp_Short = (TxHT == 1) ? ((tcb_desc->use_short_gi) ? 1 : 0) :
- ((tcb_desc->use_short_preamble) ? 1 : 0);
- if (TxHT == 1 && TxRate != DESC90_RATEMCS15)
- tmp_Short = 0;
-
- return tmp_Short;
-}
-
-void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc,
- struct cb_desc *cb_desc, struct sk_buff *skb)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- dma_addr_t mapping;
- struct tx_fwinfo_8190pci *pTxFwInfo;
-
- pTxFwInfo = (struct tx_fwinfo_8190pci *)skb->data;
- memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
- pTxFwInfo->TxHT = (cb_desc->data_rate & 0x80) ? 1 : 0;
- pTxFwInfo->TxRate = _rtl92e_rate_mgn_to_hw(cb_desc->data_rate);
- pTxFwInfo->EnableCPUDur = cb_desc->tx_enable_fw_calc_dur;
- pTxFwInfo->Short = _rtl92e_query_is_short(pTxFwInfo->TxHT,
- pTxFwInfo->TxRate, cb_desc);
-
- if (cb_desc->ampdu_enable) {
- pTxFwInfo->AllowAggregation = 1;
- pTxFwInfo->RxMF = cb_desc->ampdu_factor;
- pTxFwInfo->RxAMD = cb_desc->ampdu_density;
- } else {
- pTxFwInfo->AllowAggregation = 0;
- pTxFwInfo->RxMF = 0;
- pTxFwInfo->RxAMD = 0;
- }
-
- pTxFwInfo->RtsEnable = (cb_desc->rts_enable) ? 1 : 0;
- pTxFwInfo->CtsEnable = (cb_desc->cts_enable) ? 1 : 0;
- pTxFwInfo->RtsSTBC = (cb_desc->rtsstbc) ? 1 : 0;
- pTxFwInfo->RtsHT = (cb_desc->rts_rate & 0x80) ? 1 : 0;
- pTxFwInfo->RtsRate = _rtl92e_rate_mgn_to_hw(cb_desc->rts_rate);
- pTxFwInfo->RtsBandwidth = 0;
- pTxFwInfo->RtsSubcarrier = cb_desc->RTSSC;
- pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT == 0) ?
- (cb_desc->rts_use_short_preamble ? 1 : 0) :
- (cb_desc->rts_use_short_gi ? 1 : 0);
- if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20_40) {
- if (cb_desc->packet_bw) {
- pTxFwInfo->TxBandwidth = 1;
- pTxFwInfo->TxSubCarrier = 0;
- } else {
- pTxFwInfo->TxBandwidth = 0;
- pTxFwInfo->TxSubCarrier = priv->n_cur_40mhz_prime_sc;
- }
- } else {
- pTxFwInfo->TxBandwidth = 0;
- pTxFwInfo->TxSubCarrier = 0;
- }
-
- memset((u8 *)pdesc, 0, 12);
-
- mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&priv->pdev->dev, mapping)) {
- netdev_err(dev, "%s(): DMA Mapping error\n", __func__);
- return;
- }
-
- pdesc->LINIP = 0;
- pdesc->CmdInit = 1;
- pdesc->Offset = sizeof(struct tx_fwinfo_8190pci) + 8;
- pdesc->PktSize = skb->len - sizeof(struct tx_fwinfo_8190pci);
-
- pdesc->SecCAMID = 0;
- pdesc->RATid = cb_desc->ratr_index;
-
- pdesc->NoEnc = 1;
- pdesc->SecType = 0x0;
- if (cb_desc->hw_sec) {
- static u8 tmp;
-
- if (!tmp)
- tmp = 1;
- switch (priv->rtllib->pairwise_key_type) {
- case KEY_TYPE_WEP40:
- case KEY_TYPE_WEP104:
- pdesc->SecType = 0x1;
- pdesc->NoEnc = 0;
- break;
- case KEY_TYPE_TKIP:
- pdesc->SecType = 0x2;
- pdesc->NoEnc = 0;
- break;
- case KEY_TYPE_CCMP:
- pdesc->SecType = 0x3;
- pdesc->NoEnc = 0;
- break;
- case KEY_TYPE_NA:
- pdesc->SecType = 0x0;
- pdesc->NoEnc = 1;
- break;
- }
- }
-
- pdesc->PktId = 0x0;
-
- pdesc->QueueSelect = _rtl92e_hw_queue_to_fw_queue(dev,
- cb_desc->queue_index,
- cb_desc->priority);
- pdesc->TxFWInfoSize = sizeof(struct tx_fwinfo_8190pci);
-
- pdesc->DISFB = cb_desc->tx_dis_rate_fallback;
- pdesc->USERATE = cb_desc->tx_use_drv_assinged_rate;
-
- pdesc->FirstSeg = 1;
- pdesc->LastSeg = 1;
- pdesc->TxBufferSize = skb->len;
-
- pdesc->TxBuffAddr = mapping;
-}
-
-void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry,
- struct cb_desc *cb_desc, struct sk_buff *skb)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- dma_addr_t mapping = dma_map_single(&priv->pdev->dev, skb->data,
- skb->len, DMA_TO_DEVICE);
-
- if (dma_mapping_error(&priv->pdev->dev, mapping))
- netdev_err(dev, "%s(): DMA Mapping error\n", __func__);
- memset(entry, 0, 12);
- entry->LINIP = cb_desc->last_ini_pkt;
- entry->FirstSeg = 1;
- entry->LastSeg = 1;
- if (cb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) {
- entry->CmdInit = DESC_PACKET_TYPE_INIT;
- } else {
- struct tx_desc *entry_tmp = (struct tx_desc *)entry;
-
- entry_tmp->CmdInit = DESC_PACKET_TYPE_NORMAL;
- entry_tmp->Offset = sizeof(struct tx_fwinfo_8190pci) + 8;
- entry_tmp->PktSize = cb_desc->pkt_size + entry_tmp->Offset;
- entry_tmp->QueueSelect = QSLT_CMD;
- entry_tmp->TxFWInfoSize = 0x08;
- entry_tmp->RATid = DESC_PACKET_TYPE_INIT;
- }
- entry->TxBufferSize = skb->len;
- entry->TxBuffAddr = mapping;
- entry->OWN = 1;
-}
-
-static u8 _rtl92e_rate_hw_to_mgn(bool bIsHT, u8 rate)
-{
- u8 ret_rate = 0x02;
-
- if (!bIsHT) {
- switch (rate) {
- case DESC90_RATE1M:
- ret_rate = MGN_1M;
- break;
- case DESC90_RATE2M:
- ret_rate = MGN_2M;
- break;
- case DESC90_RATE5_5M:
- ret_rate = MGN_5_5M;
- break;
- case DESC90_RATE11M:
- ret_rate = MGN_11M;
- break;
- case DESC90_RATE6M:
- ret_rate = MGN_6M;
- break;
- case DESC90_RATE9M:
- ret_rate = MGN_9M;
- break;
- case DESC90_RATE12M:
- ret_rate = MGN_12M;
- break;
- case DESC90_RATE18M:
- ret_rate = MGN_18M;
- break;
- case DESC90_RATE24M:
- ret_rate = MGN_24M;
- break;
- case DESC90_RATE36M:
- ret_rate = MGN_36M;
- break;
- case DESC90_RATE48M:
- ret_rate = MGN_48M;
- break;
- case DESC90_RATE54M:
- ret_rate = MGN_54M;
- break;
- }
-
- } else {
- switch (rate) {
- case DESC90_RATEMCS0:
- ret_rate = MGN_MCS0;
- break;
- case DESC90_RATEMCS1:
- ret_rate = MGN_MCS1;
- break;
- case DESC90_RATEMCS2:
- ret_rate = MGN_MCS2;
- break;
- case DESC90_RATEMCS3:
- ret_rate = MGN_MCS3;
- break;
- case DESC90_RATEMCS4:
- ret_rate = MGN_MCS4;
- break;
- case DESC90_RATEMCS5:
- ret_rate = MGN_MCS5;
- break;
- case DESC90_RATEMCS6:
- ret_rate = MGN_MCS6;
- break;
- case DESC90_RATEMCS7:
- ret_rate = MGN_MCS7;
- break;
- case DESC90_RATEMCS8:
- ret_rate = MGN_MCS8;
- break;
- case DESC90_RATEMCS9:
- ret_rate = MGN_MCS9;
- break;
- case DESC90_RATEMCS10:
- ret_rate = MGN_MCS10;
- break;
- case DESC90_RATEMCS11:
- ret_rate = MGN_MCS11;
- break;
- case DESC90_RATEMCS12:
- ret_rate = MGN_MCS12;
- break;
- case DESC90_RATEMCS13:
- ret_rate = MGN_MCS13;
- break;
- case DESC90_RATEMCS14:
- ret_rate = MGN_MCS14;
- break;
- case DESC90_RATEMCS15:
- ret_rate = MGN_MCS15;
- break;
- case DESC90_RATEMCS32:
- ret_rate = 0x80 | 0x20;
- break;
- }
- }
-
- return ret_rate;
-}
-
-static long _rtl92e_signal_scale_mapping(struct r8192_priv *priv, long currsig)
-{
- long retsig;
-
- if (currsig >= 61 && currsig <= 100)
- retsig = 90 + ((currsig - 60) / 4);
- else if (currsig >= 41 && currsig <= 60)
- retsig = 78 + ((currsig - 40) / 2);
- else if (currsig >= 31 && currsig <= 40)
- retsig = 66 + (currsig - 30);
- else if (currsig >= 21 && currsig <= 30)
- retsig = 54 + (currsig - 20);
- else if (currsig >= 5 && currsig <= 20)
- retsig = 42 + (((currsig - 5) * 2) / 3);
- else if (currsig == 4)
- retsig = 36;
- else if (currsig == 3)
- retsig = 27;
- else if (currsig == 2)
- retsig = 18;
- else if (currsig == 1)
- retsig = 9;
- else
- retsig = currsig;
-
- return retsig;
-}
-
-#define rx_hal_is_cck_rate(_pdrvinfo)\
- ((_pdrvinfo->RxRate == DESC90_RATE1M ||\
- _pdrvinfo->RxRate == DESC90_RATE2M ||\
- _pdrvinfo->RxRate == DESC90_RATE5_5M ||\
- _pdrvinfo->RxRate == DESC90_RATE11M) &&\
- !_pdrvinfo->RxHT)
-
-static void _rtl92e_query_rxphystatus(struct r8192_priv *priv,
- struct rtllib_rx_stats *pstats,
- struct rx_desc *pdesc,
- struct rx_fwinfo *pdrvinfo,
- struct rtllib_rx_stats *precord_stats,
- bool bpacket_match_bssid,
- bool bpacket_toself,
- bool bPacketBeacon,
- bool bToSelfBA)
-{
- struct phy_sts_ofdm_819xpci *pofdm_buf;
- struct phy_sts_cck_819xpci *pcck_buf;
- u8 *prxpkt;
- u8 i, max_spatial_stream, tmp_rxevm;
- s8 rx_pwr[RF90_PATH_MAX], rx_pwr_all = 0;
- s8 rx_evmX;
- u8 evm, pwdb_all;
- u32 RSSI, total_rssi = 0;
- u8 is_cck_rate = 0;
- u8 rf_rx_num = 0;
- static u8 check_reg824;
- static u32 reg824_bit9;
-
- is_cck_rate = rx_hal_is_cck_rate(pdrvinfo);
- memset(precord_stats, 0, sizeof(struct rtllib_rx_stats));
- pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID =
- bpacket_match_bssid;
- pstats->packet_to_self = precord_stats->packet_to_self = bpacket_toself;
- pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate;
- pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon;
- pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA;
- if (check_reg824 == 0) {
- reg824_bit9 = rtl92e_get_bb_reg(priv->rtllib->dev,
- rFPGA0_XA_HSSIParameter2,
- 0x200);
- check_reg824 = 1;
- }
-
- prxpkt = (u8 *)pdrvinfo;
-
- prxpkt += sizeof(struct rx_fwinfo);
-
- pcck_buf = (struct phy_sts_cck_819xpci *)prxpkt;
- pofdm_buf = (struct phy_sts_ofdm_819xpci *)prxpkt;
-
- pstats->RxMIMOSignalQuality[0] = -1;
- pstats->RxMIMOSignalQuality[1] = -1;
- precord_stats->RxMIMOSignalQuality[0] = -1;
- precord_stats->RxMIMOSignalQuality[1] = -1;
-
- if (is_cck_rate) {
- u8 report;
-
- if (!reg824_bit9) {
- report = pcck_buf->cck_agc_rpt & 0xc0;
- report >>= 6;
- switch (report) {
- case 0x3:
- rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt &
- 0x3e);
- break;
- case 0x2:
- rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt &
- 0x3e);
- break;
- case 0x1:
- rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt &
- 0x3e);
- break;
- case 0x0:
- rx_pwr_all = 8 - (pcck_buf->cck_agc_rpt & 0x3e);
- break;
- }
- } else {
- report = pcck_buf->cck_agc_rpt & 0x60;
- report >>= 5;
- switch (report) {
- case 0x3:
- rx_pwr_all = -35 -
- ((pcck_buf->cck_agc_rpt &
- 0x1f) << 1);
- break;
- case 0x2:
- rx_pwr_all = -23 -
- ((pcck_buf->cck_agc_rpt &
- 0x1f) << 1);
- break;
- case 0x1:
- rx_pwr_all = -11 -
- ((pcck_buf->cck_agc_rpt &
- 0x1f) << 1);
- break;
- case 0x0:
- rx_pwr_all = -8 -
- ((pcck_buf->cck_agc_rpt &
- 0x1f) << 1);
- break;
- }
- }
-
- pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all);
- pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all;
- pstats->RecvSignalPower = rx_pwr_all;
-
- if (bpacket_match_bssid) {
- u8 sq;
-
- if (pstats->RxPWDBAll > 40) {
- sq = 100;
- } else {
- sq = pcck_buf->sq_rpt;
-
- if (pcck_buf->sq_rpt > 64)
- sq = 0;
- else if (pcck_buf->sq_rpt < 20)
- sq = 100;
- else
- sq = ((64 - sq) * 100) / 44;
- }
- pstats->signal_quality = sq;
- precord_stats->signal_quality = sq;
- pstats->RxMIMOSignalQuality[0] = sq;
- precord_stats->RxMIMOSignalQuality[0] = sq;
- pstats->RxMIMOSignalQuality[1] = -1;
- precord_stats->RxMIMOSignalQuality[1] = -1;
- }
- } else {
- for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
- if (priv->brfpath_rxenable[i])
- rf_rx_num++;
-
- rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i] & 0x3F) *
- 2) - 110;
-
- RSSI = rtl92e_rx_db_to_percent(rx_pwr[i]);
- if (priv->brfpath_rxenable[i])
- total_rssi += RSSI;
-
- if (bpacket_match_bssid) {
- pstats->RxMIMOSignalStrength[i] = RSSI;
- precord_stats->RxMIMOSignalStrength[i] = RSSI;
- }
- }
-
- rx_pwr_all = (((pofdm_buf->pwdb_all) >> 1) & 0x7f) - 106;
- pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all);
-
- pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all;
- pstats->RecvSignalPower = rx_pwr_all;
- if (pdrvinfo->RxHT && pdrvinfo->RxRate >= DESC90_RATEMCS8 &&
- pdrvinfo->RxRate <= DESC90_RATEMCS15)
- max_spatial_stream = 2;
- else
- max_spatial_stream = 1;
-
- for (i = 0; i < max_spatial_stream; i++) {
- tmp_rxevm = pofdm_buf->rxevm_X[i];
- rx_evmX = (s8)(tmp_rxevm);
-
- rx_evmX /= 2;
-
- evm = rtl92e_evm_db_to_percent(rx_evmX);
- if (bpacket_match_bssid) {
- if (i == 0) {
- pstats->signal_quality = evm & 0xff;
- precord_stats->signal_quality = evm & 0xff;
- }
- pstats->RxMIMOSignalQuality[i] = evm & 0xff;
- precord_stats->RxMIMOSignalQuality[i] = evm & 0xff;
- }
- }
- }
-
- if (is_cck_rate) {
- pstats->signal_strength = precord_stats->signal_strength =
- _rtl92e_signal_scale_mapping(priv, (long)pwdb_all);
-
- } else {
- if (rf_rx_num != 0)
- pstats->signal_strength = precord_stats->signal_strength =
- _rtl92e_signal_scale_mapping(priv,
- (long)(total_rssi /= rf_rx_num));
- }
-}
-
-static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
- struct rtllib_rx_stats *prev_st,
- struct rtllib_rx_stats *curr_st)
-{
- bool bcheck = false;
- u8 rfpath;
- u32 ij, tmp_val;
- static u32 slide_rssi_index, slide_rssi_statistics;
- static u32 slide_evm_index, slide_evm_statistics;
- static u32 last_rssi, last_evm;
- static u32 slide_beacon_adc_pwdb_index;
- static u32 slide_beacon_adc_pwdb_statistics;
- static u32 last_beacon_adc_pwdb;
-
- if (!prev_st->bIsAMPDU)
- bcheck = true;
-
- if (slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) {
- slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX;
- last_rssi = priv->stats.slide_signal_strength[slide_rssi_index];
- priv->stats.slide_rssi_total -= last_rssi;
- }
- priv->stats.slide_rssi_total += prev_st->signal_strength;
-
- priv->stats.slide_signal_strength[slide_rssi_index++] =
- prev_st->signal_strength;
- if (slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX)
- slide_rssi_index = 0;
-
- tmp_val = priv->stats.slide_rssi_total / slide_rssi_statistics;
- priv->stats.signal_strength = rtl92e_translate_to_dbm(priv, tmp_val);
- curr_st->rssi = priv->stats.signal_strength;
- if (!prev_st->bPacketMatchBSSID) {
- if (!prev_st->bToSelfBA)
- return;
- }
-
- if (!bcheck)
- return;
-
- if (!prev_st->bIsCCK && prev_st->packet_to_self) {
- for (rfpath = RF90_PATH_A; rfpath < priv->num_total_rf_path; rfpath++) {
- if (priv->stats.rx_rssi_percentage[rfpath] == 0) {
- priv->stats.rx_rssi_percentage[rfpath] =
- prev_st->RxMIMOSignalStrength[rfpath];
- }
- if (prev_st->RxMIMOSignalStrength[rfpath] >
- priv->stats.rx_rssi_percentage[rfpath]) {
- priv->stats.rx_rssi_percentage[rfpath] =
- ((priv->stats.rx_rssi_percentage[rfpath]
- * (RX_SMOOTH - 1)) +
- (prev_st->RxMIMOSignalStrength
- [rfpath])) / (RX_SMOOTH);
- priv->stats.rx_rssi_percentage[rfpath] =
- priv->stats.rx_rssi_percentage[rfpath]
- + 1;
- } else {
- priv->stats.rx_rssi_percentage[rfpath] =
- ((priv->stats.rx_rssi_percentage[rfpath] *
- (RX_SMOOTH - 1)) +
- (prev_st->RxMIMOSignalStrength[rfpath])) /
- (RX_SMOOTH);
- }
- }
- }
-
- if (prev_st->bPacketBeacon) {
- if (slide_beacon_adc_pwdb_statistics++ >=
- PHY_Beacon_RSSI_SLID_WIN_MAX) {
- slide_beacon_adc_pwdb_statistics =
- PHY_Beacon_RSSI_SLID_WIN_MAX;
- last_beacon_adc_pwdb = priv->stats.slide_beacon_pwdb
- [slide_beacon_adc_pwdb_index];
- priv->stats.slide_beacon_total -= last_beacon_adc_pwdb;
- }
- priv->stats.slide_beacon_total += prev_st->RxPWDBAll;
- priv->stats.slide_beacon_pwdb[slide_beacon_adc_pwdb_index] =
- prev_st->RxPWDBAll;
- slide_beacon_adc_pwdb_index++;
- if (slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX)
- slide_beacon_adc_pwdb_index = 0;
- prev_st->RxPWDBAll = priv->stats.slide_beacon_total /
- slide_beacon_adc_pwdb_statistics;
- if (prev_st->RxPWDBAll >= 3)
- prev_st->RxPWDBAll -= 3;
- }
- if (prev_st->packet_to_self || prev_st->bPacketBeacon ||
- prev_st->bToSelfBA) {
- if (priv->undecorated_smoothed_pwdb < 0)
- priv->undecorated_smoothed_pwdb = prev_st->RxPWDBAll;
- if (prev_st->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) {
- priv->undecorated_smoothed_pwdb =
- (((priv->undecorated_smoothed_pwdb) *
- (RX_SMOOTH - 1)) +
- (prev_st->RxPWDBAll)) / (RX_SMOOTH);
- priv->undecorated_smoothed_pwdb =
- priv->undecorated_smoothed_pwdb + 1;
- } else {
- priv->undecorated_smoothed_pwdb =
- (((priv->undecorated_smoothed_pwdb) *
- (RX_SMOOTH - 1)) +
- (prev_st->RxPWDBAll)) / (RX_SMOOTH);
- }
- rtl92e_update_rx_statistics(priv, prev_st);
- }
-
- if (prev_st->signal_quality != 0) {
- if (prev_st->packet_to_self || prev_st->bPacketBeacon ||
- prev_st->bToSelfBA) {
- if (slide_evm_statistics++ >= PHY_RSSI_SLID_WIN_MAX) {
- slide_evm_statistics = PHY_RSSI_SLID_WIN_MAX;
- last_evm =
- priv->stats.slide_evm[slide_evm_index];
- priv->stats.slide_evm_total -= last_evm;
- }
-
- priv->stats.slide_evm_total += prev_st->signal_quality;
-
- priv->stats.slide_evm[slide_evm_index++] =
- prev_st->signal_quality;
- if (slide_evm_index >= PHY_RSSI_SLID_WIN_MAX)
- slide_evm_index = 0;
-
- tmp_val = priv->stats.slide_evm_total /
- slide_evm_statistics;
- priv->stats.last_signal_strength_inpercent = tmp_val;
- }
-
- if (prev_st->packet_to_self ||
- prev_st->bPacketBeacon ||
- prev_st->bToSelfBA) {
- for (ij = 0; ij < 2; ij++) {
- if (prev_st->RxMIMOSignalQuality[ij] != -1) {
- if (priv->stats.rx_evm_percentage[ij] == 0)
- priv->stats.rx_evm_percentage[ij] =
- prev_st->RxMIMOSignalQuality[ij];
- priv->stats.rx_evm_percentage[ij] =
- ((priv->stats.rx_evm_percentage[ij] *
- (RX_SMOOTH - 1)) +
- (prev_st->RxMIMOSignalQuality[ij])) /
- (RX_SMOOTH);
- }
- }
- }
- }
-}
-
-static void _rtl92e_translate_rx_signal_stats(struct net_device *dev,
- struct sk_buff *skb,
- struct rtllib_rx_stats *pstats,
- struct rx_desc *pdesc,
- struct rx_fwinfo *pdrvinfo)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- bool bpacket_match_bssid, bpacket_toself;
- bool bPacketBeacon = false;
- struct ieee80211_hdr_3addr *hdr;
- bool bToSelfBA = false;
- static struct rtllib_rx_stats previous_stats;
- u16 fc, type;
- u8 *tmp_buf;
- u8 *praddr;
-
- tmp_buf = skb->data + pstats->rx_drv_info_size + pstats->rx_buf_shift;
-
- hdr = (struct ieee80211_hdr_3addr *)tmp_buf;
- fc = le16_to_cpu(hdr->frame_control);
- type = WLAN_FC_GET_TYPE(fc);
- praddr = hdr->addr1;
-
- bpacket_match_bssid =
- ((type != RTLLIB_FTYPE_CTL) &&
- ether_addr_equal(priv->rtllib->current_network.bssid,
- (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 :
- (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 :
- hdr->addr3) &&
- (!pstats->hw_error) && (!pstats->bCRC) && (!pstats->bICV));
- bpacket_toself = bpacket_match_bssid && /* check this */
- ether_addr_equal(praddr, priv->rtllib->dev->dev_addr);
- if (ieee80211_is_beacon(hdr->frame_control))
- bPacketBeacon = true;
- _rtl92e_process_phyinfo(priv, tmp_buf, &previous_stats, pstats);
- _rtl92e_query_rxphystatus(priv, pstats, pdesc, pdrvinfo,
- &previous_stats, bpacket_match_bssid,
- bpacket_toself, bPacketBeacon, bToSelfBA);
- rtl92e_copy_mpdu_stats(pstats, &previous_stats);
-}
-
-static void _rtl92e_update_received_rate_histogram_stats(struct net_device *dev,
- struct rtllib_rx_stats *pstats)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- u32 rcvType = 1;
- u32 rate_index;
-
- if (pstats->bCRC)
- rcvType = 2;
- else if (pstats->bICV)
- rcvType = 3;
-
- switch (pstats->rate) {
- case MGN_1M:
- rate_index = 0;
- break;
- case MGN_2M:
- rate_index = 1;
- break;
- case MGN_5_5M:
- rate_index = 2;
- break;
- case MGN_11M:
- rate_index = 3;
- break;
- case MGN_6M:
- rate_index = 4;
- break;
- case MGN_9M:
- rate_index = 5;
- break;
- case MGN_12M:
- rate_index = 6;
- break;
- case MGN_18M:
- rate_index = 7;
- break;
- case MGN_24M:
- rate_index = 8;
- break;
- case MGN_36M:
- rate_index = 9;
- break;
- case MGN_48M:
- rate_index = 10;
- break;
- case MGN_54M:
- rate_index = 11;
- break;
- case MGN_MCS0:
- rate_index = 12;
- break;
- case MGN_MCS1:
- rate_index = 13;
- break;
- case MGN_MCS2:
- rate_index = 14;
- break;
- case MGN_MCS3:
- rate_index = 15;
- break;
- case MGN_MCS4:
- rate_index = 16;
- break;
- case MGN_MCS5:
- rate_index = 17;
- break;
- case MGN_MCS6:
- rate_index = 18;
- break;
- case MGN_MCS7:
- rate_index = 19;
- break;
- case MGN_MCS8:
- rate_index = 20;
- break;
- case MGN_MCS9:
- rate_index = 21;
- break;
- case MGN_MCS10:
- rate_index = 22;
- break;
- case MGN_MCS11:
- rate_index = 23;
- break;
- case MGN_MCS12:
- rate_index = 24;
- break;
- case MGN_MCS13:
- rate_index = 25;
- break;
- case MGN_MCS14:
- rate_index = 26;
- break;
- case MGN_MCS15:
- rate_index = 27;
- break;
- default:
- rate_index = 28;
- break;
- }
- priv->stats.received_rate_histogram[0][rate_index]++;
- priv->stats.received_rate_histogram[rcvType][rate_index]++;
-}
-
-bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
- struct rx_desc *pdesc, struct sk_buff *skb)
-{
- struct rx_fwinfo *pDrvInfo = NULL;
-
- stats->bICV = pdesc->ICV;
- stats->bCRC = pdesc->CRC32;
- stats->hw_error = pdesc->CRC32 | pdesc->ICV;
-
- stats->Length = pdesc->Length;
- if (stats->Length < 24)
- stats->hw_error |= 1;
-
- if (stats->hw_error)
- return false;
-
- stats->rx_drv_info_size = pdesc->rx_drv_info_size;
- stats->rx_buf_shift = (pdesc->Shift) & 0x03;
- stats->decrypted = !pdesc->SWDec;
-
- pDrvInfo = (struct rx_fwinfo *)(skb->data + stats->rx_buf_shift);
-
- stats->rate = _rtl92e_rate_hw_to_mgn((bool)pDrvInfo->RxHT,
- pDrvInfo->RxRate);
-
- _rtl92e_update_received_rate_histogram_stats(dev, stats);
-
- stats->bIsAMPDU = (pDrvInfo->PartAggr == 1);
- stats->bFirstMPDU = (pDrvInfo->PartAggr == 1) &&
- (pDrvInfo->FirstAGGR == 1);
-
- stats->time_stamp_low = pDrvInfo->TSFL;
- stats->time_stamp_high = rtl92e_readl(dev, TSFR + 4);
-
- _rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo);
- skb_trim(skb, skb->len - S_CRC_LEN);
-
- return true;
-}
-
-void rtl92e_stop_adapter(struct net_device *dev, bool reset)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int i;
- u8 op_mode;
- u8 u1bTmp;
- u32 ulRegRead;
-
- op_mode = RT_OP_MODE_NO_LINK;
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_MEDIA_STATUS, &op_mode);
-
- if (!priv->rtllib->bSupportRemoteWakeUp) {
- u1bTmp = 0x0;
- rtl92e_writeb(dev, CMDR, u1bTmp);
- }
-
- mdelay(20);
-
- if (!reset) {
- mdelay(150);
-
- priv->hw_rf_off_action = 2;
-
- if (!priv->rtllib->bSupportRemoteWakeUp) {
- rtl92e_set_rf_off(dev);
- ulRegRead = rtl92e_readl(dev, CPU_GEN);
- ulRegRead |= CPU_GEN_SYSTEM_RESET;
- rtl92e_writel(dev, CPU_GEN, ulRegRead);
- } else {
- rtl92e_writel(dev, WFCRC0, 0xffffffff);
- rtl92e_writel(dev, WFCRC1, 0xffffffff);
- rtl92e_writel(dev, WFCRC2, 0xffffffff);
-
- rtl92e_writeb(dev, PMR, 0x5);
- rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa);
- }
- }
-
- for (i = 0; i < MAX_QUEUE_SIZE; i++)
- skb_queue_purge(&priv->rtllib->skb_waitq[i]);
-
- skb_queue_purge(&priv->skb_queue);
-}
-
-void rtl92e_update_ratr_table(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- u8 *pMcsRate = ieee->dot11ht_oper_rate_set;
- u32 ratr_value = 0;
- u16 rate_config = 0;
- u8 rate_index = 0;
-
- rtl92e_config_rate(dev, &rate_config);
- ratr_value = rate_config | *pMcsRate << 12;
- switch (ieee->mode) {
- case WIRELESS_MODE_B:
- ratr_value &= 0x0000000F;
- break;
- case WIRELESS_MODE_G:
- case WIRELESS_MODE_G | WIRELESS_MODE_B:
- ratr_value &= 0x00000FF7;
- break;
- case WIRELESS_MODE_N_24G:
- ratr_value &= 0x000FF007;
- break;
- default:
- break;
- }
- ratr_value &= 0x0FFFFFFF;
- if (ieee->ht_info->cur_tx_bw40mhz &&
- ieee->ht_info->cur_short_gi_40mhz)
- ratr_value |= 0x80000000;
- else if (!ieee->ht_info->cur_tx_bw40mhz &&
- ieee->ht_info->cur_short_gi_20mhz)
- ratr_value |= 0x80000000;
- rtl92e_writel(dev, RATR0 + rate_index * 4, ratr_value);
- rtl92e_writeb(dev, UFWP, 1);
-}
-
-void
-rtl92e_init_variables(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- strscpy(priv->nick, "rtl8192E", sizeof(priv->nick));
-
- priv->rtllib->softmac_features = IEEE_SOFTMAC_SCAN |
- IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
- IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;
-
- priv->rtllib->tx_headroom = sizeof(struct tx_fwinfo_8190pci);
-
- priv->short_retry_limit = 0x30;
- priv->long_retry_limit = 0x30;
-
- priv->receive_config = RCR_ADD3 |
- RCR_AMF | RCR_ADF |
- RCR_AICV |
- RCR_AB | RCR_AM | RCR_APM |
- RCR_AAP | ((u32)7 << RCR_MXDMA_OFFSET) |
- ((u32)7 << RCR_FIFO_OFFSET) | RCR_ONLYERLPKT;
-
- priv->irq_mask[0] = (u32)(IMR_ROK | IMR_VODOK | IMR_VIDOK |
- IMR_BEDOK | IMR_BKDOK | IMR_HCCADOK |
- IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK |
- IMR_BDOK | IMR_RXCMDOK | IMR_TIMEOUT0 |
- IMR_RDU | IMR_RXFOVW | IMR_TXFOVW |
- IMR_TBDOK | IMR_TBDER);
-
- priv->bfirst_after_down = false;
-}
-
-void rtl92e_irq_enable(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- priv->irq_enabled = 1;
-
- rtl92e_writel(dev, INTA_MASK, priv->irq_mask[0]);
-}
-
-void rtl92e_irq_disable(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- rtl92e_writel(dev, INTA_MASK, 0);
-
- priv->irq_enabled = 0;
-}
-
-void rtl92e_enable_rx(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- rtl92e_writel(dev, RDQDA, priv->rx_ring_dma);
-}
-
-static const u32 TX_DESC_BASE[] = {
- BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA
-};
-
-void rtl92e_enable_tx(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- u32 i;
-
- for (i = 0; i < MAX_TX_QUEUE_COUNT; i++)
- rtl92e_writel(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma);
-}
-
-void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta)
-{
- *p_inta = rtl92e_readl(dev, ISR);
- rtl92e_writel(dev, ISR, *p_inta);
-}
-
-bool rtl92e_is_rx_stuck(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u16 RegRxCounter = rtl92e_readw(dev, 0x130);
- bool bStuck = false;
- static u8 rx_chk_cnt;
- u32 slot_index = 0, TotalRxStuckCount = 0;
- u8 i;
- u8 SilentResetRxSoltNum = 4;
-
- rx_chk_cnt++;
- if (priv->undecorated_smoothed_pwdb >= (RATE_ADAPTIVE_TH_HIGH + 5)) {
- rx_chk_cnt = 0;
- } else if ((priv->undecorated_smoothed_pwdb < (RATE_ADAPTIVE_TH_HIGH + 5)) &&
- (((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_40M))
- || ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_20M)))) {
- if (rx_chk_cnt < 2)
- return bStuck;
- rx_chk_cnt = 0;
- } else if ((((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_40M)) ||
- ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_20M))) &&
- priv->undecorated_smoothed_pwdb >= VERY_LOW_RSSI) {
- if (rx_chk_cnt < 4)
- return bStuck;
- rx_chk_cnt = 0;
- } else {
- if (rx_chk_cnt < 8)
- return bStuck;
- rx_chk_cnt = 0;
- }
-
- slot_index = (priv->silent_reset_rx_slot_index++) % SilentResetRxSoltNum;
-
- if (priv->rx_ctr == RegRxCounter) {
- priv->silent_reset_rx_stuck_event[slot_index] = 1;
-
- for (i = 0; i < SilentResetRxSoltNum; i++)
- TotalRxStuckCount += priv->silent_reset_rx_stuck_event[i];
-
- if (TotalRxStuckCount == SilentResetRxSoltNum) {
- bStuck = true;
- for (i = 0; i < SilentResetRxSoltNum; i++)
- TotalRxStuckCount +=
- priv->silent_reset_rx_stuck_event[i];
- }
- } else {
- priv->silent_reset_rx_stuck_event[slot_index] = 0;
- }
-
- priv->rx_ctr = RegRxCounter;
-
- return bStuck;
-}
-
-bool rtl92e_is_tx_stuck(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- bool bStuck = false;
- u16 RegTxCounter = rtl92e_readw(dev, 0x128);
-
- if (priv->tx_counter == RegTxCounter)
- bStuck = true;
-
- priv->tx_counter = RegTxCounter;
-
- return bStuck;
-}
-
-bool rtl92e_get_nmode_support_by_sec(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- if (ieee->rtllib_ap_sec_type &&
- (ieee->rtllib_ap_sec_type(priv->rtllib) & (SEC_ALG_WEP |
- SEC_ALG_TKIP))) {
- return false;
- } else {
- return true;
- }
-}
-
-bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- return ieee->half_wireless_n24g_mode;
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
deleted file mode 100644
index 9d9c5051c7fe..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL8192E_H
-#define _RTL8192E_H
-
-#include "r8190P_def.h"
-
-bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev);
-bool rtl92e_get_nmode_support_by_sec(struct net_device *dev);
-bool rtl92e_is_tx_stuck(struct net_device *dev);
-bool rtl92e_is_rx_stuck(struct net_device *dev);
-void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta);
-void rtl92e_enable_rx(struct net_device *dev);
-void rtl92e_enable_tx(struct net_device *dev);
-void rtl92e_init_variables(struct net_device *dev);
-void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val);
-void rtl92e_get_eeprom_size(struct net_device *dev);
-bool rtl92e_start_adapter(struct net_device *dev);
-void rtl92e_link_change(struct net_device *dev);
-void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da,
- bool write_into_reg);
-void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc,
- struct cb_desc *cb_desc, struct sk_buff *skb);
-void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry,
- struct cb_desc *cb_desc, struct sk_buff *skb);
-bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
- struct rx_desc *pdesc, struct sk_buff *skb);
-void rtl92e_stop_adapter(struct net_device *dev, bool reset);
-void rtl92e_update_ratr_table(struct net_device *dev);
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
deleted file mode 100644
index ddf998cf2041..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ /dev/null
@@ -1,189 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_hw.h"
-#include "table.h"
-#include "r8192E_firmware.h"
-#include "r8192E_cmdpkt.h"
-#include <linux/firmware.h>
-
-static bool _rtl92e_wait_for_fw(struct net_device *dev, u32 mask, u32 timeout)
-{
- unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
-
- while (time_before(jiffies, deadline)) {
- if (rtl92e_readl(dev, CPU_GEN) & mask)
- return true;
- mdelay(2);
- }
- return false;
-}
-
-static bool _rtl92e_fw_boot_cpu(struct net_device *dev)
-{
- u32 CPU_status = 0;
-
- if (!_rtl92e_wait_for_fw(dev, CPU_GEN_PUT_CODE_OK, 200)) {
- netdev_err(dev, "Firmware download failed.\n");
- return false;
- }
- netdev_dbg(dev, "Download Firmware: Put code ok!\n");
-
- CPU_status = rtl92e_readl(dev, CPU_GEN);
- rtl92e_writeb(dev, CPU_GEN, (CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff);
- mdelay(1);
-
- if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, 200)) {
- netdev_err(dev, "Firmware boot failed.\n");
- return false;
- }
-
- netdev_dbg(dev, "Download Firmware: Boot ready!\n");
-
- return true;
-}
-
-static bool _rtl92e_fw_check_ready(struct net_device *dev,
- u8 load_fw_status)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_firmware *pfirmware = priv->fw_info;
- bool rt_status = true;
-
- switch (load_fw_status) {
- case FW_INIT_STEP0_BOOT:
- pfirmware->status = FW_STATUS_1_MOVE_BOOT_CODE;
- break;
-
- case FW_INIT_STEP1_MAIN:
- pfirmware->status = FW_STATUS_2_MOVE_MAIN_CODE;
-
- rt_status = _rtl92e_fw_boot_cpu(dev);
- if (rt_status)
- pfirmware->status = FW_STATUS_3_TURNON_CPU;
- else
- netdev_dbg(dev, "_rtl92e_fw_boot_cpu fail!\n");
-
- break;
-
- case FW_INIT_STEP2_DATA:
- pfirmware->status = FW_STATUS_4_MOVE_DATA_CODE;
- mdelay(1);
-
- rt_status = _rtl92e_wait_for_fw(dev, CPU_GEN_FIRM_RDY, 20);
- if (rt_status)
- pfirmware->status = FW_STATUS_5_READY;
- break;
- default:
- rt_status = false;
- netdev_dbg(dev, "Unknown firmware status");
- break;
- }
-
- return rt_status;
-}
-
-static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob,
- const char *name, u8 padding)
-{
- const struct firmware *fw;
- int rc, i;
- bool ret = true;
-
- rc = request_firmware(&fw, name, &dev->dev);
- if (rc < 0)
- return false;
-
- if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) {
- netdev_err(dev, "Firmware image %s too big for the device.\n",
- name);
- ret = false;
- goto out;
- }
-
- if (padding)
- memset(blob->data, 0, padding);
- if (fw->size % 4)
- memset(blob->data + padding + fw->size, 0, 4);
- memcpy(blob->data + padding, fw->data, fw->size);
-
- blob->size = round_up(fw->size, 4) + padding;
-
- /* Swap endian - firmware is packaged in invalid endiannes*/
- for (i = padding; i < blob->size; i += 4) {
- u32 *data = (u32 *)(blob->data + i);
- *data = swab32p(data);
- }
-out:
- release_firmware(fw);
- return ret;
-}
-
-bool rtl92e_init_fw(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- bool rt_status = true;
-
- u32 file_length = 0;
- u8 *mapped_file = NULL;
- u8 i = 0;
- enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
- enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
-
- struct rt_firmware *pfirmware = priv->fw_info;
-
- netdev_dbg(dev, " PlatformInitFirmware()==>\n");
-
- if (pfirmware->status == FW_STATUS_0_INIT) {
- rst_opt = OPT_SYSTEM_RESET;
- starting_state = FW_INIT_STEP0_BOOT;
-
- } else if (pfirmware->status == FW_STATUS_5_READY) {
- rst_opt = OPT_FIRMWARE_RESET;
- starting_state = FW_INIT_STEP2_DATA;
- }
-
- for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) {
- if (rst_opt == OPT_SYSTEM_RESET) {
- if (pfirmware->blobs[i].size == 0) {
- const char *fw_name[3] = {
- RTL8192E_BOOT_IMG_FW,
- RTL8192E_MAIN_IMG_FW,
- RTL8192E_DATA_IMG_FW
- };
- int pad = 0;
-
- if (i == FW_INIT_STEP1_MAIN)
- pad = 128;
-
- if (!_rtl92e_fw_prepare(dev,
- &pfirmware->blobs[i],
- fw_name[i],
- pad))
- goto download_firmware_fail;
- }
- }
-
- mapped_file = pfirmware->blobs[i].data;
- file_length = pfirmware->blobs[i].size;
-
- rt_status = rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_INIT,
- mapped_file, file_length);
- if (!rt_status)
- goto download_firmware_fail;
-
- if (!_rtl92e_fw_check_ready(dev, i))
- goto download_firmware_fail;
- }
-
- netdev_dbg(dev, "Firmware Download Success\n");
- return rt_status;
-
-download_firmware_fail:
- netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__);
- return false;
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
deleted file mode 100644
index b9059abc901b..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef __INC_FIRMWARE_H
-#define __INC_FIRMWARE_H
-
-#define RTL8192E_BOOT_IMG_FW "RTL8192E/boot.img"
-#define RTL8192E_MAIN_IMG_FW "RTL8192E/main.img"
-#define RTL8192E_DATA_IMG_FW "RTL8192E/data.img"
-
-enum firmware_init_step {
- FW_INIT_STEP0_BOOT = 0,
- FW_INIT_STEP1_MAIN = 1,
- FW_INIT_STEP2_DATA = 2,
-};
-
-enum opt_rst_type {
- OPT_SYSTEM_RESET = 0,
- OPT_FIRMWARE_RESET = 1,
-};
-
-enum desc_packet_type {
- DESC_PACKET_TYPE_INIT = 0,
- DESC_PACKET_TYPE_NORMAL = 1,
-};
-
-enum firmware_status {
- FW_STATUS_0_INIT = 0,
- FW_STATUS_1_MOVE_BOOT_CODE = 1,
- FW_STATUS_2_MOVE_MAIN_CODE = 2,
- FW_STATUS_3_TURNON_CPU = 3,
- FW_STATUS_4_MOVE_DATA_CODE = 4,
- FW_STATUS_5_READY = 5,
-};
-
-#define MAX_FW_SIZE 64000
-struct rt_fw_blob {
- u16 size;
- u8 data[MAX_FW_SIZE];
-};
-
-#define FW_BLOBS 3
-struct rt_firmware {
- enum firmware_status status;
- struct rt_fw_blob blobs[FW_BLOBS];
-};
-
-bool rtl92e_init_fw(struct net_device *dev);
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h
deleted file mode 100644
index e507593b939c..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef R8180_HW
-#define R8180_HW
-
-enum baseband_config {
- BB_CONFIG_PHY_REG = 0,
- BB_CONFIG_AGC_TAB = 1,
-};
-
-#define RTL8190_EEPROM_ID 0x8129
-#define EEPROM_VID 0x02
-#define EEPROM_DID 0x04
-#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C
-
-#define EEPROM_Default_ThermalMeter 0x77
-#define EEPROM_Default_AntTxPowerDiff 0x0
-#define EEPROM_Default_TxPwDiff_CrystalCap 0x5
-#define EEPROM_Default_TxPower 0x1010
-#define EEPROM_ICVersion_ChannelPlan 0x7C
-#define EEPROM_Customer_ID 0x7B
-#define EEPROM_RFInd_PowerDiff 0x28
-
-#define EEPROM_ThermalMeter 0x29
-#define EEPROM_TxPwDiff_CrystalCap 0x2A
-#define EEPROM_TxPwIndex_CCK 0x2C
-#define EEPROM_TxPwIndex_OFDM_24G 0x3A
-
-#define EEPROM_CID_TOSHIBA 0x4
-#define EEPROM_CID_NetCore 0x5
-enum _RTL8192PCI_HW {
- MAC0 = 0x000,
- MAC4 = 0x004,
- PCIF = 0x009,
-#define MXDMA2_NO_LIMIT 0x7
-
-#define MXDMA2_RX_SHIFT 4
-#define MXDMA2_TX_SHIFT 0
- PMR = 0x00c,
- EPROM_CMD = 0x00e,
-
-#define EPROM_CMD_9356SEL BIT(4)
-#define EPROM_CMD_OPERATING_MODE_SHIFT 6
-#define EPROM_CMD_NORMAL 0
-#define EPROM_CMD_PROGRAM 2
-#define EPROM_CS_BIT 3
-#define EPROM_CK_BIT 2
-#define EPROM_W_BIT 1
-#define EPROM_R_BIT 0
-
- ANAPAR = 0x17,
-#define BB_GLOBAL_RESET_BIT 0x1
- BB_GLOBAL_RESET = 0x020,
- BSSIDR = 0x02E,
- CMDR = 0x037,
-#define CR_RE 0x08
-#define CR_TE 0x04
- SIFS = 0x03E,
- RCR = 0x044,
-#define RCR_ONLYERLPKT BIT(31)
-#define RCR_CBSSID BIT(23)
-#define RCR_ADD3 BIT(21)
-#define RCR_AMF BIT(20)
-#define RCR_ADF BIT(18)
-#define RCR_AICV BIT(12)
-#define RCR_AB BIT(3)
-#define RCR_AM BIT(2)
-#define RCR_APM BIT(1)
-#define RCR_AAP BIT(0)
-#define RCR_MXDMA_OFFSET 8
-#define RCR_FIFO_OFFSET 13
- SLOT_TIME = 0x049,
- ACK_TIMEOUT = 0x04c,
- EDCAPARA_BE = 0x050,
- EDCAPARA_BK = 0x054,
- EDCAPARA_VO = 0x058,
- EDCAPARA_VI = 0x05C,
-#define AC_PARAM_TXOP_LIMIT_OFFSET 16
-#define AC_PARAM_ECW_MAX_OFFSET 12
-#define AC_PARAM_ECW_MIN_OFFSET 8
-#define AC_PARAM_AIFS_OFFSET 0
- BCN_TCFG = 0x062,
-#define BCN_TCFG_CW_SHIFT 8
-#define BCN_TCFG_IFS 0
- BCN_INTERVAL = 0x070,
- ATIMWND = 0x072,
- BCN_DRV_EARLY_INT = 0x074,
- BCN_DMATIME = 0x076,
- BCN_ERR_THRESH = 0x078,
- RWCAM = 0x0A0,
-#define TOTAL_CAM_ENTRY 32
- WCAMI = 0x0A4,
- SECR = 0x0B0,
-#define SCR_TxUseDK BIT(0)
-#define SCR_RxUseDK BIT(1)
-#define SCR_TxEncEnable BIT(2)
-#define SCR_RxDecEnable BIT(3)
-#define SCR_NoSKMC BIT(5)
- SWREGULATOR = 0x0BD,
- INTA_MASK = 0x0f4,
-#define IMR_TBDOK BIT(27)
-#define IMR_TBDER BIT(26)
-#define IMR_TXFOVW BIT(15)
-#define IMR_TIMEOUT0 BIT(14)
-#define IMR_BcnInt BIT(13)
-#define IMR_RXFOVW BIT(12)
-#define IMR_RDU BIT(11)
-#define IMR_RXCMDOK BIT(10)
-#define IMR_BDOK BIT(9)
-#define IMR_HIGHDOK BIT(8)
-#define IMR_COMDOK BIT(7)
-#define IMR_MGNTDOK BIT(6)
-#define IMR_HCCADOK BIT(5)
-#define IMR_BKDOK BIT(4)
-#define IMR_BEDOK BIT(3)
-#define IMR_VIDOK BIT(2)
-#define IMR_VODOK BIT(1)
-#define IMR_ROK BIT(0)
- ISR = 0x0f8,
- TP_POLL = 0x0fd,
-#define TP_POLL_CQ BIT(5)
- PSR = 0x0ff,
- CPU_GEN = 0x100,
-#define CPU_CCK_LOOPBACK 0x00030000
-#define CPU_GEN_SYSTEM_RESET 0x00000001
-#define CPU_GEN_FIRMWARE_RESET 0x00000008
-#define CPU_GEN_BOOT_RDY 0x00000010
-#define CPU_GEN_FIRM_RDY 0x00000020
-#define CPU_GEN_PUT_CODE_OK 0x00000080
-#define CPU_GEN_BB_RST 0x00000100
-#define CPU_GEN_PWR_STB_CPU 0x00000004
-#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF
-#define CPU_GEN_NO_LOOPBACK_SET 0x00080000
- ACM_HW_CTRL = 0x171,
-#define ACM_HW_BEQ_EN BIT(1)
-#define ACM_HW_VIQ_EN BIT(2)
-#define ACM_HW_VOQ_EN BIT(3)
- RQPN1 = 0x180,
- RQPN2 = 0x184,
- RQPN3 = 0x188,
- QPNR = 0x1F0,
- BQDA = 0x200,
- HQDA = 0x204,
- CQDA = 0x208,
- MQDA = 0x20C,
- HCCAQDA = 0x210,
- VOQDA = 0x214,
- VIQDA = 0x218,
- BEQDA = 0x21C,
- BKQDA = 0x220,
- RDQDA = 0x228,
-
- WFCRC0 = 0x2f0,
- WFCRC1 = 0x2f4,
- WFCRC2 = 0x2f8,
-
- BW_OPMODE = 0x300,
-#define BW_OPMODE_20MHZ BIT(2)
- IC_VERRSION = 0x301,
- MSR = 0x303,
-#define MSR_LINK_MASK (BIT(1) | BIT(0))
-#define MSR_LINK_MANAGED 2
-#define MSR_LINK_ADHOC 1
-#define MSR_LINK_MASTER 3
-
-#define MSR_NOLINK 0x00
-#define MSR_ADHOC 0x01
-#define MSR_INFRA 0x02
-#define MSR_AP 0x03
-
- RETRY_LIMIT = 0x304,
-#define RETRY_LIMIT_SHORT_SHIFT 8
-#define RETRY_LIMIT_LONG_SHIFT 0
- TSFR = 0x308,
- RRSR = 0x310,
-#define RRSR_SHORT_OFFSET 23
-#define RRSR_1M BIT(0)
-#define RRSR_2M BIT(1)
-#define RRSR_5_5M BIT(2)
-#define RRSR_11M BIT(3)
-#define RRSR_6M BIT(4)
-#define RRSR_9M BIT(5)
-#define RRSR_12M BIT(6)
-#define RRSR_18M BIT(7)
-#define RRSR_24M BIT(8)
-#define RRSR_36M BIT(9)
-#define RRSR_48M BIT(10)
-#define RRSR_54M BIT(11)
-#define BRSR_AckShortPmb BIT(23)
- UFWP = 0x318,
- RATR0 = 0x320,
-#define RATR_1M 0x00000001
-#define RATR_2M 0x00000002
-#define RATR_55M 0x00000004
-#define RATR_11M 0x00000008
-#define RATR_6M 0x00000010
-#define RATR_9M 0x00000020
-#define RATR_12M 0x00000040
-#define RATR_18M 0x00000080
-#define RATR_24M 0x00000100
-#define RATR_36M 0x00000200
-#define RATR_48M 0x00000400
-#define RATR_54M 0x00000800
-#define RATR_MCS0 0x00001000
-#define RATR_MCS1 0x00002000
-#define RATR_MCS2 0x00004000
-#define RATR_MCS3 0x00008000
-#define RATR_MCS4 0x00010000
-#define RATR_MCS5 0x00020000
-#define RATR_MCS6 0x00040000
-#define RATR_MCS7 0x00080000
-#define RATR_MCS8 0x00100000
-#define RATR_MCS9 0x00200000
-#define RATR_MCS10 0x00400000
-#define RATR_MCS11 0x00800000
-#define RATR_MCS12 0x01000000
-#define RATR_MCS13 0x02000000
-#define RATR_MCS14 0x04000000
-#define RATR_MCS15 0x08000000
-#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
-#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
- RATR_24M | RATR_36M | RATR_48M | RATR_54M)
-#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
- RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \
- RATR_MCS6 | RATR_MCS7)
-#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
- RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
- RATR_MCS14 | RATR_MCS15)
-
- DRIVER_RSSI = 0x32c,
- MCS_TXAGC = 0x340,
- CCK_TXAGC = 0x348,
- MAC_BLK_CTRL = 0x403,
-};
-
-#define GPI 0x108
-
-#define ANAPAR_FOR_8192PCIE 0x17
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
deleted file mode 100644
index fbe624e235df..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ /dev/null
@@ -1,1110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include <linux/bitops.h>
-#include "rtl_core.h"
-#include "r8192E_hw.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h"
-#include "r8192E_phy.h"
-#include "rtl_dm.h"
-
-#include "table.h"
-
-/*************************Define local function prototype**********************/
-
-static u32 _rtl92e_phy_rf_fw_read(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset);
-static void _rtl92e_phy_rf_fw_write(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset,
- u32 Data);
-
-static u32 _rtl92e_calculate_bit_shift(u32 dwBitMask)
-{
- if (!dwBitMask)
- return 32;
- return ffs(dwBitMask) - 1;
-}
-
-void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask,
- u32 dwData)
-{
- u32 OriginalValue, BitShift, NewValue;
-
- if (dwBitMask != bMaskDWord) {
- OriginalValue = rtl92e_readl(dev, dwRegAddr);
- BitShift = _rtl92e_calculate_bit_shift(dwBitMask);
- NewValue = (OriginalValue & ~dwBitMask) | (dwData << BitShift);
- rtl92e_writel(dev, dwRegAddr, NewValue);
- } else {
- rtl92e_writel(dev, dwRegAddr, dwData);
- }
-}
-
-u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask)
-{
- u32 OriginalValue, BitShift;
-
- OriginalValue = rtl92e_readl(dev, dwRegAddr);
- BitShift = _rtl92e_calculate_bit_shift(dwBitMask);
-
- return (OriginalValue & dwBitMask) >> BitShift;
-}
-
-static u32 _rtl92e_phy_rf_read(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 ret = 0;
- u32 NewOffset = 0;
- struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath];
-
- Offset &= 0x3f;
-
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);
- if (Offset >= 31) {
- priv->rf_reg_0value[eRFPath] |= 0x140;
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
- bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
- NewOffset = Offset - 30;
- } else if (Offset >= 16) {
- priv->rf_reg_0value[eRFPath] |= 0x100;
- priv->rf_reg_0value[eRFPath] &= (~0x40);
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
- bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
- NewOffset = Offset - 15;
- } else {
- NewOffset = Offset;
- }
- rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress,
- NewOffset);
- rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0);
- rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1);
-
- mdelay(1);
-
- ret = rtl92e_get_bb_reg(dev, pPhyReg->rfLSSIReadBack,
- bLSSIReadBackData);
-
- priv->rf_reg_0value[eRFPath] &= 0xebf;
-
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
-
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);
-
- return ret;
-}
-
-static void _rtl92e_phy_rf_write(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset,
- u32 Data)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 DataAndAddr = 0, NewOffset = 0;
- struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath];
-
- Offset &= 0x3f;
-
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);
-
- if (Offset >= 31) {
- priv->rf_reg_0value[eRFPath] |= 0x140;
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
- bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
- NewOffset = Offset - 30;
- } else if (Offset >= 16) {
- priv->rf_reg_0value[eRFPath] |= 0x100;
- priv->rf_reg_0value[eRFPath] &= (~0x40);
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
- bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
- NewOffset = Offset - 15;
- } else {
- NewOffset = Offset;
- }
-
- DataAndAddr = (NewOffset & 0x3f) | (Data << 16);
-
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
-
- if (Offset == 0x0)
- priv->rf_reg_0value[eRFPath] = Data;
-
- if (Offset != 0) {
- priv->rf_reg_0value[eRFPath] &= 0xebf;
- rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
- bMaskDWord,
- (priv->rf_reg_0value[eRFPath] << 16));
- }
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);
-}
-
-void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
- u32 RegAddr, u32 BitMask, u32 Data)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 Original_Value, BitShift, New_Value;
-
- if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter)
- return;
-
- if (priv->rf_mode == RF_OP_By_FW) {
- if (BitMask != bMask12Bits) {
- Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath,
- RegAddr);
- BitShift = _rtl92e_calculate_bit_shift(BitMask);
- New_Value = (Original_Value & ~BitMask) | (Data << BitShift);
-
- _rtl92e_phy_rf_fw_write(dev, eRFPath, RegAddr,
- New_Value);
- } else {
- _rtl92e_phy_rf_fw_write(dev, eRFPath, RegAddr, Data);
- }
- udelay(200);
- } else {
- if (BitMask != bMask12Bits) {
- Original_Value = _rtl92e_phy_rf_read(dev, eRFPath,
- RegAddr);
- BitShift = _rtl92e_calculate_bit_shift(BitMask);
- New_Value = (Original_Value & ~BitMask) | (Data << BitShift);
-
- _rtl92e_phy_rf_write(dev, eRFPath, RegAddr, New_Value);
- } else {
- _rtl92e_phy_rf_write(dev, eRFPath, RegAddr, Data);
- }
- }
-}
-
-u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
- u32 RegAddr, u32 BitMask)
-{
- u32 Original_Value, Readback_Value, BitShift;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter)
- return 0;
- mutex_lock(&priv->rf_mutex);
- if (priv->rf_mode == RF_OP_By_FW) {
- Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath, RegAddr);
- udelay(200);
- } else {
- Original_Value = _rtl92e_phy_rf_read(dev, eRFPath, RegAddr);
- }
- BitShift = _rtl92e_calculate_bit_shift(BitMask);
- Readback_Value = (Original_Value & BitMask) >> BitShift;
- mutex_unlock(&priv->rf_mutex);
- return Readback_Value;
-}
-
-static u32 _rtl92e_phy_rf_fw_read(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset)
-{
- u32 Data = 0;
- u8 time = 0;
-
- Data |= ((Offset & 0xFF) << 12);
- Data |= ((eRFPath & 0x3) << 20);
- Data |= 0x80000000;
- while (rtl92e_readl(dev, QPNR) & 0x80000000) {
- if (time++ < 100)
- udelay(10);
- else
- break;
- }
- rtl92e_writel(dev, QPNR, Data);
- while (rtl92e_readl(dev, QPNR) & 0x80000000) {
- if (time++ < 100)
- udelay(10);
- else
- return 0;
- }
- return rtl92e_readl(dev, RF_DATA);
-}
-
-static void _rtl92e_phy_rf_fw_write(struct net_device *dev,
- enum rf90_radio_path eRFPath, u32 Offset,
- u32 Data)
-{
- u8 time = 0;
-
- Data |= ((Offset & 0xFF) << 12);
- Data |= ((eRFPath & 0x3) << 20);
- Data |= 0x400000;
- Data |= 0x80000000;
-
- while (rtl92e_readl(dev, QPNR) & 0x80000000) {
- if (time++ < 100)
- udelay(10);
- else
- break;
- }
- rtl92e_writel(dev, QPNR, Data);
-}
-
-void rtl92e_config_mac(struct net_device *dev)
-{
- u32 dwArrayLen = 0, i = 0;
- u32 *pdwArray = NULL;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->tx_pwr_data_read_from_eeprom) {
- dwArrayLen = RTL8192E_MACPHY_ARR_PG_LEN;
- pdwArray = RTL8192E_MACPHY_ARR_PG;
-
- } else {
- dwArrayLen = RTL8192E_MACPHY_ARR_LEN;
- pdwArray = RTL8192E_MACPHY_ARR;
- }
- for (i = 0; i < dwArrayLen; i += 3) {
- if (pdwArray[i] == 0x318)
- pdwArray[i + 2] = 0x00000800;
- rtl92e_set_bb_reg(dev, pdwArray[i], pdwArray[i + 1],
- pdwArray[i + 2]);
- }
-}
-
-static void _rtl92e_phy_config_bb(struct net_device *dev, u8 ConfigType)
-{
- int i;
- u32 *Rtl819XPHY_REGArray_Table = NULL;
- u32 *Rtl819XAGCTAB_Array_Table = NULL;
- u16 AGCTAB_ArrayLen, PHY_REGArrayLen = 0;
-
- AGCTAB_ArrayLen = RTL8192E_AGCTAB_ARR_LEN;
- Rtl819XAGCTAB_Array_Table = RTL8192E_AGCTAB_ARR;
- PHY_REGArrayLen = RTL8192E_PHY_REG_1T2R_ARR_LEN;
- Rtl819XPHY_REGArray_Table = RTL8192E_PHY_REG_1T2R_ARR;
-
- if (ConfigType == BB_CONFIG_PHY_REG) {
- for (i = 0; i < PHY_REGArrayLen; i += 2) {
- rtl92e_set_bb_reg(dev, Rtl819XPHY_REGArray_Table[i],
- bMaskDWord,
- Rtl819XPHY_REGArray_Table[i + 1]);
- }
- } else if (ConfigType == BB_CONFIG_AGC_TAB) {
- for (i = 0; i < AGCTAB_ArrayLen; i += 2) {
- rtl92e_set_bb_reg(dev, Rtl819XAGCTAB_Array_Table[i],
- bMaskDWord,
- Rtl819XAGCTAB_Array_Table[i + 1]);
- }
- }
-}
-
-static void _rtl92e_init_bb_rf_reg_def(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->phy_reg_def[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW;
- priv->phy_reg_def[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW;
-
- priv->phy_reg_def[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE;
- priv->phy_reg_def[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE;
-
- priv->phy_reg_def[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE;
- priv->phy_reg_def[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE;
-
- priv->phy_reg_def[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter;
- priv->phy_reg_def[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
-
- priv->phy_reg_def[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2;
- priv->phy_reg_def[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2;
-
- priv->phy_reg_def[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
- priv->phy_reg_def[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
-}
-
-bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock,
- enum rf90_radio_path eRFPath)
-{
- bool ret = true;
- u32 i, CheckTimes = 4, dwRegRead = 0;
- u32 WriteAddr[4];
- u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f};
-
- WriteAddr[HW90_BLOCK_MAC] = 0x100;
- WriteAddr[HW90_BLOCK_PHY0] = 0x900;
- WriteAddr[HW90_BLOCK_PHY1] = 0x800;
- WriteAddr[HW90_BLOCK_RF] = 0x3;
-
- if (CheckBlock == HW90_BLOCK_MAC) {
- netdev_warn(dev, "%s(): No checks available for MAC block.\n",
- __func__);
- return ret;
- }
-
- for (i = 0; i < CheckTimes; i++) {
- switch (CheckBlock) {
- case HW90_BLOCK_PHY0:
- case HW90_BLOCK_PHY1:
- rtl92e_writel(dev, WriteAddr[CheckBlock],
- WriteData[i]);
- dwRegRead = rtl92e_readl(dev, WriteAddr[CheckBlock]);
- break;
-
- case HW90_BLOCK_RF:
- WriteData[i] &= 0xfff;
- rtl92e_set_rf_reg(dev, eRFPath,
- WriteAddr[HW90_BLOCK_RF],
- bMask12Bits, WriteData[i]);
- mdelay(10);
- dwRegRead = rtl92e_get_rf_reg(dev, eRFPath,
- WriteAddr[HW90_BLOCK_RF],
- bMaskDWord);
- mdelay(10);
- break;
-
- default:
- ret = false;
- break;
- }
-
- if (dwRegRead != WriteData[i]) {
- netdev_warn(dev, "%s(): Check failed.\n", __func__);
- ret = false;
- break;
- }
- }
-
- return ret;
-}
-
-static bool _rtl92e_bb_config_para_file(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- bool rtStatus = true;
- u8 bRegValue = 0, eCheckItem = 0;
- u32 dwRegValue = 0;
-
- bRegValue = rtl92e_readb(dev, BB_GLOBAL_RESET);
- rtl92e_writeb(dev, BB_GLOBAL_RESET, (bRegValue | BB_GLOBAL_RESET_BIT));
-
- dwRegValue = rtl92e_readl(dev, CPU_GEN);
- rtl92e_writel(dev, CPU_GEN, (dwRegValue & (~CPU_GEN_BB_RST)));
-
- for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0;
- eCheckItem <= HW90_BLOCK_PHY1; eCheckItem++) {
- rtStatus = rtl92e_check_bb_and_rf(dev,
- (enum hw90_block)eCheckItem,
- (enum rf90_radio_path)0);
- if (!rtStatus)
- return rtStatus;
- }
- rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn | bOFDMEn, 0x0);
- _rtl92e_phy_config_bb(dev, BB_CONFIG_PHY_REG);
-
- dwRegValue = rtl92e_readl(dev, CPU_GEN);
- rtl92e_writel(dev, CPU_GEN, (dwRegValue | CPU_GEN_BB_RST));
-
- _rtl92e_phy_config_bb(dev, BB_CONFIG_AGC_TAB);
-
- if (priv->ic_cut > VERSION_8190_BD) {
- dwRegValue = 0x0;
- rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage,
- (bXBTxAGC | bXCTxAGC | bXDTxAGC), dwRegValue);
-
- dwRegValue = priv->crystal_cap;
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, bXtalCap92x,
- dwRegValue);
- }
-
- return rtStatus;
-}
-
-bool rtl92e_config_bb(struct net_device *dev)
-{
- _rtl92e_init_bb_rf_reg_def(dev);
- return _rtl92e_bb_config_para_file(dev);
-}
-
-void rtl92e_get_tx_power(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->mcs_tx_pwr_level_org_offset[0] =
- rtl92e_readl(dev, rTxAGC_Rate18_06);
- priv->mcs_tx_pwr_level_org_offset[1] =
- rtl92e_readl(dev, rTxAGC_Rate54_24);
- priv->mcs_tx_pwr_level_org_offset[2] =
- rtl92e_readl(dev, rTxAGC_Mcs03_Mcs00);
- priv->mcs_tx_pwr_level_org_offset[3] =
- rtl92e_readl(dev, rTxAGC_Mcs07_Mcs04);
- priv->mcs_tx_pwr_level_org_offset[4] =
- rtl92e_readl(dev, rTxAGC_Mcs11_Mcs08);
- priv->mcs_tx_pwr_level_org_offset[5] =
- rtl92e_readl(dev, rTxAGC_Mcs15_Mcs12);
-
- priv->def_initial_gain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1);
- priv->def_initial_gain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1);
- priv->def_initial_gain[2] = rtl92e_readb(dev, rOFDM0_XCAGCCore1);
- priv->def_initial_gain[3] = rtl92e_readb(dev, rOFDM0_XDAGCCore1);
-
- priv->framesync = rtl92e_readb(dev, rOFDM0_RxDetector3);
-}
-
-void rtl92e_set_tx_power(struct net_device *dev, u8 channel)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 powerlevel = 0, powerlevelOFDM24G = 0;
-
- if (priv->epromtype == EEPROM_93C46) {
- powerlevel = priv->tx_pwr_level_cck[channel - 1];
- powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1];
- }
-
- rtl92e_set_cck_tx_power(dev, powerlevel);
- rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G);
-}
-
-u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath)
-{
- int i;
-
- switch (eRFPath) {
- case RF90_PATH_A:
- for (i = 0; i < RTL8192E_RADIO_A_ARR_LEN; i += 2) {
- if (RTL8192E_RADIO_A_ARR[i] == 0xfe) {
- msleep(100);
- continue;
- }
- rtl92e_set_rf_reg(dev, eRFPath, RTL8192E_RADIO_A_ARR[i],
- bMask12Bits,
- RTL8192E_RADIO_A_ARR[i + 1]);
- }
- break;
- case RF90_PATH_B:
- for (i = 0; i < RTL8192E_RADIO_B_ARR_LEN; i += 2) {
- if (RTL8192E_RADIO_B_ARR[i] == 0xfe) {
- msleep(100);
- continue;
- }
- rtl92e_set_rf_reg(dev, eRFPath, RTL8192E_RADIO_B_ARR[i],
- bMask12Bits,
- RTL8192E_RADIO_B_ARR[i + 1]);
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static void _rtl92e_set_tx_power_level(struct net_device *dev, u8 channel)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 powerlevel = priv->tx_pwr_level_cck[channel - 1];
- u8 powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1];
-
- rtl92e_set_cck_tx_power(dev, powerlevel);
- rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G);
-}
-
-static u8 _rtl92e_phy_set_sw_chnl_cmd_array(struct net_device *dev,
- struct sw_chnl_cmd *CmdTable,
- u32 CmdTableIdx, u32 CmdTableSz,
- enum sw_chnl_cmd_id cmd_id,
- u32 para1, u32 para2, u32 ms_delay)
-{
- struct sw_chnl_cmd *pCmd;
-
- if (!CmdTable) {
- netdev_err(dev, "%s(): CmdTable cannot be NULL.\n", __func__);
- return false;
- }
- if (CmdTableIdx >= CmdTableSz) {
- netdev_err(dev, "%s(): Invalid index requested.\n", __func__);
- return false;
- }
-
- pCmd = CmdTable + CmdTableIdx;
- pCmd->cmd_id = cmd_id;
- pCmd->para1 = para1;
- pCmd->para2 = para2;
- pCmd->ms_delay = ms_delay;
-
- return true;
-}
-
-static u8 _rtl92e_phy_switch_channel_step(struct net_device *dev, u8 channel,
- u8 *stage, u8 *step, u32 *delay)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- u32 PreCommonCmdCnt;
- u32 PostCommonCmdCnt;
- u32 RfDependCmdCnt;
- struct sw_chnl_cmd *CurrentCmd = NULL;
- u8 eRFPath;
-
- if (!rtllib_legal_channel(priv->rtllib, channel)) {
- netdev_err(dev, "Invalid channel requested: %d\n", channel);
- return true;
- }
-
- {
- PreCommonCmdCnt = 0;
- _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PreCommonCmd,
- PreCommonCmdCnt++,
- MAX_PRECMD_CNT,
- cmd_id_set_tx_power_level,
- 0, 0, 0);
- _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PreCommonCmd,
- PreCommonCmdCnt++,
- MAX_PRECMD_CNT, cmd_id_end,
- 0, 0, 0);
-
- PostCommonCmdCnt = 0;
-
- _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PostCommonCmd,
- PostCommonCmdCnt++,
- MAX_POSTCMD_CNT, cmd_id_end,
- 0, 0, 0);
-
- RfDependCmdCnt = 0;
-
- if (!(channel >= 1 && channel <= 14)) {
- netdev_err(dev,
- "Invalid channel requested for 8256: %d\n",
- channel);
- return false;
- }
- _rtl92e_phy_set_sw_chnl_cmd_array(dev,
- ieee->RfDependCmd,
- RfDependCmdCnt++,
- MAX_RFDEPENDCMD_CNT,
- cmd_id_rf_write_reg,
- rZebra1_Channel,
- channel, 10);
- _rtl92e_phy_set_sw_chnl_cmd_array(dev,
- ieee->RfDependCmd,
- RfDependCmdCnt++,
- MAX_RFDEPENDCMD_CNT,
- cmd_id_end, 0, 0, 0);
-
- do {
- switch (*stage) {
- case 0:
- CurrentCmd = &ieee->PreCommonCmd[*step];
- break;
- case 1:
- CurrentCmd = &ieee->RfDependCmd[*step];
- break;
- case 2:
- CurrentCmd = &ieee->PostCommonCmd[*step];
- break;
- }
-
- if (CurrentCmd && CurrentCmd->cmd_id == cmd_id_end) {
- if ((*stage) == 2)
- return true;
- (*stage)++;
- (*step) = 0;
- continue;
- }
-
- if (!CurrentCmd)
- continue;
- switch (CurrentCmd->cmd_id) {
- case cmd_id_set_tx_power_level:
- if (priv->ic_cut > VERSION_8190_BD)
- _rtl92e_set_tx_power_level(dev,
- channel);
- break;
- case cmd_id_write_port_ulong:
- rtl92e_writel(dev, CurrentCmd->para1,
- CurrentCmd->para2);
- break;
- case cmd_id_write_port_ushort:
- rtl92e_writew(dev, CurrentCmd->para1,
- CurrentCmd->para2);
- break;
- case cmd_id_write_port_uchar:
- rtl92e_writeb(dev, CurrentCmd->para1,
- CurrentCmd->para2);
- break;
- case cmd_id_rf_write_reg:
- for (eRFPath = 0; eRFPath <
- priv->num_total_rf_path; eRFPath++)
- rtl92e_set_rf_reg(dev,
- (enum rf90_radio_path)eRFPath,
- CurrentCmd->para1, bMask12Bits,
- CurrentCmd->para2 << 7);
- break;
- default:
- break;
- }
-
- break;
- } while (true);
- } /*for (Number of RF paths)*/
-
- (*delay) = CurrentCmd->ms_delay;
- (*step)++;
- return false;
-}
-
-static void _rtl92e_phy_switch_channel(struct net_device *dev, u8 channel)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 delay = 0;
-
- while (!_rtl92e_phy_switch_channel_step(dev, channel,
- &priv->sw_chnl_stage,
- &priv->sw_chnl_step, &delay)) {
- if (delay > 0)
- msleep(delay);
- if (!priv->up)
- break;
- }
-}
-
-static void _rtl92e_phy_switch_channel_work_item(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- _rtl92e_phy_switch_channel(dev, priv->chan);
-}
-
-void rtl92e_set_channel(struct net_device *dev, u8 channel)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (!priv->up) {
- netdev_err(dev, "%s(): Driver is not initialized\n", __func__);
- return;
- }
- if (priv->sw_chnl_in_progress)
- return;
-
- switch (priv->rtllib->mode) {
- case WIRELESS_MODE_B:
- if (channel > 14) {
- netdev_warn(dev,
- "Channel %d not available in 802.11b.\n",
- channel);
- return;
- }
- break;
- case WIRELESS_MODE_G:
- case WIRELESS_MODE_N_24G:
- if (channel > 14) {
- netdev_warn(dev,
- "Channel %d not available in 802.11g.\n",
- channel);
- return;
- }
- break;
- }
-
- priv->sw_chnl_in_progress = true;
- if (channel == 0)
- channel = 1;
-
- priv->chan = channel;
-
- priv->sw_chnl_stage = 0;
- priv->sw_chnl_step = 0;
-
- if (priv->up)
- _rtl92e_phy_switch_channel_work_item(dev);
- priv->sw_chnl_in_progress = false;
-}
-
-static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- switch (priv->current_chnl_bw) {
- case HT_CHANNEL_WIDTH_20:
- priv->cck_present_attn =
- priv->cck_present_attn_20m_def +
- priv->cck_present_attn_diff;
-
- if (priv->cck_present_attn >
- (CCK_TX_BB_GAIN_TABLE_LEN - 1))
- priv->cck_present_attn =
- CCK_TX_BB_GAIN_TABLE_LEN - 1;
- if (priv->cck_present_attn < 0)
- priv->cck_present_attn = 0;
-
- if (priv->rtllib->current_network.channel == 14 &&
- !priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = true;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else if (priv->rtllib->current_network.channel !=
- 14 && priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = false;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else {
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- }
- break;
-
- case HT_CHANNEL_WIDTH_20_40:
- priv->cck_present_attn =
- priv->cck_present_attn_40m_def +
- priv->cck_present_attn_diff;
-
- if (priv->cck_present_attn >
- (CCK_TX_BB_GAIN_TABLE_LEN - 1))
- priv->cck_present_attn =
- CCK_TX_BB_GAIN_TABLE_LEN - 1;
- if (priv->cck_present_attn < 0)
- priv->cck_present_attn = 0;
-
- if (priv->rtllib->current_network.channel == 14 &&
- !priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = true;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else if (priv->rtllib->current_network.channel != 14
- && priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = false;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else {
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- }
- break;
- }
-}
-
-static void _rtl92e_cck_tx_power_track_bw_switch_thermal(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->rtllib->current_network.channel == 14 &&
- !priv->bcck_in_ch14)
- priv->bcck_in_ch14 = true;
- else if (priv->rtllib->current_network.channel != 14 &&
- priv->bcck_in_ch14)
- priv->bcck_in_ch14 = false;
-
- switch (priv->current_chnl_bw) {
- case HT_CHANNEL_WIDTH_20:
- if (priv->rec_cck_20m_idx == 0)
- priv->rec_cck_20m_idx = 6;
- priv->cck_index = priv->rec_cck_20m_idx;
- break;
-
- case HT_CHANNEL_WIDTH_20_40:
- priv->cck_index = priv->rec_cck_40m_idx;
- break;
- }
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
-}
-
-static void _rtl92e_cck_tx_power_track_bw_switch(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->ic_cut >= IC_VersionCut_D)
- _rtl92e_cck_tx_power_track_bw_switch_tssi(dev);
- else
- _rtl92e_cck_tx_power_track_bw_switch_thermal(dev);
-}
-
-static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 regBwOpMode;
-
- if (!priv->up) {
- netdev_err(dev, "%s(): Driver is not initialized\n", __func__);
- return;
- }
- regBwOpMode = rtl92e_readb(dev, BW_OPMODE);
-
- switch (priv->current_chnl_bw) {
- case HT_CHANNEL_WIDTH_20:
- regBwOpMode |= BW_OPMODE_20MHZ;
- rtl92e_writeb(dev, BW_OPMODE, regBwOpMode);
- break;
-
- case HT_CHANNEL_WIDTH_20_40:
- regBwOpMode &= ~BW_OPMODE_20MHZ;
- rtl92e_writeb(dev, BW_OPMODE, regBwOpMode);
- break;
-
- default:
- netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__,
- priv->current_chnl_bw);
- break;
- }
-
- switch (priv->current_chnl_bw) {
- case HT_CHANNEL_WIDTH_20:
- rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x0);
- rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x0);
-
- if (!priv->btxpower_tracking) {
- rtl92e_writel(dev, rCCK0_TxFilter1, 0x1a1b0000);
- rtl92e_writel(dev, rCCK0_TxFilter2, 0x090e1317);
- rtl92e_writel(dev, rCCK0_DebugPort, 0x00000204);
- } else {
- _rtl92e_cck_tx_power_track_bw_switch(dev);
- }
-
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1);
-
- break;
- case HT_CHANNEL_WIDTH_20_40:
- rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x1);
- rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x1);
-
- if (!priv->btxpower_tracking) {
- rtl92e_writel(dev, rCCK0_TxFilter1, 0x35360000);
- rtl92e_writel(dev, rCCK0_TxFilter2, 0x121c252e);
- rtl92e_writel(dev, rCCK0_DebugPort, 0x00000409);
- } else {
- _rtl92e_cck_tx_power_track_bw_switch(dev);
- }
-
- rtl92e_set_bb_reg(dev, rCCK0_System, bCCKSideBand,
- (priv->n_cur_40mhz_prime_sc >> 1));
- rtl92e_set_bb_reg(dev, rOFDM1_LSTF, 0xC00,
- priv->n_cur_40mhz_prime_sc);
-
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0);
- break;
- default:
- netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__,
- priv->current_chnl_bw);
- break;
- }
-
- rtl92e_set_bandwidth(dev, priv->current_chnl_bw);
-
- atomic_dec(&(priv->rtllib->atm_swbw));
- priv->set_bw_mode_in_progress = false;
-}
-
-void rtl92e_set_bw_mode(struct net_device *dev, enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->set_bw_mode_in_progress)
- return;
-
- atomic_inc(&(priv->rtllib->atm_swbw));
- priv->set_bw_mode_in_progress = true;
-
- priv->current_chnl_bw = bandwidth;
-
- if (Offset == HT_EXTCHNL_OFFSET_LOWER)
- priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_UPPER;
- else if (Offset == HT_EXTCHNL_OFFSET_UPPER)
- priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_LOWER;
- else
- priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
-
- _rtl92e_set_bw_mode_work_item(dev);
-}
-
-void rtl92e_init_gain(struct net_device *dev, u8 Operation)
-{
-#define SCAN_RX_INITIAL_GAIN 0x17
-#define POWER_DETECTION_TH 0x08
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 BitMask;
- u8 initial_gain;
-
- if (priv->up) {
- switch (Operation) {
- case IG_Backup:
- initial_gain = SCAN_RX_INITIAL_GAIN;
- BitMask = bMaskByte0;
- priv->initgain_backup.xaagccore1 =
- rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1,
- BitMask);
- priv->initgain_backup.xbagccore1 =
- rtl92e_get_bb_reg(dev, rOFDM0_XBAGCCore1,
- BitMask);
- priv->initgain_backup.xcagccore1 =
- rtl92e_get_bb_reg(dev, rOFDM0_XCAGCCore1,
- BitMask);
- priv->initgain_backup.xdagccore1 =
- rtl92e_get_bb_reg(dev, rOFDM0_XDAGCCore1,
- BitMask);
- BitMask = bMaskByte2;
- priv->initgain_backup.cca = (u8)rtl92e_get_bb_reg(dev,
- rCCK0_CCA, BitMask);
-
- rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain);
- rtl92e_writeb(dev, 0xa0a, POWER_DETECTION_TH);
- break;
- case IG_Restore:
- BitMask = 0x7f;
- rtl92e_set_bb_reg(dev, rOFDM0_XAAGCCore1, BitMask,
- (u32)priv->initgain_backup.xaagccore1);
- rtl92e_set_bb_reg(dev, rOFDM0_XBAGCCore1, BitMask,
- (u32)priv->initgain_backup.xbagccore1);
- rtl92e_set_bb_reg(dev, rOFDM0_XCAGCCore1, BitMask,
- (u32)priv->initgain_backup.xcagccore1);
- rtl92e_set_bb_reg(dev, rOFDM0_XDAGCCore1, BitMask,
- (u32)priv->initgain_backup.xdagccore1);
- BitMask = bMaskByte2;
- rtl92e_set_bb_reg(dev, rCCK0_CCA, BitMask,
- (u32)priv->initgain_backup.cca);
-
- rtl92e_set_tx_power(dev,
- priv->rtllib->current_network.channel);
- break;
- }
- }
-}
-
-void rtl92e_set_rf_off(struct net_device *dev)
-{
- rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, BIT(4), 0x0);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0);
- rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0);
- rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0);
- rtl92e_writeb(dev, ANAPAR_FOR_8192PCIE, 0x07);
-}
-
-static bool _rtl92e_set_rf_power_state(struct net_device *dev,
- enum rt_rf_power_state rf_power_state)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- (&priv->rtllib->pwr_save_ctrl);
- bool bResult = true;
- u8 i = 0, QueueID = 0;
- struct rtl8192_tx_ring *ring = NULL;
-
- if (priv->set_rf_pwr_state_in_progress)
- return false;
- priv->set_rf_pwr_state_in_progress = true;
-
- switch (rf_power_state) {
- case rf_on:
- if ((priv->rtllib->rf_power_state == rf_off) &&
- RT_IN_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC)) {
- bool rtstatus;
- u32 InitilizeCount = 3;
-
- do {
- InitilizeCount--;
- rtstatus = rtl92e_enable_nic(dev);
- } while (!rtstatus && (InitilizeCount > 0));
- if (!rtstatus) {
- netdev_err(dev,
- "%s(): Failed to initialize Adapter.\n",
- __func__);
- priv->set_rf_pwr_state_in_progress = false;
- return false;
- }
- RT_CLEAR_PS_LEVEL(psc,
- RT_RF_OFF_LEVL_HALT_NIC);
- } else {
- rtl92e_writeb(dev, ANAPAR, 0x37);
- mdelay(1);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1,
- 0x4, 0x1);
- priv->hw_rf_off_action = 0;
- rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE,
- BIT(4), 0x1);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4,
- 0x300, 0x3);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1,
- 0x18, 0x3);
- rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable,
- 0x3, 0x3);
- rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable,
- 0x3, 0x3);
- rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1,
- 0x60, 0x3);
- }
- break;
- case rf_sleep:
- if (priv->rtllib->rf_power_state == rf_off)
- break;
- for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) {
- ring = &priv->tx_ring[QueueID];
- if (skb_queue_len(&ring->queue) == 0) {
- QueueID++;
- continue;
- } else {
- udelay(10);
- i++;
- }
- if (i >= MAX_DOZE_WAITING_TIMES_9x)
- break;
- }
- rtl92e_set_rf_off(dev);
- break;
- case rf_off:
- for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) {
- ring = &priv->tx_ring[QueueID];
- if (skb_queue_len(&ring->queue) == 0) {
- QueueID++;
- continue;
- } else {
- udelay(10);
- i++;
- }
- if (i >= MAX_DOZE_WAITING_TIMES_9x)
- break;
- }
- rtl92e_set_rf_off(dev);
- break;
- default:
- bResult = false;
- netdev_warn(dev,
- "%s(): Unknown state requested: 0x%X.\n",
- __func__, rf_power_state);
- break;
- }
-
- if (bResult)
- priv->rtllib->rf_power_state = rf_power_state;
-
- priv->set_rf_pwr_state_in_progress = false;
- return bResult;
-}
-
-bool rtl92e_set_rf_power_state(struct net_device *dev,
- enum rt_rf_power_state rf_power_state)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- bool bResult = false;
-
- if (rf_power_state == priv->rtllib->rf_power_state &&
- priv->hw_rf_off_action == 0) {
- return bResult;
- }
-
- bResult = _rtl92e_set_rf_power_state(dev, rf_power_state);
- return bResult;
-}
-
-void rtl92e_scan_op_backup(struct net_device *dev, u8 Operation)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->up) {
- switch (Operation) {
- case SCAN_OPT_BACKUP:
- priv->rtllib->init_gain_handler(dev, IG_Backup);
- break;
-
- case SCAN_OPT_RESTORE:
- priv->rtllib->init_gain_handler(dev, IG_Restore);
- break;
- }
- }
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h
deleted file mode 100644
index 956dfbdd5b68..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _R819XU_PHY_H
-#define _R819XU_PHY_H
-
-#define MAX_DOZE_WAITING_TIMES_9x 64
-
-enum hw90_block {
- HW90_BLOCK_MAC = 0,
- HW90_BLOCK_PHY0 = 1,
- HW90_BLOCK_PHY1 = 2,
- HW90_BLOCK_RF = 3,
- HW90_BLOCK_MAXIMUM = 4,
-};
-
-enum rf90_radio_path {
- RF90_PATH_A = 0,
- RF90_PATH_B = 1,
- RF90_PATH_MAX
-};
-
-void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr,
- u32 dwBitMask, u32 dwData);
-u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask);
-void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
- u32 RegAddr, u32 BitMask, u32 Data);
-u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
- u32 RegAddr, u32 BitMask);
-void rtl92e_config_mac(struct net_device *dev);
-bool rtl92e_check_bb_and_rf(struct net_device *dev,
- enum hw90_block CheckBlock,
- enum rf90_radio_path eRFPath);
-bool rtl92e_config_bb(struct net_device *dev);
-void rtl92e_get_tx_power(struct net_device *dev);
-void rtl92e_set_tx_power(struct net_device *dev, u8 channel);
-u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath);
-
-void rtl92e_set_channel(struct net_device *dev, u8 channel);
-void rtl92e_set_bw_mode(struct net_device *dev,
- enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset);
-void rtl92e_init_gain(struct net_device *dev, u8 operation);
-
-void rtl92e_set_rf_off(struct net_device *dev);
-
-bool rtl92e_set_rf_power_state(struct net_device *dev,
- enum rt_rf_power_state rf_power_state);
-
-void rtl92e_scan_op_backup(struct net_device *dev, u8 operation);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h
deleted file mode 100644
index c48c56869c19..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h
+++ /dev/null
@@ -1,773 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _R819XU_PHYREG_H
-#define _R819XU_PHYREG_H
-
-#define RF_DATA 0x1d4
-
-#define rPMAC_Reset 0x100
-#define rPMAC_TxStart 0x104
-#define rPMAC_TxLegacySIG 0x108
-#define rPMAC_TxHTSIG1 0x10c
-#define rPMAC_TxHTSIG2 0x110
-#define rPMAC_PHYDebug 0x114
-#define rPMAC_TxPacketNum 0x118
-#define rPMAC_TxIdle 0x11c
-#define rPMAC_TxMACHeader0 0x120
-#define rPMAC_TxMACHeader1 0x124
-#define rPMAC_TxMACHeader2 0x128
-#define rPMAC_TxMACHeader3 0x12c
-#define rPMAC_TxMACHeader4 0x130
-#define rPMAC_TxMACHeader5 0x134
-#define rPMAC_TxDataType 0x138
-#define rPMAC_TxRandomSeed 0x13c
-#define rPMAC_CCKPLCPPreamble 0x140
-#define rPMAC_CCKPLCPHeader 0x144
-#define rPMAC_CCKCRC16 0x148
-#define rPMAC_OFDMRxCRC32OK 0x170
-#define rPMAC_OFDMRxCRC32Er 0x174
-#define rPMAC_OFDMRxParityEr 0x178
-#define rPMAC_OFDMRxCRC8Er 0x17c
-#define rPMAC_CCKCRxRC16Er 0x180
-#define rPMAC_CCKCRxRC32Er 0x184
-#define rPMAC_CCKCRxRC32OK 0x188
-#define rPMAC_TxStatus 0x18c
-
-#define MCS_TXAGC 0x340
-#define CCK_TXAGC 0x348
-
-/* Mac block on/off control register */
-#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */
-#define rFPGA0_TxInfo 0x804
-#define rFPGA0_PSDFunction 0x808
-#define rFPGA0_TxGainStage 0x80c
-#define rFPGA0_RFTiming1 0x810
-#define rFPGA0_RFTiming2 0x814
-#define rFPGA0_XA_HSSIParameter2 0x824
-#define rFPGA0_XB_HSSIParameter2 0x82c
-#define rFPGA0_XA_LSSIParameter 0x840
-#define rFPGA0_XB_LSSIParameter 0x844
-#define rFPGA0_RFWakeUpParameter 0x850
-#define rFPGA0_RFSleepUpParameter 0x854
-#define rFPGA0_XA_RFInterfaceOE 0x860
-#define rFPGA0_XB_RFInterfaceOE 0x864
-#define rFPGA0_XAB_RFInterfaceSW 0x870
-#define rFPGA0_AnalogParameter1 0x880
-#define rFPGA0_AnalogParameter2 0x884
-#define rFPGA0_AnalogParameter3 0x888
-#define rFPGA0_AnalogParameter4 0x88c
-#define rFPGA0_XA_LSSIReadBack 0x8a0
-#define rFPGA0_XB_LSSIReadBack 0x8a4
-#define rFPGA0_PSDReport 0x8b4
-
-/* Page 9 - RF mode & OFDM TxSC */
-#define rFPGA1_RFMOD 0x900
-#define rFPGA1_TxBlock 0x904
-#define rFPGA1_DebugSelect 0x908
-#define rFPGA1_TxInfo 0x90c
-
-#define rCCK0_System 0xa00
-#define rCCK0_AFESetting 0xa04
-#define rCCK0_CCA 0xa08
-/* AGC default value, saturation level */
-#define rCCK0_RxAGC1 0xa0c
-#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */
-#define rCCK0_RxHP 0xa14
-/* Timing recovery & channel estimation threshold */
-#define rCCK0_DSPParameter1 0xa18
-#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */
-#define rCCK0_TxFilter1 0xa20
-#define rCCK0_TxFilter2 0xa24
-#define rCCK0_DebugPort 0xa28 /* Debug port and TX filter 3 */
-#define rCCK0_FalseAlarmReport 0xa2c
-#define rCCK0_TRSSIReport 0xa50
-#define rCCK0_RxReport 0xa54
-#define rCCK0_FACounterLower 0xa5c
-#define rCCK0_FACounterUpper 0xa58
-
-#define rOFDM0_LSTF 0xc00
-#define rOFDM0_TRxPathEnable 0xc04
-#define rOFDM0_TRMuxPar 0xc08
-#define rOFDM0_TRSWIsolation 0xc0c
-#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */
-#define rOFDM0_RxDetector2 0xc34 /* SBD */
-#define rOFDM0_RxDetector3 0xc38 /* Frame Sync */
-/* PD, SBD, Frame Sync & Short-GI */
-#define rOFDM0_RxDetector4 0xc3c
-#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */
-#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */
-#define rOFDM0_CCADropThreshold 0xc48
-#define rOFDM0_ECCAThreshold 0xc4c /* Energy CCA */
-#define rOFDM0_XAAGCCore1 0xc50
-#define rOFDM0_XBAGCCore1 0xc58
-#define rOFDM0_XCAGCCore1 0xc60
-#define rOFDM0_XDAGCCore1 0xc68
-#define rOFDM0_AGCParameter1 0xc70
-#define rOFDM0_AGCParameter2 0xc74
-#define rOFDM0_AGCRSSITable 0xc78
-#define rOFDM0_HTSTFAGC 0xc7c
-#define rOFDM0_XATxIQImbalance 0xc80
-#define rOFDM0_XATxAFE 0xc84
-#define rOFDM0_XCTxIQImbalance 0xc90
-#define rOFDM0_RxHPParameter 0xce0
-#define rOFDM0_TxPseudoNoiseWgt 0xce4
-#define rOFDM0_FrameSync 0xcf0
-#define rOFDM0_DFSReport 0xcf4
-#define rOFDM0_TxCoeff1 0xca4
-#define rOFDM0_TxCoeff2 0xca8
-#define rOFDM0_TxCoeff3 0xcac
-#define rOFDM0_TxCoeff4 0xcb0
-#define rOFDM0_TxCoeff5 0xcb4
-#define rOFDM0_TxCoeff6 0xcb8
-
-#define rOFDM1_LSTF 0xd00
-#define rOFDM1_TRxPathEnable 0xd04
-#define rOFDM1_CFO 0xd08
-#define rOFDM1_CSI1 0xd10
-#define rOFDM1_SBD 0xd14
-#define rOFDM1_CSI2 0xd18
-#define rOFDM1_CFOTracking 0xd2c
-#define rOFDM1_TRxMesaure1 0xd34
-#define rOFDM1_IntfDet 0xd3c
-#define rOFDM1_PseudoNoiseStateAB 0xd50
-#define rOFDM1_PseudoNoiseStateCD 0xd54
-#define rOFDM1_RxPseudoNoiseWgt 0xd58
-#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */
-#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */
-#define rOFDM_PHYCounter3 0xda8 /* MCS not supported */
-#define rOFDM_ShortCFOAB 0xdac
-#define rOFDM_ShortCFOCD 0xdb0
-#define rOFDM_LongCFOAB 0xdb4
-#define rOFDM_LongCFOCD 0xdb8
-#define rOFDM_TailCFOAB 0xdbc
-#define rOFDM_TailCFOCD 0xdc0
-#define rOFDM_PWMeasure1 0xdc4
-#define rOFDM_PWMeasure2 0xdc8
-#define rOFDM_BWReport 0xdcc
-#define rOFDM_AGCReport 0xdd0
-#define rOFDM_RxSNR 0xdd4
-#define rOFDM_RxEVMCSI 0xdd8
-#define rOFDM_SIGReport 0xddc
-
-#define rTxAGC_Rate18_06 0xe00
-#define rTxAGC_Rate54_24 0xe04
-#define rTxAGC_CCK_Mcs32 0xe08
-#define rTxAGC_Mcs03_Mcs00 0xe10
-#define rTxAGC_Mcs07_Mcs04 0xe14
-#define rTxAGC_Mcs11_Mcs08 0xe18
-#define rTxAGC_Mcs15_Mcs12 0xe1c
-
-#define rZebra1_HSSIEnable 0x0
-#define rZebra1_TRxEnable1 0x1
-#define rZebra1_TRxEnable2 0x2
-#define rZebra1_AGC 0x4
-#define rZebra1_ChargePump 0x5
-#define rZebra1_Channel 0x7
-#define rZebra1_TxGain 0x8
-#define rZebra1_TxLPF 0x9
-#define rZebra1_RxLPF 0xb
-#define rZebra1_RxHPFCorner 0xc
-
-/* Zebra 4 */
-#define rGlobalCtrl 0
-#define rRTL8256_TxLPF 19
-#define rRTL8256_RxLPF 11
-
-/* RTL8258 */
-#define rRTL8258_TxLPF 0x11
-#define rRTL8258_RxLPF 0x13
-#define rRTL8258_RSSILPF 0xa
-
-/* Bit Mask - Page 1*/
-#define bBBResetB 0x100
-#define bGlobalResetB 0x200
-#define bOFDMTxStart 0x4
-#define bCCKTxStart 0x8
-#define bCRC32Debug 0x100
-#define bPMACLoopback 0x10
-#define bTxLSIG 0xffffff
-#define bOFDMTxRate 0xf
-#define bOFDMTxReserved 0x10
-#define bOFDMTxLength 0x1ffe0
-#define bOFDMTxParity 0x20000
-#define bTxHTSIG1 0xffffff
-#define bTxHTMCSRate 0x7f
-#define bTxHTBW 0x80
-#define bTxHTLength 0xffff00
-#define bTxHTSIG2 0xffffff
-#define bTxHTSmoothing 0x1
-#define bTxHTSounding 0x2
-#define bTxHTReserved 0x4
-#define bTxHTAggreation 0x8
-#define bTxHTSTBC 0x30
-#define bTxHTAdvanceCoding 0x40
-#define bTxHTShortGI 0x80
-#define bTxHTNumberHT_LTF 0x300
-#define bTxHTCRC8 0x3fc00
-#define bCounterReset 0x10000
-#define bNumOfOFDMTx 0xffff
-#define bNumOfCCKTx 0xffff0000
-#define bTxIdleInterval 0xffff
-#define bOFDMService 0xffff0000
-#define bTxMACHeader 0xffffffff
-#define bTxDataInit 0xff
-#define bTxHTMode 0x100
-#define bTxDataType 0x30000
-#define bTxRandomSeed 0xffffffff
-#define bCCKTxPreamble 0x1
-#define bCCKTxSFD 0xffff0000
-#define bCCKTxSIG 0xff
-#define bCCKTxService 0xff00
-#define bCCKLengthExt 0x8000
-#define bCCKTxLength 0xffff0000
-#define bCCKTxCRC16 0xffff
-#define bCCKTxStatus 0x1
-#define bOFDMTxStatus 0x2
-/* Bit Mask - Page 8 */
-#define bRFMOD 0x1
-#define bJapanMode 0x2
-#define bCCKTxSC 0x30
-#define bCCKEn 0x1000000
-#define bOFDMEn 0x2000000
-#define bOFDMRxADCPhase 0x10000
-#define bOFDMTxDACPhase 0x40000
-#define bXATxAGC 0x3f
-#define bXBTxAGC 0xf00
-#define bXCTxAGC 0xf000
-#define bXDTxAGC 0xf0000
-#define bPAStart 0xf0000000
-#define bTRStart 0x00f00000
-#define bRFStart 0x0000f000
-#define bBBStart 0x000000f0
-#define bBBCCKStart 0x0000000f
-/* Bit Mask - rFPGA0_RFTiming2 */
-#define bPAEnd 0xf
-#define bTREnd 0x0f000000
-#define bRFEnd 0x000f0000
-/* Channel gain at continue TX. */
-#define b3WireDataLength 0x800
-#define b3WireAddressLength 0x400
-/* 3-wire total control */
-#define bRFSI_RFENV 0x10
-#define bLSSIReadAddress 0x3f000000 /* LSSI "read" address */
-#define bLSSIReadEdge 0x80000000 /* LSSI "read" edge signal */
-#define bLSSIReadBackData 0xfff
-
-#define bDA6Swing 0x380000
-#define bADClkPhase 0x4000000
-#define b80MClkDelay 0x18000000
-#define bAFEWatchDogEnable 0x20000000
-#define bXtalCap 0x0f000000
-#define bXtalCap01 0xc0000000
-#define bXtalCap23 0x3
-#define bXtalCap92x 0x0f000000
-#define bIntDifClkEnable 0x400
-#define bExtSigClkEnable 0x800
-#define bBandgapMbiasPowerUp 0x10000
-#define bAD11SHGain 0xc0000
-#define bAD11InputRange 0x700000
-#define bAD11OPCurrent 0x3800000
-#define bIPathLoopback 0x4000000
-#define bQPathLoopback 0x8000000
-#define bAFELoopback 0x10000000
-#define bDA10Swing 0x7e0
-#define bDA10Reverse 0x800
-#define bDAClkSource 0x1000
-#define bAD7InputRange 0x6000
-#define bAD7Gain 0x38000
-#define bAD7OutputCMMode 0x40000
-#define bAD7InputCMMode 0x380000
-#define bAD7Current 0xc00000
-#define bRegulatorAdjust 0x7000000
-#define bAD11PowerUpAtTx 0x1
-#define bDA10PSAtTx 0x10
-#define bAD11PowerUpAtRx 0x100
-#define bDA10PSAtRx 0x1000
-
-#define bCCKRxAGCFormat 0x200
-
-#define bPSDFFTSamplepPoint 0xc000
-#define bPSDAverageNum 0x3000
-#define bIQPathControl 0xc00
-#define bPSDFreq 0x3ff
-#define bPSDAntennaPath 0x30
-#define bPSDIQSwitch 0x40
-#define bPSDRxTrigger 0x400000
-#define bPSDTxTrigger 0x80000000
-#define bPSDSineToneScale 0x7f000000
-#define bPSDReport 0xffff
-
-/* Page 8 */
-#define bOFDMTxSC 0x30000000
-#define bCCKTxOn 0x1
-#define bOFDMTxOn 0x2
-/* Reset debug page and also HWord, LWord */
-#define bDebugPage 0xfff
-/* Reset debug page and LWord */
-#define bDebugItem 0xff
-#define bAntL 0x10
-#define bAntNonHT 0x100
-#define bAntHT1 0x1000
-#define bAntHT2 0x10000
-#define bAntHT1S1 0x100000
-#define bAntNonHTS1 0x1000000
-
-/* Page a */
-#define bCCKBBMode 0x3
-#define bCCKTxPowerSaving 0x80
-#define bCCKRxPowerSaving 0x40
-#define bCCKSideBand 0x10
-#define bCCKScramble 0x8
-#define bCCKAntDiversity 0x8000
-#define bCCKCarrierRecovery 0x4000
-#define bCCKTxRate 0x3000
-#define bCCKDCCancel 0x0800
-#define bCCKISICancel 0x0400
-#define bCCKMatchFilter 0x0200
-#define bCCKEqualizer 0x0100
-#define bCCKPreambleDetect 0x800000
-#define bCCKFastFalseCCA 0x400000
-#define bCCKChEstStart 0x300000
-#define bCCKCCACount 0x080000
-#define bCCKcs_lim 0x070000
-#define bCCKBistMode 0x80000000
-#define bCCKCCAMask 0x40000000
-#define bCCKTxDACPhase 0x4
-#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */
-#define bCCKr_cp_mode0 0x0100
-#define bCCKTxDCOffset 0xf0
-#define bCCKRxDCOffset 0xf
-#define bCCKCCAMode 0xc000
-#define bCCKFalseCS_lim 0x3f00
-#define bCCKCS_ratio 0xc00000
-#define bCCKCorgBit_sel 0x300000
-#define bCCKPD_lim 0x0f0000
-#define bCCKNewCCA 0x80000000
-#define bCCKRxHPofIG 0x8000
-#define bCCKRxIG 0x7f00
-#define bCCKLNAPolarity 0x800000
-#define bCCKRx1stGain 0x7f0000
-/* CCK Rx Initial gain polarity */
-#define bCCKRFExtend 0x20000000
-#define bCCKRxAGCSatLevel 0x1f000000
-#define bCCKRxAGCSatCount 0xe0
-/* AGCSAmp_dly */
-#define bCCKRxRFSettle 0x1f
-#define bCCKFixedRxAGC 0x8000
-/*#define bCCKRxAGCFormat 0x4000 remove to HSSI register 0x824 */
-#define bCCKAntennaPolarity 0x2000
-#define bCCKTxFilterType 0x0c00
-#define bCCKRxAGCReportType 0x0300
-#define bCCKRxDAGCEn 0x80000000
-#define bCCKRxDAGCPeriod 0x20000000
-#define bCCKRxDAGCSatLevel 0x1f000000
-#define bCCKTimingRecovery 0x800000
-#define bCCKTxC0 0x3f0000
-#define bCCKTxC1 0x3f000000
-#define bCCKTxC2 0x3f
-#define bCCKTxC3 0x3f00
-#define bCCKTxC4 0x3f0000
-#define bCCKTxC5 0x3f000000
-#define bCCKTxC6 0x3f
-#define bCCKTxC7 0x3f00
-#define bCCKDebugPort 0xff0000
-#define bCCKDACDebug 0x0f000000
-#define bCCKFalseAlarmEnable 0x8000
-#define bCCKFalseAlarmRead 0x4000
-#define bCCKTRSSI 0x7f
-#define bCCKRxAGCReport 0xfe
-#define bCCKRxReport_AntSel 0x80000000
-#define bCCKRxReport_MFOff 0x40000000
-#define bCCKRxRxReport_SQLoss 0x20000000
-#define bCCKRxReport_Pktloss 0x10000000
-#define bCCKRxReport_Lockedbit 0x08000000
-#define bCCKRxReport_RateError 0x04000000
-#define bCCKRxReport_RxRate 0x03000000
-#define bCCKRxFACounterLower 0xff
-#define bCCKRxFACounterUpper 0xff000000
-#define bCCKRxHPAGCStart 0xe000
-#define bCCKRxHPAGCFinal 0x1c00
-
-#define bCCKRxFalseAlarmEnable 0x8000
-#define bCCKFACounterFreeze 0x4000
-
-#define bCCKTxPathSel 0x10000000
-#define bCCKDefaultRxPath 0xc000000
-#define bCCKOptionRxPath 0x3000000
-
-/* Page c */
-#define bNumOfSTF 0x3
-#define bShift_L 0xc0
-#define bGI_TH 0xc
-#define bRxPathA 0x1
-#define bRxPathB 0x2
-#define bRxPathC 0x4
-#define bRxPathD 0x8
-#define bTxPathA 0x1
-#define bTxPathB 0x2
-#define bTxPathC 0x4
-#define bTxPathD 0x8
-#define bTRSSIFreq 0x200
-#define bADCBackoff 0x3000
-#define bDFIRBackoff 0xc000
-#define bTRSSILatchPhase 0x10000
-#define bRxIDCOffset 0xff
-#define bRxQDCOffset 0xff00
-#define bRxDFIRMode 0x1800000
-#define bRxDCNFType 0xe000000
-#define bRXIQImb_A 0x3ff
-#define bRXIQImb_B 0xfc00
-#define bRXIQImb_C 0x3f0000
-#define bRXIQImb_D 0xffc00000
-#define bDC_dc_Notch 0x60000
-#define bRxNBINotch 0x1f000000
-#define bPD_TH 0xf
-#define bPD_TH_Opt2 0xc000
-#define bPWED_TH 0x700
-#define bIfMF_Win_L 0x800
-#define bPD_Option 0x1000
-#define bMF_Win_L 0xe000
-#define bBW_Search_L 0x30000
-#define bwin_enh_L 0xc0000
-#define bBW_TH 0x700000
-#define bED_TH2 0x3800000
-#define bBW_option 0x4000000
-#define bRatio_TH 0x18000000
-#define bWindow_L 0xe0000000
-#define bSBD_Option 0x1
-#define bFrame_TH 0x1c
-#define bFS_Option 0x60
-#define bDC_Slope_check 0x80
-#define bFGuard_Counter_DC_L 0xe00
-#define bFrame_Weight_Short 0x7000
-#define bSub_Tune 0xe00000
-#define bFrame_DC_Length 0xe000000
-#define bSBD_start_offset 0x30000000
-#define bFrame_TH_2 0x7
-#define bFrame_GI2_TH 0x38
-#define bGI2_Sync_en 0x40
-#define bSarch_Short_Early 0x300
-#define bSarch_Short_Late 0xc00
-#define bSarch_GI2_Late 0x70000
-#define bCFOAntSum 0x1
-#define bCFOAcc 0x2
-#define bCFOStartOffset 0xc
-#define bCFOLookBack 0x70
-#define bCFOSumWeight 0x80
-#define bDAGCEnable 0x10000
-#define bTXIQImb_A 0x3ff
-#define bTXIQImb_B 0xfc00
-#define bTXIQImb_C 0x3f0000
-#define bTXIQImb_D 0xffc00000
-#define bTxIDCOffset 0xff
-#define bTxQDCOffset 0xff00
-#define bTxDFIRMode 0x10000
-#define bTxPesudoNoiseOn 0x4000000
-#define bTxPesudoNoise_A 0xff
-#define bTxPesudoNoise_B 0xff00
-#define bTxPesudoNoise_C 0xff0000
-#define bTxPesudoNoise_D 0xff000000
-#define bCCADropOption 0x20000
-#define bCCADropThres 0xfff00000
-#define bEDCCA_H 0xf
-#define bEDCCA_L 0xf0
-#define bLambda_ED 0x300
-#define bRxInitialGain 0x7f
-#define bRxAntDivEn 0x80
-#define bRxAGCAddressForLNA 0x7f00
-#define bRxHighPowerFlow 0x8000
-#define bRxAGCFreezeThres 0xc0000
-#define bRxFreezeStep_AGC1 0x300000
-#define bRxFreezeStep_AGC2 0xc00000
-#define bRxFreezeStep_AGC3 0x3000000
-#define bRxFreezeStep_AGC0 0xc000000
-#define bRxRssi_Cmp_En 0x10000000
-#define bRxQuickAGCEn 0x20000000
-#define bRxAGCFreezeThresMode 0x40000000
-#define bRxOverFlowCheckType 0x80000000
-#define bRxAGCShift 0x7f
-#define bTRSW_Tri_Only 0x80
-#define bPowerThres 0x300
-#define bRxAGCEn 0x1
-#define bRxAGCTogetherEn 0x2
-#define bRxAGCMin 0x4
-#define bRxHP_Ini 0x7
-#define bRxHP_TRLNA 0x70
-#define bRxHP_RSSI 0x700
-#define bRxHP_BBP1 0x7000
-#define bRxHP_BBP2 0x70000
-#define bRxHP_BBP3 0x700000
-/* The threshold for high power */
-#define bRSSI_H 0x7f0000
-/* The threshold for ant diversity */
-#define bRSSI_Gen 0x7f000000
-#define bRxSettle_TRSW 0x7
-#define bRxSettle_LNA 0x38
-#define bRxSettle_RSSI 0x1c0
-#define bRxSettle_BBP 0xe00
-#define bRxSettle_RxHP 0x7000
-#define bRxSettle_AntSW_RSSI 0x38000
-#define bRxSettle_AntSW 0xc0000
-#define bRxProcessTime_DAGC 0x300000
-#define bRxSettle_HSSI 0x400000
-#define bRxProcessTime_BBPPW 0x800000
-#define bRxAntennaPowerShift 0x3000000
-#define bRSSITableSelect 0xc000000
-#define bRxHP_Final 0x7000000
-#define bRxHTSettle_BBP 0x7
-#define bRxHTSettle_HSSI 0x8
-#define bRxHTSettle_RxHP 0x70
-#define bRxHTSettle_BBPPW 0x80
-#define bRxHTSettle_Idle 0x300
-#define bRxHTSettle_Reserved 0x1c00
-#define bRxHTRxHPEn 0x8000
-#define bRxHTAGCFreezeThres 0x30000
-#define bRxHTAGCTogetherEn 0x40000
-#define bRxHTAGCMin 0x80000
-#define bRxHTAGCEn 0x100000
-#define bRxHTDAGCEn 0x200000
-#define bRxHTRxHP_BBP 0x1c00000
-#define bRxHTRxHP_Final 0xe0000000
-#define bRxPWRatioTH 0x3
-#define bRxPWRatioEn 0x4
-#define bRxMFHold 0x3800
-#define bRxPD_Delay_TH1 0x38
-#define bRxPD_Delay_TH2 0x1c0
-#define bRxPD_DC_COUNT_MAX 0x600
-/*#define bRxMF_Hold 0x3800*/
-#define bRxPD_Delay_TH 0x8000
-#define bRxProcess_Delay 0xf0000
-#define bRxSearchrange_GI2_Early 0x700000
-#define bRxFrame_Guard_Counter_L 0x3800000
-#define bRxSGI_Guard_L 0xc000000
-#define bRxSGI_Search_L 0x30000000
-#define bRxSGI_TH 0xc0000000
-#define bDFSCnt0 0xff
-#define bDFSCnt1 0xff00
-#define bDFSFlag 0xf0000
-
-#define bMFWeightSum 0x300000
-#define bMinIdxTH 0x7f000000
-
-#define bDAFormat 0x40000
-
-#define bTxChEmuEnable 0x01000000
-
-#define bTRSWIsolation_A 0x7f
-#define bTRSWIsolation_B 0x7f00
-#define bTRSWIsolation_C 0x7f0000
-#define bTRSWIsolation_D 0x7f000000
-
-#define bExtLNAGain 0x7c00
-
-/* Page d */
-#define bSTBCEn 0x4
-#define bAntennaMapping 0x10
-#define bNss 0x20
-#define bCFOAntSumD 0x200
-#define bPHYCounterReset 0x8000000
-#define bCFOReportGet 0x4000000
-#define bOFDMContinueTx 0x10000000
-#define bOFDMSingleCarrier 0x20000000
-#define bOFDMSingleTone 0x40000000
-/* #define bRxPath1 0x01
- * #define bRxPath2 0x02
- * #define bRxPath3 0x04
- * #define bRxPath4 0x08
- * #define bTxPath1 0x10
- * #define bTxPath2 0x20
- */
-#define bHTDetect 0x100
-#define bCFOEn 0x10000
-#define bCFOValue 0xfff00000
-#define bSigTone_Re 0x3f
-#define bSigTone_Im 0x7f00
-#define bCounter_CCA 0xffff
-#define bCounter_ParityFail 0xffff0000
-#define bCounter_RateIllegal 0xffff
-#define bCounter_CRC8Fail 0xffff0000
-#define bCounter_MCSNoSupport 0xffff
-#define bCounter_FastSync 0xffff
-#define bShortCFO 0xfff
-#define bShortCFOTLength 12 /* total */
-#define bShortCFOFLength 11 /* fraction */
-#define bLongCFO 0x7ff
-#define bLongCFOTLength 11
-#define bLongCFOFLength 11
-#define bTailCFO 0x1fff
-#define bTailCFOTLength 13
-#define bTailCFOFLength 12
-
-#define bmax_en_pwdB 0xffff
-#define bCC_power_dB 0xffff0000
-#define bnoise_pwdB 0xffff
-#define bPowerMeasTLength 10
-#define bPowerMeasFLength 3
-#define bRx_HT_BW 0x1
-#define bRxSC 0x6
-#define bRx_HT 0x8
-
-#define bNB_intf_det_on 0x1
-#define bIntf_win_len_cfg 0x30
-#define bNB_Intf_TH_cfg 0x1c0
-
-#define bRFGain 0x3f
-#define bTableSel 0x40
-#define bTRSW 0x80
-
-#define bRxSNR_A 0xff
-#define bRxSNR_B 0xff00
-#define bRxSNR_C 0xff0000
-#define bRxSNR_D 0xff000000
-#define bSNREVMTLength 8
-#define bSNREVMFLength 1
-
-#define bCSI1st 0xff
-#define bCSI2nd 0xff00
-#define bRxEVM1st 0xff0000
-#define bRxEVM2nd 0xff000000
-
-#define bSIGEVM 0xff
-#define bPWDB 0xff00
-#define bSGIEN 0x10000
-
-#define bSFactorQAM1 0xf
-#define bSFactorQAM2 0xf0
-#define bSFactorQAM3 0xf00
-#define bSFactorQAM4 0xf000
-#define bSFactorQAM5 0xf0000
-#define bSFactorQAM6 0xf0000
-#define bSFactorQAM7 0xf00000
-#define bSFactorQAM8 0xf000000
-#define bSFactorQAM9 0xf0000000
-#define bCSIScheme 0x100000
-
-#define bNoiseLvlTopSet 0x3
-#define bChSmooth 0x4
-#define bChSmoothCfg1 0x38
-#define bChSmoothCfg2 0x1c0
-#define bChSmoothCfg3 0xe00
-#define bChSmoothCfg4 0x7000
-#define bMRCMode 0x800000
-#define bTHEVMCfg 0x7000000
-
-#define bLoopFitType 0x1
-#define bUpdCFO 0x40
-#define bUpdCFOOffData 0x80
-#define bAdvUpdCFO 0x100
-#define bAdvTimeCtrl 0x800
-#define bUpdClko 0x1000
-#define bFC 0x6000
-#define bTrackingMode 0x8000
-#define bPhCmpEnable 0x10000
-#define bUpdClkoLTF 0x20000
-#define bComChCFO 0x40000
-#define bCSIEstiMode 0x80000
-#define bAdvUpdEqz 0x100000
-#define bUChCfg 0x7000000
-#define bUpdEqz 0x8000000
-
-/* Page e */
-#define bTxAGCRate18_06 0x7f7f7f7f
-#define bTxAGCRate54_24 0x7f7f7f7f
-#define bTxAGCRateMCS32 0x7f
-#define bTxAGCRateCCK 0x7f00
-#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f
-#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f
-#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f
-#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f
-
-#define bRxPesudoNoiseOn 0x20000000 /* Rx Pseduo noise */
-#define bRxPesudoNoise_A 0xff
-#define bRxPesudoNoise_B 0xff00
-#define bRxPesudoNoise_C 0xff0000
-#define bRxPesudoNoise_D 0xff000000
-#define bPesudoNoiseState_A 0xffff
-#define bPesudoNoiseState_B 0xffff0000
-#define bPesudoNoiseState_C 0xffff
-#define bPesudoNoiseState_D 0xffff0000
-
-/* RF Zebra 1 */
-#define bZebra1_HSSIEnable 0x8
-#define bZebra1_TRxControl 0xc00
-#define bZebra1_TRxGainSetting 0x07f
-#define bZebra1_RxCorner 0xc00
-#define bZebra1_TxChargePump 0x38
-#define bZebra1_RxChargePump 0x7
-#define bZebra1_ChannelNum 0xf80
-#define bZebra1_TxLPFBW 0x400
-#define bZebra1_RxLPFBW 0x600
-
-/* Zebra4 */
-#define bRTL8256RegModeCtrl1 0x100
-#define bRTL8256RegModeCtrl0 0x40
-#define bRTL8256_TxLPFBW 0x18
-#define bRTL8256_RxLPFBW 0x600
-
-/* RTL8258 */
-#define bRTL8258_TxLPFBW 0xc
-#define bRTL8258_RxLPFBW 0xc00
-#define bRTL8258_RSSILPFBW 0xc0
-
-/* byte enable for sb_write */
-#define bByte0 0x1
-#define bByte1 0x2
-#define bByte2 0x4
-#define bByte3 0x8
-#define bWord0 0x3
-#define bWord1 0xc
-#define bDWord 0xf
-
-/* for PutRegsetting & GetRegSetting BitMask */
-#define bMaskByte0 0xff
-#define bMaskByte1 0xff00
-#define bMaskByte2 0xff0000
-#define bMaskByte3 0xff000000
-#define bMaskHWord 0xffff0000
-#define bMaskLWord 0x0000ffff
-#define bMaskDWord 0xffffffff
-
-/* for PutRFRegsetting & GetRFRegSetting BitMask */
-#define bMask12Bits 0xfff
-
-#define bEnable 0x1
-#define bDisable 0x0
-
-#define LeftAntenna 0x0
-#define RightAntenna 0x1
-
-#define tCheckTxStatus 500 /* 500 ms */
-#define tUpdateRxCounter 100 /* 100 ms */
-
-#define rateCCK 0
-#define rateOFDM 1
-#define rateHT 2
-
-#define bPMAC_End 0x1ff /* define Register-End */
-#define bFPGAPHY0_End 0x8ff
-#define bFPGAPHY1_End 0x9ff
-#define bCCKPHY0_End 0xaff
-#define bOFDMPHY0_End 0xcff
-#define bOFDMPHY1_End 0xdff
-
-#define bPMACControl 0x0
-#define bWMACControl 0x1
-#define bWNICControl 0x2
-
-#define PathA 0x0
-#define PathB 0x1
-#define PathC 0x2
-#define PathD 0x3
-
-#define rRTL8256RxMixerPole 0xb
-#define bZebraRxMixerPole 0x6
-#define rRTL8256TxBBOPBias 0x9
-#define bRTL8256TxBBOPBias 0x400
-#define rRTL8256TxBBBW 19
-#define bRTL8256TxBBBW 0x18
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
deleted file mode 100644
index 69298c7c129a..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ /dev/null
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_phy.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */
-#include "r8192E_cmdpkt.h"
-
-void rtl92e_cam_reset(struct net_device *dev)
-{
- u32 ulcommand = 0;
-
- ulcommand |= BIT(31) | BIT(30);
- rtl92e_writel(dev, RWCAM, ulcommand);
-}
-
-void rtl92e_enable_hw_security_config(struct net_device *dev)
-{
- u8 SECR_value = 0x0;
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- SECR_value = SCR_TxEncEnable | SCR_RxDecEnable;
- if (((ieee->pairwise_key_type == KEY_TYPE_WEP40) ||
- (ieee->pairwise_key_type == KEY_TYPE_WEP104)) &&
- (priv->rtllib->auth_mode != 2)) {
- SECR_value |= SCR_RxUseDK;
- SECR_value |= SCR_TxUseDK;
- }
-
- ieee->hwsec_active = 1;
- if ((ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE) || !hwwep) {
- ieee->hwsec_active = 0;
- SECR_value &= ~SCR_RxDecEnable;
- }
- rtl92e_writeb(dev, SECR, SECR_value);
-}
-
-void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex,
- u16 KeyType, const u8 *MacAddr, u32 *KeyContent)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- if (EntryNo >= TOTAL_CAM_ENTRY)
- return;
-
- ieee->swcamtable[EntryNo].bused = true;
- ieee->swcamtable[EntryNo].key_index = KeyIndex;
- ieee->swcamtable[EntryNo].key_type = KeyType;
- memcpy(ieee->swcamtable[EntryNo].macaddr, MacAddr, 6);
- ieee->swcamtable[EntryNo].useDK = 0;
- memcpy(ieee->swcamtable[EntryNo].key_buf, (u8 *)KeyContent, 16);
-}
-
-void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex,
- u16 KeyType, const u8 *MacAddr, u8 DefaultKey,
- u32 *KeyContent)
-{
- u32 TargetCommand = 0;
- u32 TargetContent = 0;
- u16 usConfig = 0;
- u8 i;
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- enum rt_rf_power_state rt_state;
-
- rt_state = priv->rtllib->rf_power_state;
- if (rt_state == rf_off) {
- if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) {
- netdev_warn(dev, "%s(): RF is OFF.\n",
- __func__);
- return;
- }
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
- }
- priv->rtllib->is_set_key = true;
- if (EntryNo >= TOTAL_CAM_ENTRY) {
- netdev_info(dev, "%s(): Invalid CAM entry\n", __func__);
- return;
- }
-
- if (DefaultKey)
- usConfig |= BIT(15) | (KeyType << 2);
- else
- usConfig |= BIT(15) | (KeyType << 2) | KeyIndex;
-
- for (i = 0; i < CAM_CONTENT_COUNT; i++) {
- TargetCommand = i + CAM_CONTENT_COUNT * EntryNo;
- TargetCommand |= BIT(31) | BIT(16);
-
- if (i == 0) {
- TargetContent = (u32)(*(MacAddr + 0)) << 16 |
- (u32)(*(MacAddr + 1)) << 24 |
- (u32)usConfig;
-
- rtl92e_writel(dev, WCAMI, TargetContent);
- rtl92e_writel(dev, RWCAM, TargetCommand);
- } else if (i == 1) {
- TargetContent = (u32)(*(MacAddr + 2)) |
- (u32)(*(MacAddr + 3)) << 8 |
- (u32)(*(MacAddr + 4)) << 16 |
- (u32)(*(MacAddr + 5)) << 24;
- rtl92e_writel(dev, WCAMI, TargetContent);
- rtl92e_writel(dev, RWCAM, TargetCommand);
- } else {
- if (KeyContent) {
- rtl92e_writel(dev, WCAMI,
- (u32)(*(KeyContent + i - 2)));
- rtl92e_writel(dev, RWCAM, TargetCommand);
- udelay(100);
- }
- }
- }
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
deleted file mode 100644
index 9deffdf96072..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL_CAM_H
-#define _RTL_CAM_H
-
-#include <linux/types.h>
-
-struct net_device;
-
-void rtl92e_cam_reset(struct net_device *dev);
-void rtl92e_enable_hw_security_config(struct net_device *dev);
-void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex,
- u16 KeyType, const u8 *MacAddr, u8 DefaultKey,
- u32 *KeyContent);
-void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex,
- u16 KeyType, const u8 *MacAddr, u32 *KeyContent);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
deleted file mode 100644
index dc1301f1a0c1..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ /dev/null
@@ -1,2016 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include <linux/uaccess.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/ieee80211.h>
-#include "rtl_core.h"
-#include "r8192E_phy.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h"
-#include "r8192E_cmdpkt.h"
-
-#include "rtl_wx.h"
-#include "rtl_dm.h"
-
-#include "rtl_pm.h"
-
-int hwwep = 1;
-static char *ifname = "wlan%d";
-
-static const struct pci_device_id rtl8192_pci_id_tbl[] = {
- {PCI_DEVICE(0x10ec, 0x8192)},
- {PCI_DEVICE(0x07aa, 0x0044)},
- {PCI_DEVICE(0x07aa, 0x0047)},
- {}
-};
-
-MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl);
-
-static int _rtl92e_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id);
-static void _rtl92e_pci_disconnect(struct pci_dev *pdev);
-static irqreturn_t _rtl92e_irq(int irq, void *netdev);
-
-static SIMPLE_DEV_PM_OPS(rtl92e_pm_ops, rtl92e_suspend, rtl92e_resume);
-
-static struct pci_driver rtl8192_pci_driver = {
- .name = DRV_NAME, /* Driver name */
- .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */
- .probe = _rtl92e_pci_probe, /* probe fn */
- .remove = _rtl92e_pci_disconnect, /* remove fn */
- .driver.pm = &rtl92e_pm_ops,
-};
-
-static short _rtl92e_is_tx_queue_empty(struct net_device *dev);
-static void _rtl92e_watchdog_wq_cb(void *data);
-static void _rtl92e_watchdog_timer_cb(struct timer_list *t);
-static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
- int rate);
-static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb);
-static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb);
-static short _rtl92e_pci_initdescring(struct net_device *dev);
-static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t);
-static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t);
-static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv);
-static int _rtl92e_up(struct net_device *dev);
-static int _rtl92e_try_up(struct net_device *dev);
-static int _rtl92e_down(struct net_device *dev, bool shutdownrf);
-static void _rtl92e_restart(void *data);
-
-/****************************************************************************
- * -----------------------------IO STUFF-------------------------
- ****************************************************************************/
-
-u8 rtl92e_readb(struct net_device *dev, int x)
-{
- return 0xff & readb((u8 __iomem *)dev->mem_start + x);
-}
-
-u32 rtl92e_readl(struct net_device *dev, int x)
-{
- return readl((u8 __iomem *)dev->mem_start + x);
-}
-
-u16 rtl92e_readw(struct net_device *dev, int x)
-{
- return readw((u8 __iomem *)dev->mem_start + x);
-}
-
-void rtl92e_writeb(struct net_device *dev, int x, u8 y)
-{
- writeb(y, (u8 __iomem *)dev->mem_start + x);
-
- udelay(20);
-}
-
-void rtl92e_writel(struct net_device *dev, int x, u32 y)
-{
- writel(y, (u8 __iomem *)dev->mem_start + x);
-
- udelay(20);
-}
-
-void rtl92e_writew(struct net_device *dev, int x, u16 y)
-{
- writew(y, (u8 __iomem *)dev->mem_start + x);
-
- udelay(20);
-}
-
-/****************************************************************************
- * -----------------------------GENERAL FUNCTION-------------------------
- ****************************************************************************/
-bool rtl92e_set_rf_state(struct net_device *dev,
- enum rt_rf_power_state state_to_set,
- RT_RF_CHANGE_SOURCE change_source)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- bool action_allowed = false;
- bool connect_by_ssid = false;
- enum rt_rf_power_state rt_state;
- u16 rf_wait_counter = 0;
- unsigned long flag;
-
- while (true) {
- spin_lock_irqsave(&priv->rf_ps_lock, flag);
- if (priv->rf_change_in_progress) {
- spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
-
- while (priv->rf_change_in_progress) {
- rf_wait_counter++;
- mdelay(1);
-
- if (rf_wait_counter > 100) {
- netdev_warn(dev,
- "%s(): Timeout waiting for RF change.\n",
- __func__);
- return false;
- }
- }
- } else {
- priv->rf_change_in_progress = true;
- spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
- break;
- }
- }
-
- rt_state = priv->rtllib->rf_power_state;
-
- switch (state_to_set) {
- case rf_on:
- priv->rtllib->rf_off_reason &= (~change_source);
-
- if ((change_source == RF_CHANGE_BY_HW) && priv->hw_radio_off)
- priv->hw_radio_off = false;
-
- if (!priv->rtllib->rf_off_reason) {
- priv->rtllib->rf_off_reason = 0;
- action_allowed = true;
-
- if (rt_state == rf_off &&
- change_source >= RF_CHANGE_BY_HW)
- connect_by_ssid = true;
- }
- break;
-
- case rf_off:
-
- if (priv->rtllib->iw_mode == IW_MODE_INFRA) {
- if ((priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) ||
- (change_source > RF_CHANGE_BY_IPS)) {
- if (ieee->link_state == MAC80211_LINKED)
- priv->blinked_ingpio = true;
- else
- priv->blinked_ingpio = false;
- rtllib_mgnt_disconnect(priv->rtllib,
- WLAN_REASON_DISASSOC_STA_HAS_LEFT);
- }
- }
- if ((change_source == RF_CHANGE_BY_HW) && !priv->hw_radio_off)
- priv->hw_radio_off = true;
- priv->rtllib->rf_off_reason |= change_source;
- action_allowed = true;
- break;
-
- case rf_sleep:
- priv->rtllib->rf_off_reason |= change_source;
- action_allowed = true;
- break;
-
- default:
- break;
- }
-
- if (action_allowed) {
- rtl92e_set_rf_power_state(dev, state_to_set);
- if (state_to_set == rf_on) {
- if (connect_by_ssid && priv->blinked_ingpio) {
- schedule_delayed_work(
- &ieee->associate_procedure_wq, 0);
- priv->blinked_ingpio = false;
- }
- }
- }
-
- spin_lock_irqsave(&priv->rf_ps_lock, flag);
- priv->rf_change_in_progress = false;
- spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
- return action_allowed;
-}
-
-static short _rtl92e_check_nic_enough_desc(struct net_device *dev, int prio)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtl8192_tx_ring *ring = &priv->tx_ring[prio];
-
- if (ring->entries - skb_queue_len(&ring->queue) >= 2)
- return 1;
- return 0;
-}
-
-static void _rtl92e_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- schedule_work(&priv->reset_wq);
- netdev_info(dev, "TXTIMEOUT");
-}
-
-static void _rtl92e_update_cap(struct net_device *dev, u16 cap)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_network *net = &priv->rtllib->current_network;
- bool ShortPreamble;
-
- if (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) {
- if (priv->dot11_current_preamble_mode != PREAMBLE_SHORT) {
- ShortPreamble = true;
- priv->dot11_current_preamble_mode = PREAMBLE_SHORT;
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE,
- (unsigned char *)&ShortPreamble);
- }
- } else {
- if (priv->dot11_current_preamble_mode != PREAMBLE_LONG) {
- ShortPreamble = false;
- priv->dot11_current_preamble_mode = PREAMBLE_LONG;
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE,
- (unsigned char *)&ShortPreamble);
- }
- }
-
- if (net->mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) {
- u8 slot_time_val;
- u8 cur_slot_time = priv->slot_time;
-
- if ((cap & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
- (!priv->rtllib->ht_info->current_rt2rt_long_slot_time)) {
- if (cur_slot_time != SHORT_SLOT_TIME) {
- slot_time_val = SHORT_SLOT_TIME;
- priv->rtllib->set_hw_reg_handler(dev,
- HW_VAR_SLOT_TIME, &slot_time_val);
- }
- } else {
- if (cur_slot_time != NON_SHORT_SLOT_TIME) {
- slot_time_val = NON_SHORT_SLOT_TIME;
- priv->rtllib->set_hw_reg_handler(dev,
- HW_VAR_SLOT_TIME, &slot_time_val);
- }
- }
- }
-}
-
-static const struct rtllib_qos_parameters def_qos_parameters = {
- {cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3)},
- {cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7)},
- {2, 2, 2, 2},
- {0, 0, 0, 0},
- {0, 0, 0, 0}
-};
-
-static void _rtl92e_update_beacon(void *data)
-{
- struct r8192_priv *priv = container_of(data, struct r8192_priv, update_beacon_wq.work);
- struct net_device *dev = priv->rtllib->dev;
- struct rtllib_device *ieee = priv->rtllib;
- struct rtllib_network *net = &ieee->current_network;
-
- if (ieee->ht_info->current_ht_support)
- HT_update_self_and_peer_setting(ieee, net);
- ieee->ht_info->current_rt2rt_long_slot_time = net->bssht.bd_rt2rt_long_slot_time;
- _rtl92e_update_cap(dev, net->capability);
-}
-
-static void _rtl92e_qos_activate(void *data)
-{
- struct r8192_priv *priv = container_of(data, struct r8192_priv, qos_activate);
- struct net_device *dev = priv->rtllib->dev;
- int i;
-
- mutex_lock(&priv->mutex);
- if (priv->rtllib->link_state != MAC80211_LINKED)
- goto success;
-
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM, (u8 *)(&i));
-
-success:
- mutex_unlock(&priv->mutex);
-}
-
-static int _rtl92e_qos_handle_probe_response(struct r8192_priv *priv,
- int active_network,
- struct rtllib_network *network)
-{
- int ret = 0;
- u32 size = sizeof(struct rtllib_qos_parameters);
-
- if (priv->rtllib->link_state != MAC80211_LINKED)
- return ret;
-
- if (priv->rtllib->iw_mode != IW_MODE_INFRA)
- return ret;
-
- if (network->flags & NETWORK_HAS_QOS_MASK) {
- if (active_network &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS))
- network->qos_data.active = network->qos_data.supported;
-
- if ((network->qos_data.active == 1) && (active_network == 1) &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
- (network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- priv->rtllib->wmm_acm = network->qos_data.wmm_acm;
- schedule_work(&priv->qos_activate);
- }
- } else {
- memcpy(&priv->rtllib->current_network.qos_data.parameters,
- &def_qos_parameters, size);
-
- if ((network->qos_data.active == 1) && (active_network == 1))
- schedule_work(&priv->qos_activate);
-
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- }
-
- return 0;
-}
-
-static int _rtl92e_handle_beacon(struct net_device *dev,
- struct rtllib_beacon *beacon,
- struct rtllib_network *network)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- _rtl92e_qos_handle_probe_response(priv, 1, network);
-
- schedule_delayed_work(&priv->update_beacon_wq, 0);
- return 0;
-}
-
-static int _rtl92e_qos_assoc_resp(struct r8192_priv *priv,
- struct rtllib_network *network)
-{
- unsigned long flags;
- u32 size = sizeof(struct rtllib_qos_parameters);
- int set_qos_param = 0;
-
- if (!priv || !network)
- return 0;
-
- if (priv->rtllib->link_state != MAC80211_LINKED)
- return 0;
-
- if (priv->rtllib->iw_mode != IW_MODE_INFRA)
- return 0;
-
- spin_lock_irqsave(&priv->rtllib->lock, flags);
- if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
- memcpy(&priv->rtllib->current_network.qos_data.parameters,
- &network->qos_data.parameters,
- sizeof(struct rtllib_qos_parameters));
- priv->rtllib->current_network.qos_data.active = 1;
- priv->rtllib->wmm_acm = network->qos_data.wmm_acm;
- set_qos_param = 1;
- priv->rtllib->current_network.qos_data.old_param_count =
- priv->rtllib->current_network.qos_data.param_count;
- priv->rtllib->current_network.qos_data.param_count =
- network->qos_data.param_count;
- } else {
- memcpy(&priv->rtllib->current_network.qos_data.parameters,
- &def_qos_parameters, size);
- priv->rtllib->current_network.qos_data.active = 0;
- priv->rtllib->current_network.qos_data.supported = 0;
- set_qos_param = 1;
- }
-
- spin_unlock_irqrestore(&priv->rtllib->lock, flags);
-
- if (set_qos_param == 1) {
- rtl92e_dm_init_edca_turbo(priv->rtllib->dev);
- schedule_work(&priv->qos_activate);
- }
- return 0;
-}
-
-static int _rtl92e_handle_assoc_response(struct net_device *dev,
- struct rtllib_assoc_response_frame *resp,
- struct rtllib_network *network)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- _rtl92e_qos_assoc_resp(priv, network);
- return 0;
-}
-
-void rtl92e_config_rate(struct net_device *dev, u16 *rate_config)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_network *net;
- u8 i = 0, basic_rate = 0;
-
- net = &priv->rtllib->current_network;
-
- for (i = 0; i < net->rates_len; i++) {
- basic_rate = net->rates[i] & 0x7f;
- switch (basic_rate) {
- case MGN_1M:
- *rate_config |= RRSR_1M;
- break;
- case MGN_2M:
- *rate_config |= RRSR_2M;
- break;
- case MGN_5_5M:
- *rate_config |= RRSR_5_5M;
- break;
- case MGN_11M:
- *rate_config |= RRSR_11M;
- break;
- case MGN_6M:
- *rate_config |= RRSR_6M;
- break;
- case MGN_9M:
- *rate_config |= RRSR_9M;
- break;
- case MGN_12M:
- *rate_config |= RRSR_12M;
- break;
- case MGN_18M:
- *rate_config |= RRSR_18M;
- break;
- case MGN_24M:
- *rate_config |= RRSR_24M;
- break;
- case MGN_36M:
- *rate_config |= RRSR_36M;
- break;
- case MGN_48M:
- *rate_config |= RRSR_48M;
- break;
- case MGN_54M:
- *rate_config |= RRSR_54M;
- break;
- }
- }
-
- for (i = 0; i < net->rates_ex_len; i++) {
- basic_rate = net->rates_ex[i] & 0x7f;
- switch (basic_rate) {
- case MGN_1M:
- *rate_config |= RRSR_1M;
- break;
- case MGN_2M:
- *rate_config |= RRSR_2M;
- break;
- case MGN_5_5M:
- *rate_config |= RRSR_5_5M;
- break;
- case MGN_11M:
- *rate_config |= RRSR_11M;
- break;
- case MGN_6M:
- *rate_config |= RRSR_6M;
- break;
- case MGN_9M:
- *rate_config |= RRSR_9M;
- break;
- case MGN_12M:
- *rate_config |= RRSR_12M;
- break;
- case MGN_18M:
- *rate_config |= RRSR_18M;
- break;
- case MGN_24M:
- *rate_config |= RRSR_24M;
- break;
- case MGN_36M:
- *rate_config |= RRSR_36M;
- break;
- case MGN_48M:
- *rate_config |= RRSR_48M;
- break;
- case MGN_54M:
- *rate_config |= RRSR_54M;
- break;
- }
- }
-}
-
-static void _rtl92e_refresh_support_rate(struct r8192_priv *priv)
-{
- struct rtllib_device *ieee = priv->rtllib;
-
- if (ieee->mode == WIRELESS_MODE_N_24G) {
- memcpy(ieee->reg_dot11ht_oper_rate_set,
- ieee->reg_ht_supp_rate_set, 16);
- memcpy(ieee->reg_dot11tx_ht_oper_rate_set,
- ieee->reg_ht_supp_rate_set, 16);
-
- } else {
- memset(ieee->reg_dot11ht_oper_rate_set, 0, 16);
- }
-}
-
-void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 support_mode = (WIRELESS_MODE_N_24G | WIRELESS_MODE_G | WIRELESS_MODE_B);
-
- if ((wireless_mode == WIRELESS_MODE_AUTO) || ((wireless_mode & support_mode) == 0))
- wireless_mode = WIRELESS_MODE_N_24G;
-
- if ((wireless_mode & (WIRELESS_MODE_B | WIRELESS_MODE_G)) ==
- (WIRELESS_MODE_G | WIRELESS_MODE_B))
- wireless_mode = WIRELESS_MODE_G;
-
- priv->rtllib->mode = wireless_mode;
-
- if (wireless_mode == WIRELESS_MODE_N_24G)
- priv->rtllib->ht_info->enable_ht = 1;
- else
- priv->rtllib->ht_info->enable_ht = 0;
-
- _rtl92e_refresh_support_rate(priv);
-}
-
-static int _rtl92e_sta_up(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- (&priv->rtllib->pwr_save_ctrl);
- bool init_status;
-
- priv->up = 1;
- priv->rtllib->ieee_up = 1;
-
- priv->up_first_time = 0;
- init_status = rtl92e_start_adapter(dev);
- if (!init_status) {
- netdev_err(dev, "%s(): Initialization failed!\n", __func__);
- return -1;
- }
-
- RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC);
-
- if (priv->polling_timer_on == 0)
- rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer);
-
- if (priv->rtllib->link_state != MAC80211_LINKED)
- rtllib_softmac_start_protocol(priv->rtllib);
- rtllib_reset_queue(priv->rtllib);
- _rtl92e_watchdog_timer_cb(&priv->watch_dog_timer);
-
- if (!netif_queue_stopped(dev))
- netif_start_queue(dev);
- else
- netif_wake_queue(dev);
-
- priv->bfirst_after_down = false;
- return 0;
-}
-
-static int _rtl92e_sta_down(struct net_device *dev, bool shutdownrf)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- unsigned long flags = 0;
- u8 rf_in_progress_timeout = 0;
-
- if (priv->up == 0)
- return -1;
-
- priv->rtllib->rtllib_ips_leave(dev);
-
- if (priv->rtllib->link_state == MAC80211_LINKED)
- rtl92e_leisure_ps_leave(dev);
-
- priv->up = 0;
- priv->rtllib->ieee_up = 0;
- priv->bfirst_after_down = true;
- if (!netif_queue_stopped(dev))
- netif_stop_queue(dev);
-
- priv->rtllib->wpa_ie_len = 0;
- kfree(priv->rtllib->wpa_ie);
- priv->rtllib->wpa_ie = NULL;
- rtl92e_cam_reset(dev);
- memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32);
- rtl92e_irq_disable(dev);
-
- del_timer_sync(&priv->watch_dog_timer);
- _rtl92e_cancel_deferred_work(priv);
- cancel_delayed_work(&priv->rtllib->hw_wakeup_wq);
-
- rtllib_softmac_stop_protocol(priv->rtllib);
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- while (priv->rf_change_in_progress) {
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- if (rf_in_progress_timeout > 100) {
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- break;
- }
- mdelay(1);
- rf_in_progress_timeout++;
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- }
- priv->rf_change_in_progress = true;
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- rtl92e_stop_adapter(dev, false);
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- priv->rf_change_in_progress = false;
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- udelay(100);
- memset(&priv->rtllib->current_network, 0,
- offsetof(struct rtllib_network, list));
-
- return 0;
-}
-
-static void _rtl92e_init_priv_handler(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->rtllib->softmac_hard_start_xmit = _rtl92e_hard_start_xmit;
- priv->rtllib->set_chan = rtl92e_set_channel;
- priv->rtllib->link_change = rtl92e_link_change;
- priv->rtllib->softmac_data_hard_start_xmit = _rtl92e_hard_data_xmit;
- priv->rtllib->check_nic_enough_desc = _rtl92e_check_nic_enough_desc;
- priv->rtllib->handle_assoc_response = _rtl92e_handle_assoc_response;
- priv->rtllib->handle_beacon = _rtl92e_handle_beacon;
- priv->rtllib->set_wireless_mode = rtl92e_set_wireless_mode;
- priv->rtllib->leisure_ps_leave = rtl92e_leisure_ps_leave;
- priv->rtllib->set_bw_mode_handler = rtl92e_set_bw_mode;
-
- priv->rtllib->sta_wake_up = rtl92e_hw_wakeup;
- priv->rtllib->enter_sleep_state = rtl92e_enter_sleep;
- priv->rtllib->ps_is_queue_empty = _rtl92e_is_tx_queue_empty;
-
- priv->rtllib->get_nmode_support_by_sec_cfg = rtl92e_get_nmode_support_by_sec;
- priv->rtllib->get_half_nmode_support_by_aps_handler =
- rtl92e_is_halfn_supported_by_ap;
-
- priv->rtllib->set_hw_reg_handler = rtl92e_set_reg;
- priv->rtllib->allow_all_dest_addr_handler = rtl92e_set_monitor_mode;
- priv->rtllib->init_gain_handler = rtl92e_init_gain;
- priv->rtllib->rtllib_ips_leave_wq = rtl92e_rtllib_ips_leave_wq;
- priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave;
- priv->rtllib->scan_operation_backup_handler = rtl92e_scan_op_backup;
-}
-
-static void _rtl92e_init_priv_variable(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 i;
-
- priv->dot11_current_preamble_mode = PREAMBLE_AUTO;
- priv->rtllib->status = 0;
- priv->polling_timer_on = 0;
- priv->up_first_time = 1;
- priv->blinked_ingpio = false;
- priv->being_init_adapter = false;
- priv->txringcount = 64;
- priv->rxbuffersize = 9100;
- priv->rxringcount = MAX_RX_COUNT;
- priv->irq_enabled = 0;
- priv->chan = 1;
- priv->rtllib->mode = WIRELESS_MODE_AUTO;
- priv->rtllib->iw_mode = IW_MODE_INFRA;
- priv->rtllib->ieee_up = 0;
- priv->retry_rts = DEFAULT_RETRY_RTS;
- priv->retry_data = DEFAULT_RETRY_DATA;
- priv->rtllib->rts = DEFAULT_RTS_THRESHOLD;
- priv->rtllib->rate = 110;
- priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
- priv->bcck_in_ch14 = false;
- priv->cck_present_attn = 0;
- priv->rfa_txpowertrackingindex = 0;
- priv->cck_pwr_enl = 6;
- memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32);
- priv->rx_ctr = 0;
- priv->rtllib->wx_set_enc = 0;
- priv->hw_radio_off = false;
- priv->rtllib->rf_off_reason = 0;
- priv->rf_change_in_progress = false;
- priv->hw_rf_off_action = 0;
- priv->set_rf_pwr_state_in_progress = false;
- priv->rtllib->pwr_save_ctrl.bLeisurePs = true;
- priv->rtllib->lps_delay_cnt = 0;
- priv->rtllib->sta_sleep = LPS_IS_WAKE;
- priv->rtllib->rf_power_state = rf_on;
-
- priv->rtllib->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
- priv->rtllib->iw_mode = IW_MODE_INFRA;
- priv->rtllib->be_scan_inprogress = false;
-
- priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD;
-
- priv->fw_info = vzalloc(sizeof(struct rt_firmware));
- if (!priv->fw_info)
- netdev_err(dev,
- "rtl8192e: Unable to allocate space for firmware\n");
-
- skb_queue_head_init(&priv->skb_queue);
-
- for (i = 0; i < MAX_QUEUE_SIZE; i++)
- skb_queue_head_init(&priv->rtllib->skb_waitq[i]);
-}
-
-static void _rtl92e_init_priv_lock(struct r8192_priv *priv)
-{
- spin_lock_init(&priv->tx_lock);
- spin_lock_init(&priv->irq_th_lock);
- spin_lock_init(&priv->rf_ps_lock);
- spin_lock_init(&priv->ps_lock);
- mutex_init(&priv->wx_mutex);
- mutex_init(&priv->rf_mutex);
- mutex_init(&priv->mutex);
-}
-
-static void _rtl92e_init_priv_task(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- INIT_WORK(&priv->reset_wq, (void *)_rtl92e_restart);
- INIT_WORK(&priv->rtllib->ips_leave_wq, (void *)rtl92e_ips_leave_wq);
- INIT_DELAYED_WORK(&priv->watch_dog_wq, (void *)_rtl92e_watchdog_wq_cb);
- INIT_DELAYED_WORK(&priv->txpower_tracking_wq, (void *)rtl92e_dm_txpower_tracking_wq);
- INIT_DELAYED_WORK(&priv->rfpath_check_wq, (void *)rtl92e_dm_rf_pathcheck_wq);
- INIT_DELAYED_WORK(&priv->update_beacon_wq, (void *)_rtl92e_update_beacon);
- INIT_WORK(&priv->qos_activate, (void *)_rtl92e_qos_activate);
- INIT_DELAYED_WORK(&priv->rtllib->hw_wakeup_wq, (void *)rtl92e_hw_wakeup_wq);
- INIT_DELAYED_WORK(&priv->rtllib->hw_sleep_wq, (void *)rtl92e_hw_sleep_wq);
- tasklet_setup(&priv->irq_rx_tasklet, _rtl92e_irq_rx_tasklet);
- tasklet_setup(&priv->irq_tx_tasklet, _rtl92e_irq_tx_tasklet);
-}
-
-static short _rtl92e_get_channel_map(struct net_device *dev)
-{
- int i;
-
- struct r8192_priv *priv = rtllib_priv(dev);
-
- for (i = 1; i <= 11; i++)
- (priv->rtllib->active_channel_map)[i] = 1;
- (priv->rtllib->active_channel_map)[12] = 2;
- (priv->rtllib->active_channel_map)[13] = 2;
-
- return 0;
-}
-
-static short _rtl92e_init(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- memset(&priv->stats, 0, sizeof(struct rt_stats));
-
- _rtl92e_init_priv_handler(dev);
- _rtl92e_init_priv_variable(dev);
- _rtl92e_init_priv_lock(priv);
- _rtl92e_init_priv_task(dev);
- rtl92e_get_eeprom_size(dev);
- rtl92e_init_variables(dev);
- _rtl92e_get_channel_map(dev);
-
- rtl92e_dm_init(dev);
-
- timer_setup(&priv->watch_dog_timer, _rtl92e_watchdog_timer_cb, 0);
-
- timer_setup(&priv->gpio_polling_timer, rtl92e_check_rfctrl_gpio_timer,
- 0);
-
- rtl92e_irq_disable(dev);
- if (request_irq(dev->irq, _rtl92e_irq, IRQF_SHARED, dev->name, dev)) {
- netdev_err(dev, "Error allocating IRQ %d", dev->irq);
- return -1;
- }
-
- priv->irq = dev->irq;
-
- if (_rtl92e_pci_initdescring(dev) != 0) {
- netdev_err(dev, "Endopoints initialization failed");
- free_irq(dev->irq, dev);
- return -1;
- }
-
- return 0;
-}
-
-/***************************************************************************
- * -------------------------------WATCHDOG STUFF---------------------------
- **************************************************************************/
-static short _rtl92e_is_tx_queue_empty(struct net_device *dev)
-{
- int i = 0;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- for (i = 0; i <= MGNT_QUEUE; i++) {
- if ((i == TXCMD_QUEUE) || (i == HCCA_QUEUE))
- continue;
- if (skb_queue_len(&(&priv->tx_ring[i])->queue) > 0) {
- netdev_info(dev, "===>tx queue is not empty:%d, %d\n",
- i, skb_queue_len(&(&priv->tx_ring[i])->queue));
- return 0;
- }
- }
- return 1;
-}
-
-static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 QueueID;
- bool bCheckFwTxCnt = false;
- struct rtl8192_tx_ring *ring = NULL;
- struct sk_buff *skb = NULL;
- struct cb_desc *tcb_desc = NULL;
- unsigned long flags = 0;
-
- switch (priv->rtllib->ps) {
- case RTLLIB_PS_DISABLED:
- break;
- case (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST):
- break;
- default:
- break;
- }
- spin_lock_irqsave(&priv->irq_th_lock, flags);
- for (QueueID = 0; QueueID < MAX_TX_QUEUE; QueueID++) {
- if (QueueID == TXCMD_QUEUE)
- continue;
-
- if (QueueID == BEACON_QUEUE)
- continue;
-
- ring = &priv->tx_ring[QueueID];
-
- if (skb_queue_len(&ring->queue) == 0) {
- continue;
- } else {
- skb = __skb_peek(&ring->queue);
- tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- tcb_desc->stuck_count++;
- bCheckFwTxCnt = true;
- if (tcb_desc->stuck_count > 1)
- netdev_info(dev,
- "%s: QueueID=%d tcb_desc->stuck_count=%d\n",
- __func__, QueueID,
- tcb_desc->stuck_count);
- }
- }
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
-
- if (bCheckFwTxCnt) {
- if (rtl92e_is_tx_stuck(dev))
- return RESET_TYPE_SILENT;
- }
-
- return RESET_TYPE_NORESET;
-}
-
-static enum reset_type _rtl92e_rx_check_stuck(struct net_device *dev)
-{
- if (rtl92e_is_rx_stuck(dev))
- return RESET_TYPE_SILENT;
-
- return RESET_TYPE_NORESET;
-}
-
-static void _rtl92e_if_check_reset(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- enum reset_type TxResetType = RESET_TYPE_NORESET;
- enum reset_type RxResetType = RESET_TYPE_NORESET;
- enum rt_rf_power_state rfState;
-
- rfState = priv->rtllib->rf_power_state;
-
- if (rfState == rf_on)
- TxResetType = _rtl92e_tx_check_stuck(dev);
-
- if (rfState == rf_on &&
- (priv->rtllib->iw_mode == IW_MODE_INFRA) &&
- (priv->rtllib->link_state == MAC80211_LINKED))
- RxResetType = _rtl92e_rx_check_stuck(dev);
-
- if (TxResetType == RESET_TYPE_SILENT ||
- RxResetType == RESET_TYPE_SILENT) {
- netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n",
- __func__, TxResetType, RxResetType);
- }
-}
-
-static void _rtl92e_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum,
- u32 *TotalRxDataNum)
-{
- u16 slot_index;
- u8 i;
-
- *TotalRxBcnNum = 0;
- *TotalRxDataNum = 0;
-
- slot_index = (priv->rtllib->link_detect_info.slot_index++) %
- (priv->rtllib->link_detect_info.slot_num);
- priv->rtllib->link_detect_info.RxBcnNum[slot_index] =
- priv->rtllib->link_detect_info.num_recv_bcn_in_period;
- priv->rtllib->link_detect_info.RxDataNum[slot_index] =
- priv->rtllib->link_detect_info.num_recv_data_in_period;
- for (i = 0; i < priv->rtllib->link_detect_info.slot_num; i++) {
- *TotalRxBcnNum += priv->rtllib->link_detect_info.RxBcnNum[i];
- *TotalRxDataNum += priv->rtllib->link_detect_info.RxDataNum[i];
- }
-}
-
-static void _rtl92e_watchdog_wq_cb(void *data)
-{
- struct r8192_priv *priv = container_of_dwork_rsl(data,
- struct r8192_priv, watch_dog_wq);
- struct net_device *dev = priv->rtllib->dev;
- struct rtllib_device *ieee = priv->rtllib;
- static u8 check_reset_cnt;
- unsigned long flags;
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- (&priv->rtllib->pwr_save_ctrl);
- bool busy_traffic = false;
- bool bHigherBusyTraffic = false;
- bool bHigherBusyRxTraffic = false;
- bool bEnterPS = false;
-
- if (!priv->up || priv->hw_radio_off)
- return;
-
- if (priv->rtllib->link_state >= MAC80211_LINKED) {
- if (priv->rtllib->cnt_after_link < 2)
- priv->rtllib->cnt_after_link++;
- } else {
- priv->rtllib->cnt_after_link = 0;
- }
-
- rtl92e_dm_watchdog(dev);
-
- if (!rtllib_act_scanning(priv->rtllib, false)) {
- if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->link_state ==
- MAC80211_NOLINK) &&
- (ieee->rf_power_state == rf_on) && !ieee->is_set_key &&
- (!ieee->proto_stoppping) && !ieee->wx_set_enc) {
- if (ieee->pwr_save_ctrl.return_point == IPS_CALLBACK_NONE)
- rtl92e_ips_enter(dev);
- }
- }
- if ((ieee->link_state == MAC80211_LINKED) && (ieee->iw_mode == IW_MODE_INFRA)) {
- if (ieee->link_detect_info.num_rx_ok_in_period > 100 ||
- ieee->link_detect_info.num_tx_ok_in_period > 100)
- busy_traffic = true;
-
- if (ieee->link_detect_info.num_rx_ok_in_period > 4000 ||
- ieee->link_detect_info.num_tx_ok_in_period > 4000) {
- bHigherBusyTraffic = true;
- if (ieee->link_detect_info.num_rx_ok_in_period > 5000)
- bHigherBusyRxTraffic = true;
- else
- bHigherBusyRxTraffic = false;
- }
-
- if (((ieee->link_detect_info.num_rx_unicast_ok_in_period +
- ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
- (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2))
- bEnterPS = false;
- else
- bEnterPS = true;
-
- if (ieee->current_network.beacon_interval < 95)
- bEnterPS = false;
-
- if (bEnterPS)
- rtl92e_leisure_ps_enter(dev);
- else
- rtl92e_leisure_ps_leave(dev);
-
- } else {
- rtl92e_leisure_ps_leave(dev);
- }
-
- ieee->link_detect_info.num_rx_ok_in_period = 0;
- ieee->link_detect_info.num_tx_ok_in_period = 0;
- ieee->link_detect_info.num_rx_unicast_ok_in_period = 0;
- ieee->link_detect_info.busy_traffic = busy_traffic;
-
- ieee->link_detect_info.bHigherBusyTraffic = bHigherBusyTraffic;
- ieee->link_detect_info.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
-
- if (ieee->link_state == MAC80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) {
- u32 TotalRxBcnNum = 0;
- u32 TotalRxDataNum = 0;
-
- _rtl92e_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum);
-
- if ((TotalRxBcnNum + TotalRxDataNum) == 0)
- priv->check_roaming_cnt++;
- else
- priv->check_roaming_cnt = 0;
-
- if (priv->check_roaming_cnt > 0) {
- if (ieee->rf_power_state == rf_off)
- netdev_info(dev, "%s(): RF is off\n", __func__);
-
- netdev_info(dev,
- "===>%s(): AP is power off, chan:%d, connect another one\n",
- __func__, priv->chan);
-
- ieee->link_state = RTLLIB_ASSOCIATING;
-
- remove_peer_ts(priv->rtllib,
- priv->rtllib->current_network.bssid);
- ieee->is_roaming = true;
- ieee->is_set_key = false;
- ieee->link_change(dev);
- notify_wx_assoc_event(ieee);
-
- if (!(ieee->rtllib_ap_sec_type(ieee) &
- (SEC_ALG_CCMP | SEC_ALG_TKIP)))
- schedule_delayed_work(
- &ieee->associate_procedure_wq, 0);
-
- priv->check_roaming_cnt = 0;
- }
- ieee->link_detect_info.num_recv_bcn_in_period = 0;
- ieee->link_detect_info.num_recv_data_in_period = 0;
- }
-
- spin_lock_irqsave(&priv->tx_lock, flags);
- if ((check_reset_cnt++ >= 3) && (!ieee->is_roaming) &&
- (!priv->rf_change_in_progress) && (!psc->bSwRfProcessing)) {
- _rtl92e_if_check_reset(dev);
- check_reset_cnt = 3;
- }
- spin_unlock_irqrestore(&priv->tx_lock, flags);
-}
-
-static void _rtl92e_watchdog_timer_cb(struct timer_list *t)
-{
- struct r8192_priv *priv = from_timer(priv, t, watch_dog_timer);
-
- schedule_delayed_work(&priv->watch_dog_wq, 0);
- mod_timer(&priv->watch_dog_timer, jiffies +
- msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME));
-}
-
-/****************************************************************************
- * ---------------------------- NIC TX/RX STUFF---------------------------
- ****************************************************************************/
-void rtl92e_rx_enable(struct net_device *dev)
-{
- rtl92e_enable_rx(dev);
-}
-
-void rtl92e_tx_enable(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- rtl92e_enable_tx(dev);
-
- rtllib_reset_queue(priv->rtllib);
-}
-
-static void _rtl92e_free_rx_ring(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int i;
-
- for (i = 0; i < priv->rxringcount; i++) {
- struct sk_buff *skb = priv->rx_buf[i];
-
- if (!skb)
- continue;
-
- dma_unmap_single(&priv->pdev->dev,
- *((dma_addr_t *)skb->cb),
- priv->rxbuffersize, DMA_FROM_DEVICE);
- kfree_skb(skb);
- }
-
- dma_free_coherent(&priv->pdev->dev,
- sizeof(*priv->rx_ring) * priv->rxringcount,
- priv->rx_ring,
- priv->rx_ring_dma);
- priv->rx_ring = NULL;
-}
-
-static void _rtl92e_free_tx_ring(struct net_device *dev, unsigned int prio)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtl8192_tx_ring *ring = &priv->tx_ring[prio];
-
- while (skb_queue_len(&ring->queue)) {
- struct tx_desc *entry = &ring->desc[ring->idx];
- struct sk_buff *skb = __skb_dequeue(&ring->queue);
-
- dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr,
- skb->len, DMA_TO_DEVICE);
- kfree_skb(skb);
- ring->idx = (ring->idx + 1) % ring->entries;
- }
-
- dma_free_coherent(&priv->pdev->dev,
- sizeof(*ring->desc) * ring->entries, ring->desc,
- ring->dma);
- ring->desc = NULL;
-}
-
-static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
- int rate)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u8 queue_index = tcb_desc->queue_index;
-
- if ((priv->rtllib->rf_power_state == rf_off) || !priv->up) {
- kfree_skb(skb);
- return;
- }
-
- if (queue_index == TXCMD_QUEUE)
- netdev_warn(dev, "%s(): queue index == TXCMD_QUEUE\n",
- __func__);
-
- memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
- skb_push(skb, priv->rtllib->tx_headroom);
- ret = _rtl92e_tx(dev, skb);
-
- if (queue_index != MGNT_QUEUE) {
- priv->rtllib->stats.tx_bytes += (skb->len -
- priv->rtllib->tx_headroom);
- priv->rtllib->stats.tx_packets++;
- }
-
- if (ret != 0)
- kfree_skb(skb);
-}
-
-static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u8 queue_index = tcb_desc->queue_index;
-
- if (queue_index != TXCMD_QUEUE) {
- if ((priv->rtllib->rf_power_state == rf_off) ||
- !priv->up) {
- kfree_skb(skb);
- return 0;
- }
- }
-
- memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
- if (queue_index == TXCMD_QUEUE) {
- _rtl92e_tx_cmd(dev, skb);
- return 0;
- }
-
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_dis_rate_fallback = 1;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- tcb_desc->tx_enable_fw_calc_dur = 1;
- skb_push(skb, priv->rtllib->tx_headroom);
- ret = _rtl92e_tx(dev, skb);
- if (ret != 0)
- kfree_skb(skb);
- return ret;
-}
-
-static void _rtl92e_tx_isr(struct net_device *dev, int prio)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- struct rtl8192_tx_ring *ring = &priv->tx_ring[prio];
-
- while (skb_queue_len(&ring->queue)) {
- struct tx_desc *entry = &ring->desc[ring->idx];
- struct sk_buff *skb;
-
- if (prio != BEACON_QUEUE) {
- if (entry->OWN)
- return;
- ring->idx = (ring->idx + 1) % ring->entries;
- }
-
- skb = __skb_dequeue(&ring->queue);
- dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr,
- skb->len, DMA_TO_DEVICE);
-
- kfree_skb(skb);
- }
- if (prio != BEACON_QUEUE)
- tasklet_schedule(&priv->irq_tx_tasklet);
-}
-
-static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtl8192_tx_ring *ring;
- struct tx_desc_cmd *entry;
- unsigned int idx;
- struct cb_desc *tcb_desc;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_th_lock, flags);
- ring = &priv->tx_ring[TXCMD_QUEUE];
-
- idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
- entry = (struct tx_desc_cmd *)&ring->desc[idx];
-
- tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
-
- rtl92e_fill_tx_cmd_desc(dev, entry, tcb_desc, skb);
-
- __skb_queue_tail(&ring->queue, skb);
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
-}
-
-static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtl8192_tx_ring *ring;
- unsigned long flags;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- struct tx_desc *pdesc = NULL;
- struct ieee80211_hdr *header = NULL;
- u8 *pda_addr = NULL;
- int idx;
- u32 fwinfo_size = 0;
-
- priv->rtllib->awake_pkt_sent = true;
-
- fwinfo_size = sizeof(struct tx_fwinfo_8190pci);
-
- header = (struct ieee80211_hdr *)(((u8 *)skb->data) + fwinfo_size);
- pda_addr = header->addr1;
-
- if (!is_broadcast_ether_addr(pda_addr) && !is_multicast_ether_addr(pda_addr))
- priv->stats.txbytesunicast += skb->len - fwinfo_size;
-
- spin_lock_irqsave(&priv->irq_th_lock, flags);
- ring = &priv->tx_ring[tcb_desc->queue_index];
- if (tcb_desc->queue_index != BEACON_QUEUE)
- idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
- else
- idx = 0;
-
- pdesc = &ring->desc[idx];
- if ((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) {
- netdev_warn(dev,
- "No more TX desc@%d, ring->idx = %d, idx = %d, skblen = 0x%x queuelen=%d",
- tcb_desc->queue_index, ring->idx, idx, skb->len,
- skb_queue_len(&ring->queue));
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- return skb->len;
- }
- rtl92e_fill_tx_desc(dev, pdesc, tcb_desc, skb);
- __skb_queue_tail(&ring->queue, skb);
- pdesc->OWN = 1;
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- netif_trans_update(dev);
-
- rtl92e_writew(dev, TP_POLL, 0x01 << tcb_desc->queue_index);
- return 0;
-}
-
-static short _rtl92e_alloc_rx_ring(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rx_desc *entry = NULL;
- int i;
-
- priv->rx_ring = dma_alloc_coherent(&priv->pdev->dev,
- sizeof(*priv->rx_ring) * priv->rxringcount,
- &priv->rx_ring_dma,
- GFP_ATOMIC);
- if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
- netdev_warn(dev, "Cannot allocate RX ring\n");
- return -ENOMEM;
- }
-
- priv->rx_idx = 0;
-
- for (i = 0; i < priv->rxringcount; i++) {
- struct sk_buff *skb = dev_alloc_skb(priv->rxbuffersize);
- dma_addr_t *mapping;
-
- entry = &priv->rx_ring[i];
- if (!skb)
- return 0;
- skb->dev = dev;
- priv->rx_buf[i] = skb;
- mapping = (dma_addr_t *)skb->cb;
- *mapping = dma_map_single(&priv->pdev->dev,
- skb_tail_pointer(skb),
- priv->rxbuffersize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&priv->pdev->dev, *mapping)) {
- dev_kfree_skb_any(skb);
- return -1;
- }
- entry->BufferAddress = *mapping;
-
- entry->Length = priv->rxbuffersize;
- entry->OWN = 1;
- }
-
- if (entry)
- entry->EOR = 1;
- return 0;
-}
-
-static int _rtl92e_alloc_tx_ring(struct net_device *dev, unsigned int prio,
- unsigned int entries)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct tx_desc *ring;
- dma_addr_t dma;
- int i;
-
- ring = dma_alloc_coherent(&priv->pdev->dev, sizeof(*ring) * entries,
- &dma, GFP_ATOMIC);
- if (!ring || (unsigned long)ring & 0xFF) {
- netdev_warn(dev, "Cannot allocate TX ring (prio = %d)\n", prio);
- return -ENOMEM;
- }
-
- priv->tx_ring[prio].desc = ring;
- priv->tx_ring[prio].dma = dma;
- priv->tx_ring[prio].idx = 0;
- priv->tx_ring[prio].entries = entries;
- skb_queue_head_init(&priv->tx_ring[prio].queue);
-
- for (i = 0; i < entries; i++)
- ring[i].NextDescAddress =
- (u32)dma + ((i + 1) % entries) *
- sizeof(*ring);
-
- return 0;
-}
-
-static short _rtl92e_pci_initdescring(struct net_device *dev)
-{
- u32 ret;
- int i;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- ret = _rtl92e_alloc_rx_ring(dev);
- if (ret)
- return ret;
-
- for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) {
- ret = _rtl92e_alloc_tx_ring(dev, i, priv->txringcount);
- if (ret)
- goto err_free_rings;
- }
-
- return 0;
-
-err_free_rings:
- _rtl92e_free_rx_ring(dev);
- for (i = 0; i < MAX_TX_QUEUE_COUNT; i++)
- if (priv->tx_ring[i].desc)
- _rtl92e_free_tx_ring(dev, i);
- return 1;
-}
-
-void rtl92e_reset_desc_ring(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int i;
- unsigned long flags = 0;
-
- if (priv->rx_ring) {
- struct rx_desc *entry = NULL;
-
- for (i = 0; i < priv->rxringcount; i++) {
- entry = &priv->rx_ring[i];
- entry->OWN = 1;
- }
- priv->rx_idx = 0;
- }
-
- spin_lock_irqsave(&priv->irq_th_lock, flags);
- for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) {
- if (priv->tx_ring[i].desc) {
- struct rtl8192_tx_ring *ring = &priv->tx_ring[i];
-
- while (skb_queue_len(&ring->queue)) {
- struct tx_desc *entry = &ring->desc[ring->idx];
- struct sk_buff *skb =
- __skb_dequeue(&ring->queue);
-
- dma_unmap_single(&priv->pdev->dev,
- entry->TxBuffAddr, skb->len,
- DMA_TO_DEVICE);
- kfree_skb(skb);
- ring->idx = (ring->idx + 1) % ring->entries;
- }
- ring->idx = 0;
- }
- }
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
-}
-
-long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
-
- return signal_power;
-}
-
-void rtl92e_update_rx_statistics(struct r8192_priv *priv,
- struct rtllib_rx_stats *pprevious_stats)
-{
- int weighting = 0;
-
- if (priv->stats.recv_signal_power == 0)
- priv->stats.recv_signal_power =
- pprevious_stats->RecvSignalPower;
-
- if (pprevious_stats->RecvSignalPower > priv->stats.recv_signal_power)
- weighting = 5;
- else if (pprevious_stats->RecvSignalPower <
- priv->stats.recv_signal_power)
- weighting = (-5);
- priv->stats.recv_signal_power = (priv->stats.recv_signal_power * 5 +
- pprevious_stats->RecvSignalPower +
- weighting) / 6;
-}
-
-u8 rtl92e_rx_db_to_percent(s8 antpower)
-{
- if ((antpower <= -100) || (antpower >= 20))
- return 0;
- else if (antpower >= 0)
- return 100;
- else
- return 100 + antpower;
-
-} /* QueryRxPwrPercentage */
-
-u8 rtl92e_evm_db_to_percent(s8 value)
-{
- s8 ret_val = clamp(-value, 0, 33) * 3;
-
- if (ret_val == 99)
- ret_val = 100;
-
- return ret_val;
-}
-
-void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats,
- struct rtllib_rx_stats *ptarget_stats)
-{
- ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU;
- ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU;
-}
-
-static void _rtl92e_rx_normal(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct ieee80211_hdr *rtllib_hdr = NULL;
- bool unicast_packet = false;
- u32 skb_len = 0;
-
- struct rtllib_rx_stats stats = {
- .signal = 0,
- .noise = (u8)-98,
- .rate = 0,
- };
- unsigned int count = priv->rxringcount;
-
- while (count--) {
- struct rx_desc *pdesc = &priv->rx_ring
- [priv->rx_idx];
- struct sk_buff *skb = priv->rx_buf
- [priv->rx_idx];
- struct sk_buff *new_skb;
-
- if (pdesc->OWN)
- return;
- if (!rtl92e_get_rx_stats(dev, &stats, pdesc, skb))
- goto done;
- new_skb = dev_alloc_skb(priv->rxbuffersize);
- /* if allocation of new skb failed - drop current packet
- * and reuse skb
- */
- if (unlikely(!new_skb))
- goto done;
-
- dma_unmap_single(&priv->pdev->dev, *((dma_addr_t *)skb->cb),
- priv->rxbuffersize, DMA_FROM_DEVICE);
-
- skb_put(skb, pdesc->Length);
- skb_reserve(skb, stats.rx_drv_info_size +
- stats.rx_buf_shift);
- skb_trim(skb, skb->len - S_CRC_LEN);
- rtllib_hdr = (struct ieee80211_hdr *)skb->data;
- if (!is_multicast_ether_addr(rtllib_hdr->addr1)) {
- /* unicast packet */
- unicast_packet = true;
- }
- skb_len = skb->len;
-
- if (!rtllib_rx(priv->rtllib, skb, &stats)) {
- dev_kfree_skb_any(skb);
- } else {
- if (unicast_packet)
- priv->stats.rxbytesunicast += skb_len;
- }
-
- skb = new_skb;
- skb->dev = dev;
-
- priv->rx_buf[priv->rx_idx] = skb;
- *((dma_addr_t *)skb->cb) = dma_map_single(&priv->pdev->dev,
- skb_tail_pointer(skb),
- priv->rxbuffersize, DMA_FROM_DEVICE);
- if (dma_mapping_error(&priv->pdev->dev, *((dma_addr_t *)skb->cb))) {
- dev_kfree_skb_any(skb);
- return;
- }
-done:
- pdesc->BufferAddress = *((dma_addr_t *)skb->cb);
- pdesc->OWN = 1;
- pdesc->Length = priv->rxbuffersize;
- if (priv->rx_idx == priv->rxringcount - 1)
- pdesc->EOR = 1;
- priv->rx_idx = (priv->rx_idx + 1) %
- priv->rxringcount;
- }
-}
-
-static void _rtl92e_tx_resume(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- struct sk_buff *skb;
- int queue_index;
-
- for (queue_index = BK_QUEUE;
- queue_index < MAX_QUEUE_SIZE; queue_index++) {
- while ((!skb_queue_empty(&ieee->skb_waitq[queue_index])) &&
- (priv->rtllib->check_nic_enough_desc(dev, queue_index) > 0)) {
- skb = skb_dequeue(&ieee->skb_waitq[queue_index]);
- ieee->softmac_data_hard_start_xmit(skb, dev, 0);
- }
- }
-}
-
-static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t)
-{
- struct r8192_priv *priv = from_tasklet(priv, t, irq_tx_tasklet);
-
- _rtl92e_tx_resume(priv->rtllib->dev);
-}
-
-static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t)
-{
- struct r8192_priv *priv = from_tasklet(priv, t, irq_rx_tasklet);
-
- _rtl92e_rx_normal(priv->rtllib->dev);
-
- rtl92e_writel(priv->rtllib->dev, INTA_MASK,
- rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU);
-}
-
-/****************************************************************************
- * ---------------------------- NIC START/CLOSE STUFF---------------------------
- ****************************************************************************/
-static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv)
-{
- cancel_delayed_work_sync(&priv->watch_dog_wq);
- cancel_delayed_work_sync(&priv->update_beacon_wq);
- cancel_delayed_work(&priv->rtllib->hw_sleep_wq);
- cancel_work_sync(&priv->reset_wq);
- cancel_work_sync(&priv->qos_activate);
-}
-
-static int _rtl92e_up(struct net_device *dev)
-{
- if (_rtl92e_sta_up(dev) == -1)
- return -1;
- return 0;
-}
-
-static int _rtl92e_open(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
-
- mutex_lock(&priv->wx_mutex);
- ret = _rtl92e_try_up(dev);
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_try_up(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->up == 1)
- return -1;
- return _rtl92e_up(dev);
-}
-
-static int _rtl92e_close(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
-
- if ((rtllib_act_scanning(priv->rtllib, false)) &&
- !(priv->rtllib->softmac_features & IEEE_SOFTMAC_SCAN)) {
- rtllib_stop_scan(priv->rtllib);
- }
-
- mutex_lock(&priv->wx_mutex);
-
- ret = _rtl92e_down(dev, true);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_down(struct net_device *dev, bool shutdownrf)
-{
- if (_rtl92e_sta_down(dev, shutdownrf) == -1)
- return -1;
-
- return 0;
-}
-
-void rtl92e_commit(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->up == 0)
- return;
- rtllib_softmac_stop_protocol(priv->rtllib);
- rtl92e_irq_disable(dev);
- rtl92e_stop_adapter(dev, true);
- _rtl92e_up(dev);
-}
-
-static void _rtl92e_restart(void *data)
-{
- struct r8192_priv *priv = container_of(data, struct r8192_priv, reset_wq);
- struct net_device *dev = priv->rtllib->dev;
-
- mutex_lock(&priv->wx_mutex);
-
- rtl92e_commit(dev);
-
- mutex_unlock(&priv->wx_mutex);
-}
-
-static void _rtl92e_set_multicast(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- short promisc;
-
- promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
- priv->promisc = promisc;
-}
-
-static int _rtl92e_set_mac_adr(struct net_device *dev, void *mac)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct sockaddr *addr = mac;
-
- mutex_lock(&priv->wx_mutex);
-
- eth_hw_addr_set(dev, addr->sa_data);
-
- schedule_work(&priv->reset_wq);
- mutex_unlock(&priv->wx_mutex);
-
- return 0;
-}
-
-static irqreturn_t _rtl92e_irq(int irq, void *netdev)
-{
- struct net_device *dev = netdev;
- struct r8192_priv *priv = rtllib_priv(dev);
- unsigned long flags;
- u32 inta;
-
- if (priv->irq_enabled == 0)
- goto done;
-
- spin_lock_irqsave(&priv->irq_th_lock, flags);
-
- rtl92e_ack_irq(dev, &inta);
-
- if (!inta) {
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- goto done;
- }
-
- if (inta == 0xffff) {
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- goto done;
- }
-
- if (!netif_running(dev)) {
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- goto done;
- }
-
- if (inta & IMR_MGNTDOK) {
- _rtl92e_tx_isr(dev, MGNT_QUEUE);
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
- if (priv->rtllib->ack_tx_to_ieee) {
- if (_rtl92e_is_tx_queue_empty(dev)) {
- priv->rtllib->ack_tx_to_ieee = 0;
- rtllib_ps_tx_ack(priv->rtllib, 1);
- }
- }
- spin_lock_irqsave(&priv->irq_th_lock, flags);
- }
-
- if (inta & IMR_COMDOK)
- _rtl92e_tx_isr(dev, TXCMD_QUEUE);
-
- if (inta & IMR_HIGHDOK)
- _rtl92e_tx_isr(dev, HIGH_QUEUE);
-
- if (inta & IMR_ROK)
- tasklet_schedule(&priv->irq_rx_tasklet);
-
- if (inta & IMR_RDU) {
- rtl92e_writel(dev, INTA_MASK,
- rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU);
- tasklet_schedule(&priv->irq_rx_tasklet);
- }
-
- if (inta & IMR_RXFOVW)
- tasklet_schedule(&priv->irq_rx_tasklet);
-
- if (inta & IMR_BKDOK) {
- priv->rtllib->link_detect_info.num_tx_ok_in_period++;
- _rtl92e_tx_isr(dev, BK_QUEUE);
- }
-
- if (inta & IMR_BEDOK) {
- priv->rtllib->link_detect_info.num_tx_ok_in_period++;
- _rtl92e_tx_isr(dev, BE_QUEUE);
- }
-
- if (inta & IMR_VIDOK) {
- priv->rtllib->link_detect_info.num_tx_ok_in_period++;
- _rtl92e_tx_isr(dev, VI_QUEUE);
- }
-
- if (inta & IMR_VODOK) {
- priv->rtllib->link_detect_info.num_tx_ok_in_period++;
- _rtl92e_tx_isr(dev, VO_QUEUE);
- }
-
- spin_unlock_irqrestore(&priv->irq_th_lock, flags);
-
-done:
-
- return IRQ_HANDLED;
-}
-
-/****************************************************************************
- * ---------------------------- PCI_STUFF---------------------------
- ****************************************************************************/
-static const struct net_device_ops rtl8192_netdev_ops = {
- .ndo_open = _rtl92e_open,
- .ndo_stop = _rtl92e_close,
- .ndo_tx_timeout = _rtl92e_tx_timeout,
- .ndo_set_rx_mode = _rtl92e_set_multicast,
- .ndo_set_mac_address = _rtl92e_set_mac_adr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_start_xmit = rtllib_xmit,
-};
-
-static int _rtl92e_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- unsigned long ioaddr = 0;
- struct net_device *dev = NULL;
- struct r8192_priv *priv = NULL;
- unsigned long pmem_start, pmem_len, pmem_flags;
- int err = -ENOMEM;
-
- if (pci_enable_device(pdev)) {
- dev_err(&pdev->dev, "Failed to enable PCI device");
- return -EIO;
- }
-
- pci_set_master(pdev);
-
- if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
- if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) {
- dev_info(&pdev->dev,
- "Unable to obtain 32bit DMA for consistent allocations\n");
- goto err_pci_disable;
- }
- }
- dev = alloc_rtllib(sizeof(struct r8192_priv));
- if (!dev)
- goto err_pci_disable;
-
- err = -ENODEV;
-
- pci_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
- priv = rtllib_priv(dev);
- priv->rtllib = (struct rtllib_device *)netdev_priv_rsl(dev);
- priv->pdev = pdev;
- priv->rtllib->pdev = pdev;
- if ((pdev->subsystem_vendor == PCI_VENDOR_ID_DLINK) &&
- (pdev->subsystem_device == 0x3304))
- priv->rtllib->bSupportRemoteWakeUp = 1;
- else
- priv->rtllib->bSupportRemoteWakeUp = 0;
-
- pmem_start = pci_resource_start(pdev, 1);
- pmem_len = pci_resource_len(pdev, 1);
- pmem_flags = pci_resource_flags(pdev, 1);
-
- if (!(pmem_flags & IORESOURCE_MEM)) {
- netdev_err(dev, "region #1 not a MMIO resource, aborting");
- goto err_rel_rtllib;
- }
-
- dev_info(&pdev->dev, "Memory mapped space start: 0x%08lx\n",
- pmem_start);
- if (!request_mem_region(pmem_start, pmem_len, DRV_NAME)) {
- netdev_err(dev, "request_mem_region failed!");
- goto err_rel_rtllib;
- }
-
- ioaddr = (unsigned long)ioremap(pmem_start, pmem_len);
- if (ioaddr == (unsigned long)NULL) {
- netdev_err(dev, "ioremap failed!");
- goto err_rel_mem;
- }
-
- dev->mem_start = ioaddr;
- dev->mem_end = ioaddr + pci_resource_len(pdev, 0);
-
- if (!rtl92e_check_adapter(pdev, dev))
- goto err_unmap;
-
- dev->irq = pdev->irq;
- priv->irq = 0;
-
- dev->netdev_ops = &rtl8192_netdev_ops;
-
- dev->wireless_handlers = &r8192_wx_handlers_def;
- dev->ethtool_ops = &rtl819x_ethtool_ops;
-
- dev->type = ARPHRD_ETHER;
- dev->watchdog_timeo = HZ * 3;
-
- if (dev_alloc_name(dev, ifname) < 0)
- dev_alloc_name(dev, ifname);
-
- if (_rtl92e_init(dev) != 0) {
- netdev_warn(dev, "Initialization failed");
- goto err_free_irq;
- }
-
- netif_carrier_off(dev);
- netif_stop_queue(dev);
-
- if (register_netdev(dev))
- goto err_free_irq;
-
- if (priv->polling_timer_on == 0)
- rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer);
-
- return 0;
-
-err_free_irq:
- free_irq(dev->irq, dev);
- priv->irq = 0;
-err_unmap:
- iounmap((void __iomem *)ioaddr);
-err_rel_mem:
- release_mem_region(pmem_start, pmem_len);
-err_rel_rtllib:
- free_rtllib(dev);
-err_pci_disable:
- pci_disable_device(pdev);
- return err;
-}
-
-static void _rtl92e_pci_disconnect(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct r8192_priv *priv;
- u32 i;
-
- if (dev) {
- unregister_netdev(dev);
-
- priv = rtllib_priv(dev);
-
- del_timer_sync(&priv->gpio_polling_timer);
- cancel_delayed_work_sync(&priv->gpio_change_rf_wq);
- priv->polling_timer_on = 0;
- _rtl92e_down(dev, true);
- rtl92e_dm_deinit(dev);
- vfree(priv->fw_info);
- priv->fw_info = NULL;
- _rtl92e_free_rx_ring(dev);
- for (i = 0; i < MAX_TX_QUEUE_COUNT; i++)
- _rtl92e_free_tx_ring(dev, i);
-
- if (priv->irq) {
- dev_info(&pdev->dev, "Freeing irq %d\n", dev->irq);
- free_irq(dev->irq, dev);
- priv->irq = 0;
- }
-
- if (dev->mem_start != 0) {
- iounmap((void __iomem *)dev->mem_start);
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- }
-
- free_rtllib(dev);
- }
-
- pci_disable_device(pdev);
-}
-
-bool rtl92e_enable_nic(struct net_device *dev)
-{
- bool init_status = true;
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- (&priv->rtllib->pwr_save_ctrl);
-
- if (!priv->up) {
- netdev_warn(dev, "%s(): Driver is already down!\n", __func__);
- return false;
- }
-
- init_status = rtl92e_start_adapter(dev);
- if (!init_status) {
- netdev_warn(dev, "%s(): Initialization failed!\n", __func__);
- return false;
- }
- RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC);
-
- rtl92e_irq_enable(dev);
- return init_status;
-}
-
-module_pci_driver(rtl8192_pci_driver);
-
-void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t)
-{
- struct r8192_priv *priv = from_timer(priv, t, gpio_polling_timer);
-
- priv->polling_timer_on = 1;
-
- schedule_delayed_work(&priv->gpio_change_rf_wq, 0);
-
- mod_timer(&priv->gpio_polling_timer, jiffies +
- msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME));
-}
-
-/***************************************************************************
- * ------------------- module init / exit stubs ----------------
- ***************************************************************************/
-MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards");
-MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
-MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW);
-MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW);
-MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW);
-
-module_param(ifname, charp, 0644);
-module_param(hwwep, int, 0644);
-
-MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default");
-MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support(default use hw. set 0 to use software security)");
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
deleted file mode 100644
index 8297d7e59415..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL_CORE_H
-#define _RTL_CORE_H
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <linux/timer.h>
-#include <linux/proc_fs.h>
-#include <linux/if_arp.h>
-#include <linux/random.h>
-#include <linux/io.h>
-
-/* Need this defined before including local include files */
-#define DRV_NAME "rtl819xE"
-
-#include "../rtllib.h"
-
-#include "r8192E_firmware.h"
-#include "r8192E_hw.h"
-
-#include "r8190P_def.h"
-#include "r8192E_dev.h"
-
-#include "rtl_eeprom.h"
-#include "rtl_ps.h"
-#include "rtl_pci.h"
-#include "rtl_cam.h"
-
-#define DRV_COPYRIGHT \
- "Copyright(c) 2008 - 2010 Realsil Semiconductor Corporation"
-#define DRV_AUTHOR "<wlanfae@realtek.com>"
-#define DRV_VERSION "0014.0401.2010"
-
-#define TOTAL_CAM_ENTRY 32
-#define CAM_CONTENT_COUNT 8
-
-#define HAL_HW_PCI_REVISION_ID_8192PCIE 0x01
-#define HAL_HW_PCI_REVISION_ID_8192SE 0x10
-
-#define RTLLIB_WATCH_DOG_TIME 2000
-
-#define MAX_DEV_ADDR_SIZE 8 /*support till 64 bit bus width OS*/
-#define MAX_FIRMWARE_INFORMATION_SIZE 32
-#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE)
-#define ENCRYPTION_MAX_OVERHEAD 128
-#define MAX_FRAGMENT_COUNT 8
-#define MAX_TRANSMIT_BUFFER_SIZE \
- (1600 + (MAX_802_11_HEADER_LENGTH + ENCRYPTION_MAX_OVERHEAD) * \
- MAX_FRAGMENT_COUNT)
-
-#define CMDPACKET_FRAG_SIZE (4 * (MAX_TRANSMIT_BUFFER_SIZE / 4) - 8)
-
-#define DEFAULT_FRAG_THRESHOLD 2342U
-#define MIN_FRAG_THRESHOLD 256U
-#define DEFAULT_BEACONINTERVAL 0x64U
-
-#define DEFAULT_RETRY_RTS 7
-#define DEFAULT_RETRY_DATA 7
-
-#define PHY_RSSI_SLID_WIN_MAX 100
-
-#define TX_BB_GAIN_TABLE_LEN 37
-#define CCK_TX_BB_GAIN_TABLE_LEN 23
-
-#define CHANNEL_PLAN_LEN 10
-#define S_CRC_LEN 4
-
-#define NIC_SEND_HANG_THRESHOLD_NORMAL 4
-#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8
-
-#define MAX_TX_QUEUE 9
-
-#define MAX_RX_COUNT 64
-#define MAX_TX_QUEUE_COUNT 9
-
-extern int hwwep;
-
-enum nic_t {
- NIC_UNKNOWN = 0,
- NIC_8192E = 1,
- NIC_8190P = 2,
- NIC_8192SE = 4,
- NIC_8192CE = 5,
- NIC_8192CU = 6,
- NIC_8192DE = 7,
- NIC_8192DU = 8,
-};
-
-enum rt_eeprom_type {
- EEPROM_93C46,
- EEPROM_93C56,
-};
-
-enum dcmg_txcmd_op {
- TXCMD_TXRA_HISTORY_CTRL = 0xFF900000,
- TXCMD_RESET_TX_PKT_BUFF = 0xFF900001,
- TXCMD_RESET_RX_PKT_BUFF = 0xFF900002,
- TXCMD_SET_TX_DURATION = 0xFF900003,
- TXCMD_SET_RX_RSSI = 0xFF900004,
- TXCMD_SET_TX_PWR_TRACKING = 0xFF900005,
- TXCMD_XXXX_CTRL,
-};
-
-enum rt_customer_id {
- RT_CID_DEFAULT = 0,
- RT_CID_TOSHIBA = 9,
- RT_CID_819X_NETCORE = 10,
-};
-
-enum reset_type {
- RESET_TYPE_NORESET = 0x00,
- RESET_TYPE_SILENT = 0x02
-};
-
-struct rt_stats {
- unsigned long received_rate_histogram[4][32];
- unsigned long txbytesunicast;
- unsigned long rxbytesunicast;
- unsigned long txretrycount;
- u8 last_packet_rate;
- unsigned long slide_signal_strength[100];
- unsigned long slide_evm[100];
- unsigned long slide_rssi_total;
- unsigned long slide_evm_total;
- long signal_strength;
- long last_signal_strength_inpercent;
- long recv_signal_power;
- u8 rx_rssi_percentage[4];
- u8 rx_evm_percentage[2];
- u32 slide_beacon_pwdb[100];
- u32 slide_beacon_total;
- u32 CurrentShowTxate;
-};
-
-struct init_gain {
- u8 xaagccore1;
- u8 xbagccore1;
- u8 xcagccore1;
- u8 xdagccore1;
- u8 cca;
-
-};
-
-struct tx_ring {
- u32 *desc;
- u8 nStuckCount;
- struct tx_ring *next;
-} __packed;
-
-struct rtl8192_tx_ring {
- struct tx_desc *desc;
- dma_addr_t dma;
- unsigned int idx;
- unsigned int entries;
- struct sk_buff_head queue;
-};
-
-struct r8192_priv {
- struct pci_dev *pdev;
- struct pci_dev *bridge_pdev;
-
- bool bfirst_after_down;
- bool being_init_adapter;
-
- int irq;
- short irq_enabled;
-
- short up;
- short up_first_time;
- struct delayed_work update_beacon_wq;
- struct delayed_work watch_dog_wq;
- struct delayed_work txpower_tracking_wq;
- struct delayed_work rfpath_check_wq;
- struct delayed_work gpio_change_rf_wq;
- struct rtllib_device *rtllib;
-
- struct work_struct reset_wq;
-
- enum rt_customer_id customer_id;
-
- enum ht_channel_width current_chnl_bw;
- struct bb_reg_definition phy_reg_def[4];
- struct rate_adaptive rate_adaptive;
-
- struct rt_firmware *fw_info;
- enum rtl819x_loopback loopback_mode;
-
- struct timer_list watch_dog_timer;
- struct timer_list fsync_timer;
- struct timer_list gpio_polling_timer;
-
- spinlock_t irq_th_lock;
- spinlock_t tx_lock;
- spinlock_t rf_ps_lock;
- spinlock_t ps_lock;
-
- struct sk_buff_head skb_queue;
-
- struct tasklet_struct irq_rx_tasklet;
- struct tasklet_struct irq_tx_tasklet;
-
- struct mutex wx_mutex;
- struct mutex rf_mutex;
- struct mutex mutex;
-
- struct rt_stats stats;
- struct iw_statistics wstats;
-
- struct rx_desc *rx_ring;
- struct sk_buff *rx_buf[MAX_RX_COUNT];
- dma_addr_t rx_ring_dma;
- unsigned int rx_idx;
- int rxringcount;
- u16 rxbuffersize;
-
- u32 receive_config;
- u8 retry_data;
- u8 retry_rts;
- u16 rts;
-
- struct rtl8192_tx_ring tx_ring[MAX_TX_QUEUE_COUNT];
- int txringcount;
- atomic_t tx_pending[0x10];
-
- u16 short_retry_limit;
- u16 long_retry_limit;
-
- bool hw_radio_off;
- bool blinked_ingpio;
- u8 polling_timer_on;
-
- /**********************************************************/
- struct work_struct qos_activate;
-
- short promisc;
-
- short chan;
-
- u32 irq_mask[2];
-
- u8 rf_mode;
- enum nic_t card_8192;
- u8 card_8192_version;
-
- u8 ic_cut;
- char nick[IW_ESSID_MAX_SIZE + 1];
- u8 check_roaming_cnt;
-
- u32 silent_reset_rx_slot_index;
- u32 silent_reset_rx_stuck_event[MAX_SILENT_RESET_RX_SLOT_NUM];
-
- u16 basic_rate;
- u8 short_preamble;
- u8 dot11_current_preamble_mode;
- u8 slot_time;
-
- bool autoload_fail_flag;
-
- short epromtype;
- u16 eeprom_vid;
- u16 eeprom_did;
- u8 eeprom_customer_id;
-
- u8 eeprom_tx_pwr_level_cck[14];
- u8 eeprom_tx_pwr_level_ofdm24g[14];
- u16 eeprom_ant_pwr_diff;
- u8 eeprom_thermal_meter;
- u8 eeprom_crystal_cap;
-
- u8 eeprom_legacy_ht_tx_pwr_diff;
-
- u8 crystal_cap;
- u8 thermal_meter[2];
-
- u8 sw_chnl_in_progress;
- u8 sw_chnl_stage;
- u8 sw_chnl_step;
- u8 set_bw_mode_in_progress;
-
- u8 n_cur_40mhz_prime_sc;
-
- u32 rf_reg_0value[4];
- u8 num_total_rf_path;
- bool brfpath_rxenable[RF90_PATH_MAX];
-
- bool tx_pwr_data_read_from_eeprom;
-
- u8 hw_rf_off_action;
-
- bool rf_change_in_progress;
- bool set_rf_pwr_state_in_progress;
-
- u8 cck_pwr_enl;
- u16 tssi_13dBm;
- u32 pwr_track;
- u8 cck_present_attn_20m_def;
- u8 cck_present_attn_40m_def;
- s8 cck_present_attn_diff;
- s8 cck_present_attn;
- long undecorated_smoothed_pwdb;
-
- u32 mcs_tx_pwr_level_org_offset[6];
- u8 tx_pwr_level_cck[14];
- u8 tx_pwr_level_ofdm_24g[14];
- u8 legacy_ht_tx_pwr_diff;
- u8 antenna_tx_pwr_diff[3];
-
- bool dynamic_tx_high_pwr;
- bool dynamic_tx_low_pwr;
- bool last_dtp_flag_high;
- bool last_dtp_flag_low;
-
- u8 rfa_txpowertrackingindex;
- u8 rfa_txpowertrackingindex_real;
- u8 rfa_txpowertracking_default;
- bool btxpower_tracking;
- bool bcck_in_ch14;
-
- u8 txpower_count;
- bool tx_pwr_tracking_init;
-
- u8 ofdm_index[2];
- u8 cck_index;
-
- u8 rec_cck_20m_idx;
- u8 rec_cck_40m_idx;
-
- struct init_gain initgain_backup;
- u8 def_initial_gain[4];
- bool bis_any_nonbepkts;
- bool bcurrent_turbo_EDCA;
- bool bis_cur_rdlstate;
-
- u32 rate_record;
- u32 rate_count_diff_rec;
- u32 continue_diff_count;
- bool bswitch_fsync;
- u8 framesync;
-
- u16 tx_counter;
- u16 rx_ctr;
-};
-
-extern const struct ethtool_ops rtl819x_ethtool_ops;
-
-u8 rtl92e_readb(struct net_device *dev, int x);
-u32 rtl92e_readl(struct net_device *dev, int x);
-u16 rtl92e_readw(struct net_device *dev, int x);
-void rtl92e_writeb(struct net_device *dev, int x, u8 y);
-void rtl92e_writew(struct net_device *dev, int x, u16 y);
-void rtl92e_writel(struct net_device *dev, int x, u32 y);
-
-void force_pci_posting(struct net_device *dev);
-
-void rtl92e_rx_enable(struct net_device *dev);
-void rtl92e_tx_enable(struct net_device *dev);
-
-void rtl92e_hw_sleep_wq(void *data);
-void rtl92e_commit(struct net_device *dev);
-
-void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t);
-
-void rtl92e_hw_wakeup_wq(void *data);
-
-void rtl92e_reset_desc_ring(struct net_device *dev);
-void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode);
-void rtl92e_irq_enable(struct net_device *dev);
-void rtl92e_config_rate(struct net_device *dev, u16 *rate_config);
-void rtl92e_irq_disable(struct net_device *dev);
-
-long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index);
-void rtl92e_update_rx_statistics(struct r8192_priv *priv,
- struct rtllib_rx_stats *pprevious_stats);
-u8 rtl92e_evm_db_to_percent(s8 value);
-u8 rtl92e_rx_db_to_percent(s8 antpower);
-void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats,
- struct rtllib_rx_stats *ptarget_stats);
-bool rtl92e_enable_nic(struct net_device *dev);
-
-bool rtl92e_set_rf_state(struct net_device *dev,
- enum rt_rf_power_state state_to_set,
- RT_RF_CHANGE_SOURCE change_source);
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
deleted file mode 100644
index e9ca5a8768ad..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ /dev/null
@@ -1,1856 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "rtl_dm.h"
-#include "r8192E_hw.h"
-#include "r8192E_phy.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h"
-#include "r8192E_cmdpkt.h"
-
-/*---------------------------Define Local Constant---------------------------*/
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] = {
- 0x5e4322,
- 0x5e4322,
- 0x5ea44f,
- 0x5e4322,
- 0x604322,
- 0xa44f,
- 0x5e4322,
- 0x5e4332
-};
-
-static u32 edca_setting_DL_GMode[HT_IOT_PEER_MAX] = {
- 0x5e4322,
- 0x5e4322,
- 0x5e4322,
- 0x5e4322,
- 0x604322,
- 0xa44f,
- 0x5e4322,
- 0x5e4322
-};
-
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] = {
- 0x5e4322,
- 0xa44f,
- 0x5ea44f,
- 0x5e4322,
- 0x604322,
- 0x5e4322,
- 0x5e4322,
- 0x5e4332
-};
-
-const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN] = {
- 0x7f8001fe, /* 12 dB */
- 0x788001e2, /* 11 dB */
- 0x71c001c7,
- 0x6b8001ae,
- 0x65400195,
- 0x5fc0017f,
- 0x5a400169,
- 0x55400155,
- 0x50800142,
- 0x4c000130,
- 0x47c0011f,
- 0x43c0010f,
- 0x40000100,
- 0x3c8000f2,
- 0x390000e4,
- 0x35c000d7,
- 0x32c000cb,
- 0x300000c0,
- 0x2d4000b5,
- 0x2ac000ab,
- 0x288000a2,
- 0x26000098,
- 0x24000090,
- 0x22000088,
- 0x20000080,
- 0x1a00006c,
- 0x1c800072,
- 0x18000060,
- 0x19800066,
- 0x15800056,
- 0x26c0005b,
- 0x14400051,
- 0x24400051,
- 0x1300004c,
- 0x12000048,
- 0x11000044,
- 0x10000040, /* -24 dB */
-};
-
-const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8] = {
- {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
- {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04},
- {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
- {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03},
- {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
- {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03},
- {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
- {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03},
- {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
- {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02},
- {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
- {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02},
- {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
- {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02},
- {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
- {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02},
- {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},
- {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02},
- {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},
- {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
- {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
- {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01},
- {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}
-};
-
-const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8] = {
- {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
- {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00},
- {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
- {0x2d, 0x2d, 0x27, 0x17, 0x00, 0x00, 0x00, 0x00},
- {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
- {0x28, 0x28, 0x22, 0x14, 0x00, 0x00, 0x00, 0x00},
- {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
- {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00},
- {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
- {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00},
- {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
- {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00},
- {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
- {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00},
- {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
- {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00},
- {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},
- {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00},
- {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},
- {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
- {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
- {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00},
- {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}
-};
-
-/*---------------------------Define Local Constant---------------------------*/
-
-
-/*------------------------Define global variable-----------------------------*/
-struct dig_t dm_digtable;
-
-static struct drx_path_sel dm_rx_path_sel_table;
-/*------------------------Define global variable-----------------------------*/
-
-
-/*------------------------Define local variable------------------------------*/
-/*------------------------Define local variable------------------------------*/
-
-
-
-/*---------------------Define local function prototype-----------------------*/
-static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev);
-
-static void _rtl92e_dm_init_bandwidth_autoswitch(struct net_device *dev);
-static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev);
-
-static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev);
-
-static void _rtl92e_dm_dig_init(struct net_device *dev);
-static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev);
-static void _rtl92e_dm_initial_gain(struct net_device *dev);
-static void _rtl92e_dm_pd_th(struct net_device *dev);
-static void _rtl92e_dm_cs_ratio(struct net_device *dev);
-
-static void _rtl92e_dm_init_cts_to_self(struct net_device *dev);
-
-static void _rtl92e_dm_check_edca_turbo(struct net_device *dev);
-static void _rtl92e_dm_check_rx_path_selection(struct net_device *dev);
-static void _rtl92e_dm_init_rx_path_selection(struct net_device *dev);
-static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev);
-
-static void _rtl92e_dm_init_fsync(struct net_device *dev);
-static void _rtl92e_dm_deinit_fsync(struct net_device *dev);
-
-static void _rtl92e_dm_check_txrateandretrycount(struct net_device *dev);
-static void _rtl92e_dm_check_fsync(struct net_device *dev);
-static void _rtl92e_dm_check_rf_ctrl_gpio(void *data);
-static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t);
-
-/*---------------------Define local function prototype-----------------------*/
-
-static void _rtl92e_dm_init_dynamic_tx_power(struct net_device *dev);
-static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev);
-
-static void _rtl92e_dm_send_rssi_to_fw(struct net_device *dev);
-static void _rtl92e_dm_cts_to_self(struct net_device *dev);
-/*---------------------------Define function prototype------------------------*/
-
-void rtl92e_dm_init(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->undecorated_smoothed_pwdb = -1;
-
- _rtl92e_dm_init_dynamic_tx_power(dev);
-
- rtl92e_init_adaptive_rate(dev);
-
- _rtl92e_dm_dig_init(dev);
- rtl92e_dm_init_edca_turbo(dev);
- _rtl92e_dm_init_bandwidth_autoswitch(dev);
- _rtl92e_dm_init_fsync(dev);
- _rtl92e_dm_init_rx_path_selection(dev);
- _rtl92e_dm_init_cts_to_self(dev);
-
- INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, (void *)_rtl92e_dm_check_rf_ctrl_gpio);
-}
-
-void rtl92e_dm_deinit(struct net_device *dev)
-{
- _rtl92e_dm_deinit_fsync(dev);
-}
-
-void rtl92e_dm_watchdog(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->being_init_adapter)
- return;
-
- _rtl92e_dm_check_txrateandretrycount(dev);
- _rtl92e_dm_check_edca_turbo(dev);
-
- _rtl92e_dm_check_rate_adaptive(dev);
- _rtl92e_dm_dynamic_tx_power(dev);
- _rtl92e_dm_check_tx_power_tracking(dev);
-
- _rtl92e_dm_ctrl_initgain_byrssi(dev);
- _rtl92e_dm_bandwidth_autoswitch(dev);
-
- _rtl92e_dm_check_rx_path_selection(dev);
- _rtl92e_dm_check_fsync(dev);
-
- _rtl92e_dm_send_rssi_to_fw(dev);
- _rtl92e_dm_cts_to_self(dev);
-}
-
-void rtl92e_init_adaptive_rate(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rate_adaptive *pra = &priv->rate_adaptive;
-
- pra->ratr_state = DM_RATR_STA_MAX;
- pra->high2low_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH;
- pra->low2high_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M + 5;
- pra->low2high_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M + 5;
-
- pra->high_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH + 5;
- pra->low_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M;
- pra->low_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M;
-
- if (priv->customer_id == RT_CID_819X_NETCORE)
- pra->ping_rssi_enable = 1;
- else
- pra->ping_rssi_enable = 0;
- pra->ping_rssi_thresh_for_ra = 15;
-
- pra->upper_rssi_threshold_ratr = 0x000fc000;
- pra->middle_rssi_threshold_ratr = 0x000ff000;
- pra->low_rssi_threshold_ratr = 0x000ff001;
- pra->low_rssi_threshold_ratr_40M = 0x000ff005;
- pra->low_rssi_threshold_ratr_20M = 0x000ff001;
- pra->ping_rssi_ratr = 0x0000000d;
-}
-
-static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_hi_throughput *ht_info = priv->rtllib->ht_info;
- struct rate_adaptive *pra = &priv->rate_adaptive;
- u32 current_ratr, target_ratr = 0;
- u32 low_rssi_thresh_for_ra = 0, high_rssi_thresh_for_ra = 0;
- bool bshort_gi_enabled = false;
- static u8 ping_rssi_state;
-
- if (!priv->up)
- return;
-
- if (priv->rtllib->mode != WIRELESS_MODE_N_24G)
- return;
-
- if (priv->rtllib->link_state == MAC80211_LINKED) {
- bshort_gi_enabled = (ht_info->cur_tx_bw40mhz &&
- ht_info->cur_short_gi_40mhz) ||
- (!ht_info->cur_tx_bw40mhz &&
- ht_info->cur_short_gi_20mhz);
-
- pra->upper_rssi_threshold_ratr =
- (pra->upper_rssi_threshold_ratr & (~BIT(31))) |
- ((bshort_gi_enabled) ? BIT(31) : 0);
-
- pra->middle_rssi_threshold_ratr =
- (pra->middle_rssi_threshold_ratr & (~BIT(31))) |
- ((bshort_gi_enabled) ? BIT(31) : 0);
-
- if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) {
- pra->low_rssi_threshold_ratr =
- (pra->low_rssi_threshold_ratr_40M & (~BIT(31))) |
- ((bshort_gi_enabled) ? BIT(31) : 0);
- } else {
- pra->low_rssi_threshold_ratr =
- (pra->low_rssi_threshold_ratr_20M & (~BIT(31))) |
- ((bshort_gi_enabled) ? BIT(31) : 0);
- }
- pra->ping_rssi_ratr =
- (pra->ping_rssi_ratr & (~BIT(31))) |
- ((bshort_gi_enabled) ? BIT(31) : 0);
-
- if (pra->ratr_state == DM_RATR_STA_HIGH) {
- high_rssi_thresh_for_ra = pra->high2low_rssi_thresh_for_ra;
- low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
- (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M);
- } else if (pra->ratr_state == DM_RATR_STA_LOW) {
- high_rssi_thresh_for_ra = pra->high_rssi_thresh_for_ra;
- low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
- (pra->low2high_rssi_thresh_for_ra40M) : (pra->low2high_rssi_thresh_for_ra20M);
- } else {
- high_rssi_thresh_for_ra = pra->high_rssi_thresh_for_ra;
- low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
- (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M);
- }
-
- if (priv->undecorated_smoothed_pwdb >=
- (long)high_rssi_thresh_for_ra) {
- pra->ratr_state = DM_RATR_STA_HIGH;
- target_ratr = pra->upper_rssi_threshold_ratr;
- } else if (priv->undecorated_smoothed_pwdb >=
- (long)low_rssi_thresh_for_ra) {
- pra->ratr_state = DM_RATR_STA_MIDDLE;
- target_ratr = pra->middle_rssi_threshold_ratr;
- } else {
- pra->ratr_state = DM_RATR_STA_LOW;
- target_ratr = pra->low_rssi_threshold_ratr;
- }
-
- if (pra->ping_rssi_enable) {
- if (priv->undecorated_smoothed_pwdb <
- (long)(pra->ping_rssi_thresh_for_ra + 5)) {
- if ((priv->undecorated_smoothed_pwdb <
- (long)pra->ping_rssi_thresh_for_ra) ||
- ping_rssi_state) {
- pra->ratr_state = DM_RATR_STA_LOW;
- target_ratr = pra->ping_rssi_ratr;
- ping_rssi_state = 1;
- }
- } else {
- ping_rssi_state = 0;
- }
- }
-
- if (priv->rtllib->get_half_nmode_support_by_aps_handler(dev))
- target_ratr &= 0xf00fffff;
-
- current_ratr = rtl92e_readl(dev, RATR0);
- if (target_ratr != current_ratr) {
- u32 ratr_value;
-
- ratr_value = target_ratr;
- ratr_value &= ~(RATE_ALL_OFDM_2SS);
- rtl92e_writel(dev, RATR0, ratr_value);
- rtl92e_writeb(dev, UFWP, 1);
- }
-
- } else {
- pra->ratr_state = DM_RATR_STA_MAX;
- }
-}
-
-static void _rtl92e_dm_init_bandwidth_autoswitch(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH;
- priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW;
- priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = false;
- priv->rtllib->bandwidth_auto_switch.bautoswitch_enable = false;
-}
-
-static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20 ||
- !priv->rtllib->bandwidth_auto_switch.bautoswitch_enable)
- return;
- if (!priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz) {
- if (priv->undecorated_smoothed_pwdb <=
- priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
- priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = true;
- } else {
- if (priv->undecorated_smoothed_pwdb >=
- priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
- priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = false;
- }
-}
-
-static u32 OFDMSwingTable[OFDM_TABLE_LEN] = {
- 0x7f8001fe,
- 0x71c001c7,
- 0x65400195,
- 0x5a400169,
- 0x50800142,
- 0x47c0011f,
- 0x40000100,
- 0x390000e4,
- 0x32c000cb,
- 0x2d4000b5,
- 0x288000a2,
- 0x24000090,
- 0x20000080,
- 0x1c800072,
- 0x19800066,
- 0x26c0005b,
- 0x24400051,
- 0x12000048,
- 0x10000040
-};
-
-static u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_LEN][8] = {
- {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
- {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
- {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
- {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
- {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
- {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
- {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
- {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
- {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},
- {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},
- {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
- {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}
-};
-
-static u8 CCKSwingTable_Ch14[CCK_TABLE_LEN][8] = {
- {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
- {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
- {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
- {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
- {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
- {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
- {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
- {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
- {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},
- {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},
- {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
- {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}
-};
-
-#define Pw_Track_Flag 0x11d
-#define Tssi_Mea_Value 0x13c
-#define Tssi_Report_Value1 0x134
-#define Tssi_Report_Value2 0x13e
-#define FW_Busy_Flag 0x13f
-
-static void _rtl92e_dm_tx_update_tssi_weak_signal(struct net_device *dev)
-{
- struct r8192_priv *p = rtllib_priv(dev);
-
- if (p->rfa_txpowertrackingindex > 0) {
- p->rfa_txpowertrackingindex--;
- if (p->rfa_txpowertrackingindex_real > 4) {
- p->rfa_txpowertrackingindex_real--;
- rtl92e_set_bb_reg(dev,
- rOFDM0_XATxIQImbalance,
- bMaskDWord,
- dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]);
- }
- } else {
- rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
- bMaskDWord, dm_tx_bb_gain[4]);
- }
-}
-
-static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev)
-{
- struct r8192_priv *p = rtllib_priv(dev);
-
- if (p->rfa_txpowertrackingindex < (TX_BB_GAIN_TABLE_LEN - 1)) {
- p->rfa_txpowertrackingindex++;
- p->rfa_txpowertrackingindex_real++;
- rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
- bMaskDWord,
- dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]);
- } else {
- rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
- bMaskDWord,
- dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]);
- }
-}
-
-static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- bool viviflag = false;
- struct dcmd_txcmd tx_cmd;
- int i = 0, j = 0, k = 0;
- u8 tmp_report[5] = {0, 0, 0, 0, 0};
- u8 Pwr_Flag;
- u16 Avg_TSSI_Meas, tssi_13dBm, Avg_TSSI_Meas_from_driver = 0;
- u32 delta = 0;
-
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- priv->rtllib->bdynamic_txpower_enable = false;
-
- for (j = 0; j <= 30; j++) {
- tx_cmd.op = TXCMD_SET_TX_PWR_TRACKING;
- tx_cmd.length = 4;
- tx_cmd.value = priv->pwr_track >> 24;
- rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_NORMAL, (u8 *)&tx_cmd,
- sizeof(struct dcmd_txcmd));
- mdelay(1);
- for (i = 0; i <= 30; i++) {
- Pwr_Flag = rtl92e_readb(dev, Pw_Track_Flag);
-
- if (Pwr_Flag == 0) {
- mdelay(1);
-
- if (priv->rtllib->rf_power_state != rf_on) {
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- return;
- }
-
- continue;
- }
-
- Avg_TSSI_Meas = rtl92e_readw(dev, Tssi_Mea_Value);
-
- if (Avg_TSSI_Meas == 0) {
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- return;
- }
-
- for (k = 0; k < 5; k++) {
- if (k != 4)
- tmp_report[k] = rtl92e_readb(dev,
- Tssi_Report_Value1 + k);
- else
- tmp_report[k] = rtl92e_readb(dev,
- Tssi_Report_Value2);
-
- if (tmp_report[k] <= 20) {
- viviflag = true;
- break;
- }
- }
-
- if (viviflag) {
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- viviflag = false;
- for (k = 0; k < 5; k++)
- tmp_report[k] = 0;
- break;
- }
-
- for (k = 0; k < 5; k++)
- Avg_TSSI_Meas_from_driver += tmp_report[k];
-
- Avg_TSSI_Meas_from_driver *= 100 / 5;
- tssi_13dBm = priv->tssi_13dBm;
-
- if (Avg_TSSI_Meas_from_driver > tssi_13dBm)
- delta = Avg_TSSI_Meas_from_driver - tssi_13dBm;
- else
- delta = tssi_13dBm - Avg_TSSI_Meas_from_driver;
-
- if (delta <= E_FOR_TX_POWER_TRACK) {
- priv->rtllib->bdynamic_txpower_enable = true;
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- return;
- }
- if (Avg_TSSI_Meas_from_driver < tssi_13dBm - E_FOR_TX_POWER_TRACK)
- _rtl92e_dm_tx_update_tssi_weak_signal(dev);
- else
- _rtl92e_dm_tx_update_tssi_strong_signal(dev);
-
- priv->cck_present_attn_diff
- = priv->rfa_txpowertrackingindex_real - priv->rfa_txpowertracking_default;
-
- if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20)
- priv->cck_present_attn =
- priv->cck_present_attn_20m_def +
- priv->cck_present_attn_diff;
- else
- priv->cck_present_attn =
- priv->cck_present_attn_40m_def +
- priv->cck_present_attn_diff;
-
- if (priv->cck_present_attn > (CCK_TX_BB_GAIN_TABLE_LEN - 1))
- priv->cck_present_attn = CCK_TX_BB_GAIN_TABLE_LEN - 1;
- if (priv->cck_present_attn < 0)
- priv->cck_present_attn = 0;
-
- if (priv->cck_present_attn > -1 &&
- priv->cck_present_attn < CCK_TX_BB_GAIN_TABLE_LEN) {
- if (priv->rtllib->current_network.channel == 14 &&
- !priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = true;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = false;
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- } else {
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- }
- }
-
- if (priv->cck_present_attn_diff <= -12 ||
- priv->cck_present_attn_diff >= 24) {
- priv->rtllib->bdynamic_txpower_enable = true;
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- return;
- }
-
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
- Avg_TSSI_Meas_from_driver = 0;
- for (k = 0; k < 5; k++)
- tmp_report[k] = 0;
- break;
- }
- rtl92e_writeb(dev, FW_Busy_Flag, 0);
- }
- priv->rtllib->bdynamic_txpower_enable = true;
- rtl92e_writeb(dev, Pw_Track_Flag, 0);
-}
-
-static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev)
-{
-#define ThermalMeterVal 9
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 tmp_reg, tmp_cck;
- u8 tmp_ofdm_index, tmp_cck_index, tmp_cck_20m_index, tmp_cck_40m_index, tmpval;
- int i = 0, CCKSwingNeedUpdate = 0;
-
- if (!priv->tx_pwr_tracking_init) {
- tmp_reg = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance,
- bMaskDWord);
- for (i = 0; i < OFDM_TABLE_LEN; i++) {
- if (tmp_reg == OFDMSwingTable[i])
- priv->ofdm_index[0] = i;
- }
-
- tmp_cck = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, bMaskByte2);
- for (i = 0; i < CCK_TABLE_LEN; i++) {
- if (tmp_cck == (u32)CCKSwingTable_Ch1_Ch13[i][0]) {
- priv->cck_index = i;
- break;
- }
- }
- priv->tx_pwr_tracking_init = true;
- return;
- }
-
- tmp_reg = rtl92e_get_rf_reg(dev, RF90_PATH_A, 0x12, 0x078);
- if (tmp_reg < 3 || tmp_reg > 13)
- return;
- if (tmp_reg >= 12)
- tmp_reg = 12;
- priv->thermal_meter[0] = ThermalMeterVal;
- priv->thermal_meter[1] = ThermalMeterVal;
-
- if (priv->thermal_meter[0] >= (u8)tmp_reg) {
- tmp_ofdm_index = 6 + (priv->thermal_meter[0] - (u8)tmp_reg);
- tmp_cck_20m_index = tmp_ofdm_index;
- tmp_cck_40m_index = tmp_cck_20m_index - 6;
- if (tmp_ofdm_index >= OFDM_TABLE_LEN)
- tmp_ofdm_index = OFDM_TABLE_LEN - 1;
- if (tmp_cck_20m_index >= CCK_TABLE_LEN)
- tmp_cck_20m_index = CCK_TABLE_LEN - 1;
- if (tmp_cck_40m_index >= CCK_TABLE_LEN)
- tmp_cck_40m_index = CCK_TABLE_LEN - 1;
- } else {
- tmpval = (u8)tmp_reg - priv->thermal_meter[0];
- if (tmpval >= 6) {
- tmp_ofdm_index = 0;
- tmp_cck_20m_index = 0;
- } else {
- tmp_ofdm_index = 6 - tmpval;
- tmp_cck_20m_index = 6 - tmpval;
- }
- tmp_cck_40m_index = 0;
- }
- if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
- tmp_cck_index = tmp_cck_40m_index;
- else
- tmp_cck_index = tmp_cck_20m_index;
-
- priv->rec_cck_20m_idx = tmp_cck_20m_index;
- priv->rec_cck_40m_idx = tmp_cck_40m_index;
-
- if (priv->rtllib->current_network.channel == 14 &&
- !priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = true;
- CCKSwingNeedUpdate = 1;
- } else if (priv->rtllib->current_network.channel != 14 &&
- priv->bcck_in_ch14) {
- priv->bcck_in_ch14 = false;
- CCKSwingNeedUpdate = 1;
- }
-
- if (priv->cck_index != tmp_cck_index) {
- priv->cck_index = tmp_cck_index;
- CCKSwingNeedUpdate = 1;
- }
-
- if (CCKSwingNeedUpdate)
- rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- if (priv->ofdm_index[0] != tmp_ofdm_index) {
- priv->ofdm_index[0] = tmp_ofdm_index;
- rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord,
- OFDMSwingTable[priv->ofdm_index[0]]);
- }
- priv->txpower_count = 0;
-}
-
-void rtl92e_dm_txpower_tracking_wq(void *data)
-{
- struct r8192_priv *priv = container_of_dwork_rsl(data,
- struct r8192_priv, txpower_tracking_wq);
- struct net_device *dev = priv->rtllib->dev;
-
- if (priv->ic_cut >= IC_VersionCut_D)
- _rtl92e_dm_tx_power_tracking_callback_tssi(dev);
- else
- _rtl92e_dm_tx_power_tracking_cb_thermal(dev);
-}
-
-static void _rtl92e_dm_initialize_tx_power_tracking_tssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->btxpower_tracking = true;
- priv->txpower_count = 0;
- priv->tx_pwr_tracking_init = false;
-}
-
-static void _rtl92e_dm_init_tx_power_tracking_thermal(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->rtllib->FwRWRF)
- priv->btxpower_tracking = true;
- else
- priv->btxpower_tracking = false;
- priv->txpower_count = 0;
- priv->tx_pwr_tracking_init = false;
-}
-
-void rtl92e_dm_init_txpower_tracking(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->ic_cut >= IC_VersionCut_D)
- _rtl92e_dm_initialize_tx_power_tracking_tssi(dev);
- else
- _rtl92e_dm_init_tx_power_tracking_thermal(dev);
-}
-
-static void _rtl92e_dm_check_tx_power_tracking_tssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- static u32 tx_power_track_counter;
-
- if (rtl92e_readb(dev, 0x11e) == 1)
- return;
- if (!priv->btxpower_tracking)
- return;
- tx_power_track_counter++;
-
- if (tx_power_track_counter >= 180) {
- schedule_delayed_work(&priv->txpower_tracking_wq, 0);
- tx_power_track_counter = 0;
- }
-}
-
-static void _rtl92e_dm_check_tx_power_tracking_thermal(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- static u8 TM_Trigger;
- u8 TxPowerCheckCnt = 0;
-
- TxPowerCheckCnt = 2;
- if (!priv->btxpower_tracking)
- return;
-
- if (priv->txpower_count <= TxPowerCheckCnt) {
- priv->txpower_count++;
- return;
- }
-
- if (!TM_Trigger) {
- rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
- rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
- rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
- rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
- TM_Trigger = 1;
- return;
- }
- netdev_info(dev, "===============>Schedule TxPowerTrackingWorkItem\n");
- schedule_delayed_work(&priv->txpower_tracking_wq, 0);
- TM_Trigger = 0;
-}
-
-static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->ic_cut >= IC_VersionCut_D)
- _rtl92e_dm_check_tx_power_tracking_tssi(dev);
- else
- _rtl92e_dm_check_tx_power_tracking_thermal(dev);
-}
-
-static void _rtl92e_dm_cck_tx_power_adjust_tssi(struct net_device *dev,
- bool bInCH14)
-{
- u32 TempVal;
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 attenuation = priv->cck_present_attn;
-
- TempVal = 0;
- if (!bInCH14) {
- TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][0] +
- (dm_cck_tx_bb_gain[attenuation][1] << 8));
-
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = (u32)((dm_cck_tx_bb_gain[attenuation][2]) +
- (dm_cck_tx_bb_gain[attenuation][3] << 8) +
- (dm_cck_tx_bb_gain[attenuation][4] << 16) +
- (dm_cck_tx_bb_gain[attenuation][5] << 24));
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][6] +
- (dm_cck_tx_bb_gain[attenuation][7] << 8));
-
- rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
- } else {
- TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][0]) +
- (dm_cck_tx_bb_gain_ch14[attenuation][1] << 8));
-
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][2]) +
- (dm_cck_tx_bb_gain_ch14[attenuation][3] << 8) +
- (dm_cck_tx_bb_gain_ch14[attenuation][4] << 16) +
- (dm_cck_tx_bb_gain_ch14[attenuation][5] << 24));
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][6]) +
- (dm_cck_tx_bb_gain_ch14[attenuation][7] << 8));
-
- rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
- }
-}
-
-static void _rtl92e_dm_cck_tx_power_adjust_thermal_meter(struct net_device *dev,
- bool bInCH14)
-{
- u32 TempVal;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- TempVal = 0;
- if (!bInCH14) {
- TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][0] +
- (CCKSwingTable_Ch1_Ch13[priv->cck_index][1] << 8);
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][2] +
- (CCKSwingTable_Ch1_Ch13[priv->cck_index][3] << 8) +
- (CCKSwingTable_Ch1_Ch13[priv->cck_index][4] << 16) +
- (CCKSwingTable_Ch1_Ch13[priv->cck_index][5] << 24);
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][6] +
- (CCKSwingTable_Ch1_Ch13[priv->cck_index][7] << 8);
-
- rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
- } else {
- TempVal = CCKSwingTable_Ch14[priv->cck_index][0] +
- (CCKSwingTable_Ch14[priv->cck_index][1] << 8);
-
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = CCKSwingTable_Ch14[priv->cck_index][2] +
- (CCKSwingTable_Ch14[priv->cck_index][3] << 8) +
- (CCKSwingTable_Ch14[priv->cck_index][4] << 16) +
- (CCKSwingTable_Ch14[priv->cck_index][5] << 24);
- rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = CCKSwingTable_Ch14[priv->cck_index][6] +
- (CCKSwingTable_Ch14[priv->cck_index][7] << 8);
-
- rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
- }
-}
-
-void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->ic_cut >= IC_VersionCut_D)
- _rtl92e_dm_cck_tx_power_adjust_tssi(dev, binch14);
- else
- _rtl92e_dm_cck_tx_power_adjust_thermal_meter(dev, binch14);
-}
-
-static void _rtl92e_dm_dig_init(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- dm_digtable.cur_sta_connect_state = DIG_STA_DISCONNECT;
- dm_digtable.pre_sta_connect_state = DIG_STA_DISCONNECT;
-
- dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW;
- dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH;
-
- dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
- dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
-
- dm_digtable.rssi_val = 50;
- dm_digtable.backoff_val = DM_DIG_BACKOFF;
- dm_digtable.rx_gain_range_max = DM_DIG_MAX;
- if (priv->customer_id == RT_CID_819X_NETCORE)
- dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore;
- else
- dm_digtable.rx_gain_range_min = DM_DIG_MIN;
-}
-
-/*-----------------------------------------------------------------------------
- * Function: dm_CtrlInitGainBeforeConnectByRssiAndFalseAlarm()
- *
- * Overview: Driver monitor RSSI and False Alarm to change initial gain.
- Only change initial gain during link in progress.
- *
- * Input: IN PADAPTER pAdapter
- *
- * Output: NONE
- *
- * Return: NONE
- *
- * Revised History:
- * When Who Remark
- * 03/04/2009 hpfan Create Version 0.
- *
- ******************************************************************************/
-
-static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 i;
- static u8 fw_dig;
-
- if (fw_dig <= 3) {
- for (i = 0; i < 3; i++)
- rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8);
- fw_dig++;
- }
-
- if (priv->rtllib->link_state == MAC80211_LINKED)
- dm_digtable.cur_sta_connect_state = DIG_STA_CONNECT;
- else
- dm_digtable.cur_sta_connect_state = DIG_STA_DISCONNECT;
-
- dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb;
- _rtl92e_dm_initial_gain(dev);
- _rtl92e_dm_pd_th(dev);
- _rtl92e_dm_cs_ratio(dev);
- dm_digtable.pre_sta_connect_state = dm_digtable.cur_sta_connect_state;
-}
-
-static void _rtl92e_dm_initial_gain(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 initial_gain = 0;
- static u8 initialized, force_write;
-
- if (rtllib_act_scanning(priv->rtllib, true)) {
- force_write = 1;
- return;
- }
-
- if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) {
- if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) {
- long gain_range = dm_digtable.rssi_val + 10 -
- dm_digtable.backoff_val;
- gain_range = clamp_t(long, gain_range,
- dm_digtable.rx_gain_range_min,
- dm_digtable.rx_gain_range_max);
- dm_digtable.cur_ig_value = gain_range;
- } else {
- if (dm_digtable.cur_ig_value == 0)
- dm_digtable.cur_ig_value = priv->def_initial_gain[0];
- else
- dm_digtable.cur_ig_value = dm_digtable.pre_ig_value;
- }
- } else {
- dm_digtable.cur_ig_value = priv->def_initial_gain[0];
- dm_digtable.pre_ig_value = 0;
- }
-
- if (dm_digtable.pre_ig_value != rtl92e_readb(dev, rOFDM0_XAAGCCore1))
- force_write = 1;
-
- if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
- || !initialized || force_write) {
- initial_gain = dm_digtable.cur_ig_value;
- rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain);
- rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain);
- dm_digtable.pre_ig_value = dm_digtable.cur_ig_value;
- initialized = 1;
- force_write = 0;
- }
-}
-
-static void _rtl92e_dm_pd_th(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- static u8 initialized, force_write;
-
- if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) {
- if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) {
- if (dm_digtable.rssi_val >=
- dm_digtable.rssi_high_power_highthresh)
- dm_digtable.curpd_thstate =
- DIG_PD_AT_HIGH_POWER;
- else if (dm_digtable.rssi_val <=
- dm_digtable.rssi_low_thresh)
- dm_digtable.curpd_thstate =
- DIG_PD_AT_LOW_POWER;
- else if ((dm_digtable.rssi_val >=
- dm_digtable.rssi_high_thresh) &&
- (dm_digtable.rssi_val <
- dm_digtable.rssi_high_power_lowthresh))
- dm_digtable.curpd_thstate =
- DIG_PD_AT_NORMAL_POWER;
- else
- dm_digtable.curpd_thstate =
- dm_digtable.prepd_thstate;
- } else {
- dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
- }
- } else {
- dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
- }
-
- if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
- (initialized <= 3) || force_write) {
- if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
- if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
- rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x00);
- else
- rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42);
- } else if (dm_digtable.curpd_thstate ==
- DIG_PD_AT_NORMAL_POWER) {
- if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
- rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x20);
- else
- rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44);
- } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) {
- if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
- rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x10);
- else
- rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43);
- }
- dm_digtable.prepd_thstate = dm_digtable.curpd_thstate;
- if (initialized <= 3)
- initialized++;
- force_write = 0;
- }
-}
-
-static void _rtl92e_dm_cs_ratio(struct net_device *dev)
-{
- static u8 initialized, force_write;
-
- if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) {
- if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) {
- if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)
- dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
- else if (dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh)
- dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER;
- else
- dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state;
- } else {
- dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
- }
- } else {
- dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
- }
-
- if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
- !initialized || force_write) {
- if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER)
- rtl92e_writeb(dev, 0xa0a, 0x08);
- else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER)
- rtl92e_writeb(dev, 0xa0a, 0xcd);
- dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state;
- initialized = 1;
- force_write = 0;
- }
-}
-
-void rtl92e_dm_init_edca_turbo(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->bcurrent_turbo_EDCA = false;
- priv->rtllib->bis_any_nonbepkts = false;
- priv->bis_cur_rdlstate = false;
-}
-
-static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_hi_throughput *ht_info = priv->rtllib->ht_info;
-
- static unsigned long lastTxOkCnt;
- static unsigned long lastRxOkCnt;
- unsigned long curTxOkCnt = 0;
- unsigned long curRxOkCnt = 0;
-
- if (priv->rtllib->link_state != MAC80211_LINKED)
- goto dm_CheckEdcaTurbo_EXIT;
- if (priv->rtllib->ht_info->iot_action & HT_IOT_ACT_DISABLE_EDCA_TURBO)
- goto dm_CheckEdcaTurbo_EXIT;
-
- if (!priv->rtllib->bis_any_nonbepkts) {
- curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
- curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
- if (ht_info->iot_action & HT_IOT_ACT_EDCA_BIAS_ON_RX) {
- if (curTxOkCnt > 4 * curRxOkCnt) {
- if (priv->bis_cur_rdlstate ||
- !priv->bcurrent_turbo_EDCA) {
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_UL[ht_info->iot_peer]);
- priv->bis_cur_rdlstate = false;
- }
- } else {
- if (!priv->bis_cur_rdlstate ||
- !priv->bcurrent_turbo_EDCA) {
- if (priv->rtllib->mode == WIRELESS_MODE_G)
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL_GMode[ht_info->iot_peer]);
- else
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL[ht_info->iot_peer]);
- priv->bis_cur_rdlstate = true;
- }
- }
- priv->bcurrent_turbo_EDCA = true;
- } else {
- if (curRxOkCnt > 4 * curTxOkCnt) {
- if (!priv->bis_cur_rdlstate ||
- !priv->bcurrent_turbo_EDCA) {
- if (priv->rtllib->mode == WIRELESS_MODE_G)
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL_GMode[ht_info->iot_peer]);
- else
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL[ht_info->iot_peer]);
- priv->bis_cur_rdlstate = true;
- }
- } else {
- if (priv->bis_cur_rdlstate ||
- !priv->bcurrent_turbo_EDCA) {
- rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_UL[ht_info->iot_peer]);
- priv->bis_cur_rdlstate = false;
- }
- }
-
- priv->bcurrent_turbo_EDCA = true;
- }
- } else {
- if (priv->bcurrent_turbo_EDCA) {
- u8 tmp = AC0_BE;
-
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM,
- (u8 *)(&tmp));
- priv->bcurrent_turbo_EDCA = false;
- }
- }
-
-dm_CheckEdcaTurbo_EXIT:
- priv->rtllib->bis_any_nonbepkts = false;
- lastTxOkCnt = priv->stats.txbytesunicast;
- lastRxOkCnt = priv->stats.rxbytesunicast;
-}
-
-static void _rtl92e_dm_init_cts_to_self(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv((struct net_device *)dev);
-
- priv->rtllib->bCTSToSelfEnable = true;
-}
-
-static void _rtl92e_dm_cts_to_self(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv((struct net_device *)dev);
- struct rt_hi_throughput *ht_info = priv->rtllib->ht_info;
- static unsigned long lastTxOkCnt;
- static unsigned long lastRxOkCnt;
- unsigned long curTxOkCnt = 0;
- unsigned long curRxOkCnt = 0;
-
- if (!priv->rtllib->bCTSToSelfEnable) {
- ht_info->iot_action &= ~HT_IOT_ACT_FORCED_CTS2SELF;
- return;
- }
- if (ht_info->iot_peer == HT_IOT_PEER_BROADCOM) {
- curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
- curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
- if (curRxOkCnt > 4 * curTxOkCnt)
- ht_info->iot_action &= ~HT_IOT_ACT_FORCED_CTS2SELF;
- else
- ht_info->iot_action |= HT_IOT_ACT_FORCED_CTS2SELF;
-
- lastTxOkCnt = priv->stats.txbytesunicast;
- lastRxOkCnt = priv->stats.rxbytesunicast;
- }
-}
-
-static void _rtl92e_dm_check_rf_ctrl_gpio(void *data)
-{
- struct r8192_priv *priv = container_of_dwork_rsl(data,
- struct r8192_priv, gpio_change_rf_wq);
- struct net_device *dev = priv->rtllib->dev;
- u8 tmp1byte;
- enum rt_rf_power_state rf_power_state_to_set;
- bool bActuallySet = false;
-
- if ((priv->up_first_time == 1) || (priv->being_init_adapter))
- return;
-
- if (priv->bfirst_after_down)
- return;
-
- tmp1byte = rtl92e_readb(dev, GPI);
-
- rf_power_state_to_set = (tmp1byte & BIT(1)) ? rf_on : rf_off;
-
- if (priv->hw_radio_off && (rf_power_state_to_set == rf_on)) {
- netdev_info(dev, "gpiochangeRF - HW Radio ON\n");
- priv->hw_radio_off = false;
- bActuallySet = true;
- } else if (!priv->hw_radio_off && (rf_power_state_to_set == rf_off)) {
- netdev_info(dev, "gpiochangeRF - HW Radio OFF\n");
- priv->hw_radio_off = true;
- bActuallySet = true;
- }
-
- if (bActuallySet) {
- mdelay(1000);
- priv->hw_rf_off_action = 1;
- rtl92e_set_rf_state(dev, rf_power_state_to_set, RF_CHANGE_BY_HW);
- }
-}
-
-void rtl92e_dm_rf_pathcheck_wq(void *data)
-{
- struct r8192_priv *priv = container_of_dwork_rsl(data,
- struct r8192_priv,
- rfpath_check_wq);
- struct net_device *dev = priv->rtllib->dev;
- u8 rfpath, i;
-
- rfpath = rtl92e_readb(dev, 0xc04);
-
- for (i = 0; i < RF90_PATH_MAX; i++) {
- if (rfpath & (0x01 << i))
- priv->brfpath_rxenable[i] = true;
- else
- priv->brfpath_rxenable[i] = false;
- }
- if (!dm_rx_path_sel_table.enable)
- return;
-
- _rtl92e_dm_rx_path_sel_byrssi(dev);
-}
-
-static void _rtl92e_dm_init_rx_path_selection(struct net_device *dev)
-{
- u8 i;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- dm_rx_path_sel_table.enable = 1;
- dm_rx_path_sel_table.ss_th_low = RX_PATH_SEL_SS_TH_LOW;
- dm_rx_path_sel_table.diff_th = RX_PATH_SEL_DIFF_TH;
- if (priv->customer_id == RT_CID_819X_NETCORE)
- dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2;
- else
- dm_rx_path_sel_table.cck_method = CCK_Rx_Version_1;
- dm_rx_path_sel_table.disabled_rf = 0;
- for (i = 0; i < 4; i++) {
- dm_rx_path_sel_table.rf_rssi[i] = 50;
- dm_rx_path_sel_table.cck_pwdb_sta[i] = -64;
- dm_rx_path_sel_table.rf_enable_rssi_th[i] = 100;
- }
-}
-
-#define PWDB_IN_RANGE ((cur_cck_pwdb < tmp_cck_max_pwdb) && \
- (cur_cck_pwdb > tmp_cck_sec_pwdb))
-
-static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u8 i, max_rssi_index = 0, min_rssi_index = 0;
- u8 sec_rssi_index = 0, rf_num = 0;
- u8 tmp_max_rssi = 0, tmp_min_rssi = 0, tmp_sec_rssi = 0;
- u8 cck_default_Rx = 0x2;
- u8 cck_optional_Rx = 0x3;
- long tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0;
- u8 cck_rx_ver2_max_index = 0;
- u8 cck_rx_ver2_sec_index = 0;
- u8 cur_rf_rssi;
- long cur_cck_pwdb;
- static u8 disabled_rf_cnt, cck_Rx_Path_initialized;
- u8 update_cck_rx_path;
-
- if (!cck_Rx_Path_initialized) {
- dm_rx_path_sel_table.cck_rx_path = (rtl92e_readb(dev, 0xa07) & 0xf);
- cck_Rx_Path_initialized = 1;
- }
-
- dm_rx_path_sel_table.disabled_rf = 0xf;
- dm_rx_path_sel_table.disabled_rf &= ~(rtl92e_readb(dev, 0xc04));
-
- if (priv->rtllib->mode == WIRELESS_MODE_B)
- dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2;
-
- for (i = 0; i < RF90_PATH_MAX; i++) {
- dm_rx_path_sel_table.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
-
- if (!priv->brfpath_rxenable[i])
- continue;
-
- rf_num++;
- cur_rf_rssi = dm_rx_path_sel_table.rf_rssi[i];
-
- if (rf_num == 1) {
- max_rssi_index = min_rssi_index = sec_rssi_index = i;
- tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi;
- } else if (rf_num == 2) {
- if (cur_rf_rssi >= tmp_max_rssi) {
- tmp_max_rssi = cur_rf_rssi;
- max_rssi_index = i;
- } else {
- tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi;
- sec_rssi_index = min_rssi_index = i;
- }
- } else {
- if (cur_rf_rssi > tmp_max_rssi) {
- tmp_sec_rssi = tmp_max_rssi;
- sec_rssi_index = max_rssi_index;
- tmp_max_rssi = cur_rf_rssi;
- max_rssi_index = i;
- } else if (cur_rf_rssi == tmp_max_rssi) {
- tmp_sec_rssi = cur_rf_rssi;
- sec_rssi_index = i;
- } else if ((cur_rf_rssi < tmp_max_rssi) &&
- (cur_rf_rssi > tmp_sec_rssi)) {
- tmp_sec_rssi = cur_rf_rssi;
- sec_rssi_index = i;
- } else if (cur_rf_rssi == tmp_sec_rssi) {
- if (tmp_sec_rssi == tmp_min_rssi) {
- tmp_sec_rssi = cur_rf_rssi;
- sec_rssi_index = i;
- }
- } else if ((cur_rf_rssi < tmp_sec_rssi) &&
- (cur_rf_rssi > tmp_min_rssi)) {
- ;
- } else if (cur_rf_rssi == tmp_min_rssi) {
- if (tmp_sec_rssi == tmp_min_rssi) {
- tmp_min_rssi = cur_rf_rssi;
- min_rssi_index = i;
- }
- } else if (cur_rf_rssi < tmp_min_rssi) {
- tmp_min_rssi = cur_rf_rssi;
- min_rssi_index = i;
- }
- }
- }
-
- rf_num = 0;
- if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) {
- for (i = 0; i < RF90_PATH_MAX; i++) {
- if (!priv->brfpath_rxenable[i])
- continue;
-
- rf_num++;
- cur_cck_pwdb = dm_rx_path_sel_table.cck_pwdb_sta[i];
-
- if (rf_num == 1) {
- cck_rx_ver2_max_index = i;
- cck_rx_ver2_sec_index = i;
- tmp_cck_max_pwdb = cur_cck_pwdb;
- tmp_cck_min_pwdb = cur_cck_pwdb;
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- } else if (rf_num == 2) {
- if (cur_cck_pwdb >= tmp_cck_max_pwdb) {
- tmp_cck_max_pwdb = cur_cck_pwdb;
- cck_rx_ver2_max_index = i;
- } else {
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- tmp_cck_min_pwdb = cur_cck_pwdb;
- cck_rx_ver2_sec_index = i;
- }
- } else {
- if (cur_cck_pwdb > tmp_cck_max_pwdb) {
- tmp_cck_sec_pwdb = tmp_cck_max_pwdb;
- cck_rx_ver2_sec_index = cck_rx_ver2_max_index;
- tmp_cck_max_pwdb = cur_cck_pwdb;
- cck_rx_ver2_max_index = i;
- } else if (cur_cck_pwdb == tmp_cck_max_pwdb) {
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- cck_rx_ver2_sec_index = i;
- } else if (PWDB_IN_RANGE) {
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- cck_rx_ver2_sec_index = i;
- } else if (cur_cck_pwdb == tmp_cck_sec_pwdb) {
- if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- cck_rx_ver2_sec_index = i;
- }
- } else if ((cur_cck_pwdb < tmp_cck_sec_pwdb) &&
- (cur_cck_pwdb > tmp_cck_min_pwdb)) {
- ;
- } else if (cur_cck_pwdb == tmp_cck_min_pwdb) {
- if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
- tmp_cck_min_pwdb = cur_cck_pwdb;
- } else if (cur_cck_pwdb < tmp_cck_min_pwdb) {
- tmp_cck_min_pwdb = cur_cck_pwdb;
- }
- }
- }
- }
-
- update_cck_rx_path = 0;
- if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) {
- cck_default_Rx = cck_rx_ver2_max_index;
- cck_optional_Rx = cck_rx_ver2_sec_index;
- if (tmp_cck_max_pwdb != -64)
- update_cck_rx_path = 1;
- }
-
- if (tmp_min_rssi < dm_rx_path_sel_table.ss_th_low && disabled_rf_cnt < 2) {
- if ((tmp_max_rssi - tmp_min_rssi) >=
- dm_rx_path_sel_table.diff_th) {
- dm_rx_path_sel_table.rf_enable_rssi_th[min_rssi_index] =
- tmp_max_rssi + 5;
- rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable,
- 0x1 << min_rssi_index, 0x0);
- rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable,
- 0x1 << min_rssi_index, 0x0);
- disabled_rf_cnt++;
- }
- if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_1) {
- cck_default_Rx = max_rssi_index;
- cck_optional_Rx = sec_rssi_index;
- if (tmp_max_rssi)
- update_cck_rx_path = 1;
- }
- }
-
- if (update_cck_rx_path) {
- dm_rx_path_sel_table.cck_rx_path = (cck_default_Rx << 2) |
- (cck_optional_Rx);
- rtl92e_set_bb_reg(dev, rCCK0_AFESetting, 0x0f000000,
- dm_rx_path_sel_table.cck_rx_path);
- }
-
- if (dm_rx_path_sel_table.disabled_rf) {
- for (i = 0; i < 4; i++) {
- if ((dm_rx_path_sel_table.disabled_rf >> i) & 0x1) {
- if (tmp_max_rssi >=
- dm_rx_path_sel_table.rf_enable_rssi_th[i]) {
- rtl92e_set_bb_reg(dev,
- rOFDM0_TRxPathEnable,
- 0x1 << i, 0x1);
- rtl92e_set_bb_reg(dev,
- rOFDM1_TRxPathEnable,
- 0x1 << i, 0x1);
- dm_rx_path_sel_table.rf_enable_rssi_th[i] = 100;
- disabled_rf_cnt--;
- }
- }
- }
- }
-}
-
-static void _rtl92e_dm_check_rx_path_selection(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- schedule_delayed_work(&priv->rfpath_check_wq, 0);
-}
-
-static void _rtl92e_dm_init_fsync(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->rtllib->fsync_time_interval = 500;
- priv->rtllib->fsync_rate_bitmap = 0x0f000800;
- priv->rtllib->fsync_rssi_threshold = 30;
- priv->rtllib->bfsync_enable = false;
- priv->rtllib->fsync_multiple_timeinterval = 3;
- priv->rtllib->fsync_firstdiff_ratethreshold = 100;
- priv->rtllib->fsync_seconddiff_ratethreshold = 200;
- priv->rtllib->fsync_state = DEFAULT_FSYNC;
-
- timer_setup(&priv->fsync_timer, _rtl92e_dm_fsync_timer_callback, 0);
-}
-
-static void _rtl92e_dm_deinit_fsync(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- del_timer_sync(&priv->fsync_timer);
-}
-
-static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t)
-{
- struct r8192_priv *priv = from_timer(priv, t, fsync_timer);
- struct net_device *dev = priv->rtllib->dev;
- u32 rate_index, rate_count = 0, rate_count_diff = 0;
- bool bSwitchFromCountDiff = false;
- bool bDoubleTimeInterval = false;
-
- if (priv->rtllib->link_state == MAC80211_LINKED &&
- priv->rtllib->bfsync_enable &&
- (priv->rtllib->ht_info->iot_action & HT_IOT_ACT_CDD_FSYNC)) {
- u32 rate_bitmap;
-
- for (rate_index = 0; rate_index <= 27; rate_index++) {
- rate_bitmap = 1 << rate_index;
- if (priv->rtllib->fsync_rate_bitmap & rate_bitmap)
- rate_count +=
- priv->stats.received_rate_histogram[1]
- [rate_index];
- }
-
- if (rate_count < priv->rate_record)
- rate_count_diff = 0xffffffff - rate_count +
- priv->rate_record;
- else
- rate_count_diff = rate_count - priv->rate_record;
- if (rate_count_diff < priv->rate_count_diff_rec) {
- u32 DiffNum = priv->rate_count_diff_rec -
- rate_count_diff;
- if (DiffNum >=
- priv->rtllib->fsync_seconddiff_ratethreshold)
- priv->continue_diff_count++;
- else
- priv->continue_diff_count = 0;
-
- if (priv->continue_diff_count >= 2) {
- bSwitchFromCountDiff = true;
- priv->continue_diff_count = 0;
- }
- } else {
- priv->continue_diff_count = 0;
- }
-
- if (rate_count_diff <=
- priv->rtllib->fsync_firstdiff_ratethreshold) {
- bSwitchFromCountDiff = true;
- priv->continue_diff_count = 0;
- }
- priv->rate_record = rate_count;
- priv->rate_count_diff_rec = rate_count_diff;
- if (priv->undecorated_smoothed_pwdb >
- priv->rtllib->fsync_rssi_threshold &&
- bSwitchFromCountDiff) {
- bDoubleTimeInterval = true;
- priv->bswitch_fsync = !priv->bswitch_fsync;
- if (priv->bswitch_fsync) {
- rtl92e_writeb(dev, 0xC36, 0x1c);
- rtl92e_writeb(dev, 0xC3e, 0x90);
- } else {
- rtl92e_writeb(dev, 0xC36, 0x5c);
- rtl92e_writeb(dev, 0xC3e, 0x96);
- }
- } else if (priv->undecorated_smoothed_pwdb <=
- priv->rtllib->fsync_rssi_threshold) {
- if (priv->bswitch_fsync) {
- priv->bswitch_fsync = false;
- rtl92e_writeb(dev, 0xC36, 0x5c);
- rtl92e_writeb(dev, 0xC3e, 0x96);
- }
- }
- if (bDoubleTimeInterval) {
- if (timer_pending(&priv->fsync_timer))
- del_timer_sync(&priv->fsync_timer);
- priv->fsync_timer.expires = jiffies +
- msecs_to_jiffies(priv->rtllib->fsync_time_interval *
- priv->rtllib->fsync_multiple_timeinterval);
- add_timer(&priv->fsync_timer);
- } else {
- if (timer_pending(&priv->fsync_timer))
- del_timer_sync(&priv->fsync_timer);
- priv->fsync_timer.expires = jiffies +
- msecs_to_jiffies(priv->rtllib->fsync_time_interval);
- add_timer(&priv->fsync_timer);
- }
- } else {
- if (priv->bswitch_fsync) {
- priv->bswitch_fsync = false;
- rtl92e_writeb(dev, 0xC36, 0x5c);
- rtl92e_writeb(dev, 0xC3e, 0x96);
- }
- priv->continue_diff_count = 0;
- rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
- }
-}
-
-static void _rtl92e_dm_start_hw_fsync(struct net_device *dev)
-{
- u8 rf_timing = 0x77;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cf);
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING,
- (u8 *)(&rf_timing));
- rtl92e_writeb(dev, 0xc3b, 0x41);
-}
-
-static void _rtl92e_dm_end_hw_fsync(struct net_device *dev)
-{
- u8 rf_timing = 0xaa;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
- priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING, (u8 *)
- (&rf_timing));
- rtl92e_writeb(dev, 0xc3b, 0x49);
-}
-
-static void _rtl92e_dm_end_sw_fsync(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- del_timer_sync(&(priv->fsync_timer));
-
- if (priv->bswitch_fsync) {
- priv->bswitch_fsync = false;
-
- rtl92e_writeb(dev, 0xC36, 0x5c);
-
- rtl92e_writeb(dev, 0xC3e, 0x96);
- }
-
- priv->continue_diff_count = 0;
- rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
-}
-
-static void _rtl92e_dm_start_sw_fsync(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 rate_index;
- u32 rate_bitmap;
-
- priv->rate_record = 0;
- priv->continue_diff_count = 0;
- priv->rate_count_diff_rec = 0;
- priv->bswitch_fsync = false;
-
- if (priv->rtllib->mode == WIRELESS_MODE_N_24G) {
- priv->rtllib->fsync_firstdiff_ratethreshold = 600;
- priv->rtllib->fsync_seconddiff_ratethreshold = 0xffff;
- } else {
- priv->rtllib->fsync_firstdiff_ratethreshold = 200;
- priv->rtllib->fsync_seconddiff_ratethreshold = 200;
- }
- for (rate_index = 0; rate_index <= 27; rate_index++) {
- rate_bitmap = 1 << rate_index;
- if (priv->rtllib->fsync_rate_bitmap & rate_bitmap)
- priv->rate_record +=
- priv->stats.received_rate_histogram[1]
- [rate_index];
- }
- if (timer_pending(&priv->fsync_timer))
- del_timer_sync(&priv->fsync_timer);
- priv->fsync_timer.expires = jiffies +
- msecs_to_jiffies(priv->rtllib->fsync_time_interval);
- add_timer(&priv->fsync_timer);
-
- rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cd);
-}
-
-static void _rtl92e_dm_check_fsync(struct net_device *dev)
-{
-#define RegC38_Default 0
-#define RegC38_NonFsync_Other_AP 1
-#define RegC38_Fsync_AP_BCM 2
- struct r8192_priv *priv = rtllib_priv(dev);
- static u8 reg_c38_State = RegC38_Default;
-
- if (priv->rtllib->link_state == MAC80211_LINKED &&
- priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) {
- if (priv->rtllib->bfsync_enable == 0) {
- switch (priv->rtllib->fsync_state) {
- case DEFAULT_FSYNC:
- _rtl92e_dm_start_hw_fsync(dev);
- priv->rtllib->fsync_state = HW_FSYNC;
- break;
- case SW_FSYNC:
- _rtl92e_dm_end_sw_fsync(dev);
- _rtl92e_dm_start_hw_fsync(dev);
- priv->rtllib->fsync_state = HW_FSYNC;
- break;
- default:
- break;
- }
- } else {
- switch (priv->rtllib->fsync_state) {
- case DEFAULT_FSYNC:
- _rtl92e_dm_start_sw_fsync(dev);
- priv->rtllib->fsync_state = SW_FSYNC;
- break;
- case HW_FSYNC:
- _rtl92e_dm_end_hw_fsync(dev);
- _rtl92e_dm_start_sw_fsync(dev);
- priv->rtllib->fsync_state = SW_FSYNC;
- break;
- default:
- break;
- }
- }
- if (reg_c38_State != RegC38_Fsync_AP_BCM) {
- rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95);
-
- reg_c38_State = RegC38_Fsync_AP_BCM;
- }
- } else {
- switch (priv->rtllib->fsync_state) {
- case HW_FSYNC:
- _rtl92e_dm_end_hw_fsync(dev);
- priv->rtllib->fsync_state = DEFAULT_FSYNC;
- break;
- case SW_FSYNC:
- _rtl92e_dm_end_sw_fsync(dev);
- priv->rtllib->fsync_state = DEFAULT_FSYNC;
- break;
- default:
- break;
- }
-
- if (priv->rtllib->link_state == MAC80211_LINKED) {
- if (priv->undecorated_smoothed_pwdb <=
- REG_C38_TH) {
- if (reg_c38_State !=
- RegC38_NonFsync_Other_AP) {
- rtl92e_writeb(dev,
- rOFDM0_RxDetector3,
- 0x90);
-
- reg_c38_State =
- RegC38_NonFsync_Other_AP;
- }
- } else if (priv->undecorated_smoothed_pwdb >=
- (REG_C38_TH + 5)) {
- if (reg_c38_State) {
- rtl92e_writeb(dev,
- rOFDM0_RxDetector3,
- priv->framesync);
- reg_c38_State = RegC38_Default;
- }
- }
- } else {
- if (reg_c38_State) {
- rtl92e_writeb(dev, rOFDM0_RxDetector3,
- priv->framesync);
- reg_c38_State = RegC38_Default;
- }
- }
- }
-}
-
-/*---------------------------Define function prototype------------------------*/
-static void _rtl92e_dm_init_dynamic_tx_power(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->rtllib->bdynamic_txpower_enable = true;
- priv->last_dtp_flag_high = false;
- priv->last_dtp_flag_low = false;
- priv->dynamic_tx_high_pwr = false;
- priv->dynamic_tx_low_pwr = false;
-}
-
-static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- unsigned int txhipower_threshold = 0;
- unsigned int txlowpower_threshold = 0;
-
- if (!priv->rtllib->bdynamic_txpower_enable) {
- priv->dynamic_tx_high_pwr = false;
- priv->dynamic_tx_low_pwr = false;
- return;
- }
- if ((priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_ATHEROS) &&
- (priv->rtllib->mode == WIRELESS_MODE_G)) {
- txhipower_threshold = TX_POWER_ATHEROAP_THRESH_HIGH;
- txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW;
- } else {
- txhipower_threshold = TX_POWER_NEAR_FIELD_THRESH_HIGH;
- txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW;
- }
-
- if (priv->rtllib->link_state == MAC80211_LINKED) {
- if (priv->undecorated_smoothed_pwdb >= txhipower_threshold) {
- priv->dynamic_tx_high_pwr = true;
- priv->dynamic_tx_low_pwr = false;
- } else {
- if (priv->undecorated_smoothed_pwdb <
- txlowpower_threshold && priv->dynamic_tx_high_pwr)
- priv->dynamic_tx_high_pwr = false;
- if (priv->undecorated_smoothed_pwdb < 35)
- priv->dynamic_tx_low_pwr = true;
- else if (priv->undecorated_smoothed_pwdb >= 40)
- priv->dynamic_tx_low_pwr = false;
- }
- } else {
- priv->dynamic_tx_high_pwr = false;
- priv->dynamic_tx_low_pwr = false;
- }
-
- if ((priv->dynamic_tx_high_pwr != priv->last_dtp_flag_high) ||
- (priv->dynamic_tx_low_pwr != priv->last_dtp_flag_low)) {
- rtl92e_set_tx_power(dev, priv->rtllib->current_network.channel);
- }
- priv->last_dtp_flag_high = priv->dynamic_tx_high_pwr;
- priv->last_dtp_flag_low = priv->dynamic_tx_low_pwr;
-}
-
-static void _rtl92e_dm_check_txrateandretrycount(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- ieee->softmac_stats.CurrentShowTxate = rtl92e_readb(dev, CURRENT_TX_RATE_REG);
- ieee->softmac_stats.last_packet_rate = rtl92e_readb(dev, INITIAL_TX_RATE_REG);
- ieee->softmac_stats.txretrycount = rtl92e_readl(dev, TX_RETRY_COUNT_REG);
-}
-
-static void _rtl92e_dm_send_rssi_to_fw(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- rtl92e_writeb(dev, DRIVER_RSSI, priv->undecorated_smoothed_pwdb);
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h
deleted file mode 100644
index 55641f17412b..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef __R8192UDM_H__
-#define __R8192UDM_H__
-
-/*--------------------------Define Parameters-------------------------------*/
-#define OFDM_TABLE_LEN 19
-#define CCK_TABLE_LEN 12
-
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_DIG_HIGH_PWR_THRESH_HIGH 75
-#define DM_DIG_HIGH_PWR_THRESH_LOW 70
-
-#define BW_AUTO_SWITCH_HIGH_LOW 25
-#define BW_AUTO_SWITCH_LOW_HIGH 30
-
-#define DM_DIG_BACKOFF 12
-#define DM_DIG_MAX 0x36
-#define DM_DIG_MIN 0x1c
-#define DM_DIG_MIN_Netcore 0x12
-
-#define RX_PATH_SEL_SS_TH_LOW 30
-#define RX_PATH_SEL_DIFF_TH 18
-
-#define RATE_ADAPTIVE_TH_HIGH 50
-#define RATE_ADAPTIVE_TH_LOW_20M 30
-#define RATE_ADAPTIVE_TH_LOW_40M 10
-#define VERY_LOW_RSSI 15
-
-#define E_FOR_TX_POWER_TRACK 300
-#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68
-#define TX_POWER_NEAR_FIELD_THRESH_LOW 62
-#define TX_POWER_ATHEROAP_THRESH_HIGH 78
-#define TX_POWER_ATHEROAP_THRESH_LOW 72
-
-#define CURRENT_TX_RATE_REG 0x1e0
-#define INITIAL_TX_RATE_REG 0x1e1
-#define TX_RETRY_COUNT_REG 0x1ac
-#define REG_C38_TH 20
-
-/*--------------------------Define Parameters-------------------------------*/
-
-/*------------------------------Define structure----------------------------*/
-struct dig_t {
- long rssi_low_thresh;
- long rssi_high_thresh;
-
- long rssi_high_power_lowthresh;
- long rssi_high_power_highthresh;
-
- u8 cur_sta_connect_state;
- u8 pre_sta_connect_state;
-
- u8 curpd_thstate;
- u8 prepd_thstate;
- u8 curcs_ratio_state;
- u8 precs_ratio_state;
-
- u32 pre_ig_value;
- u32 cur_ig_value;
-
- u8 backoff_val;
- u8 rx_gain_range_max;
- u8 rx_gain_range_min;
-
- long rssi_val;
-};
-
-enum dm_ratr_sta {
- DM_RATR_STA_HIGH = 0,
- DM_RATR_STA_MIDDLE = 1,
- DM_RATR_STA_LOW = 2,
- DM_RATR_STA_MAX
-};
-
-enum dm_dig_connect {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
-};
-
-enum dm_dig_pd_th {
- DIG_PD_AT_LOW_POWER = 0,
- DIG_PD_AT_NORMAL_POWER = 1,
- DIG_PD_AT_HIGH_POWER = 2,
- DIG_PD_MAX
-};
-
-enum dm_dig_cs_ratio {
- DIG_CS_RATIO_LOWER = 0,
- DIG_CS_RATIO_HIGHER = 1,
- DIG_CS_MAX
-};
-
-struct drx_path_sel {
- u8 enable;
- u8 cck_method;
- u8 cck_rx_path;
-
- u8 ss_th_low;
- u8 diff_th;
- u8 disabled_rf;
- u8 reserved;
-
- u8 rf_rssi[4];
- u8 rf_enable_rssi_th[4];
- long cck_pwdb_sta[4];
-};
-
-enum dm_cck_rx_path_method {
- CCK_Rx_Version_1 = 0,
- CCK_Rx_Version_2 = 1,
- CCK_Rx_Version_MAX
-};
-
-struct dcmd_txcmd {
- u32 op;
- u32 length;
- u32 value;
-};
-
-/*------------------------------Define structure----------------------------*/
-
-/*------------------------Export global variable----------------------------*/
-extern struct dig_t dm_digtable;
-
-/* Pre-calculated gain tables */
-extern const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN];
-extern const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8];
-extern const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8];
-
-/*------------------------Export global variable----------------------------*/
-
-/*--------------------------Exported Function prototype---------------------*/
-/*--------------------------Exported Function prototype---------------------*/
-
-void rtl92e_dm_init(struct net_device *dev);
-void rtl92e_dm_deinit(struct net_device *dev);
-
-void rtl92e_dm_watchdog(struct net_device *dev);
-
-void rtl92e_init_adaptive_rate(struct net_device *dev);
-void rtl92e_dm_txpower_tracking_wq(void *data);
-
-void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14);
-
-void rtl92e_dm_init_edca_turbo(struct net_device *dev);
-void rtl92e_dm_rf_pathcheck_wq(void *data);
-void rtl92e_dm_init_txpower_tracking(struct net_device *dev);
-#endif /*__R8192UDM_H__ */
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
deleted file mode 100644
index db57c655c695..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
+++ /dev/null
@@ -1,84 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "rtl_eeprom.h"
-
-static void _rtl92e_gpio_write_bit(struct net_device *dev, int no, bool val)
-{
- u8 reg = rtl92e_readb(dev, EPROM_CMD);
-
- if (val)
- reg |= 1 << no;
- else
- reg &= ~(1 << no);
-
- rtl92e_writeb(dev, EPROM_CMD, reg);
- udelay(EPROM_DELAY);
-}
-
-static bool _rtl92e_gpio_get_bit(struct net_device *dev, int no)
-{
- u8 reg = rtl92e_readb(dev, EPROM_CMD);
-
- return (reg >> no) & 0x1;
-}
-
-static void _rtl92e_eeprom_ck_cycle(struct net_device *dev)
-{
- _rtl92e_gpio_write_bit(dev, EPROM_CK_BIT, 1);
- _rtl92e_gpio_write_bit(dev, EPROM_CK_BIT, 0);
-}
-
-static u16 _rtl92e_eeprom_xfer(struct net_device *dev, u16 data, int tx_len)
-{
- u16 ret = 0;
- int rx_len = 16;
-
- _rtl92e_gpio_write_bit(dev, EPROM_CS_BIT, 1);
- _rtl92e_eeprom_ck_cycle(dev);
-
- while (tx_len--) {
- _rtl92e_gpio_write_bit(dev, EPROM_W_BIT,
- (data >> tx_len) & 0x1);
- _rtl92e_eeprom_ck_cycle(dev);
- }
-
- _rtl92e_gpio_write_bit(dev, EPROM_W_BIT, 0);
-
- while (rx_len--) {
- _rtl92e_eeprom_ck_cycle(dev);
- ret |= _rtl92e_gpio_get_bit(dev, EPROM_R_BIT) << rx_len;
- }
-
- _rtl92e_gpio_write_bit(dev, EPROM_CS_BIT, 0);
- _rtl92e_eeprom_ck_cycle(dev);
-
- return ret;
-}
-
-u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 ret = 0;
-
- rtl92e_writeb(dev, EPROM_CMD,
- (EPROM_CMD_PROGRAM << EPROM_CMD_OPERATING_MODE_SHIFT));
- udelay(EPROM_DELAY);
-
- /* EEPROM is configured as x16 */
- if (priv->epromtype == EEPROM_93C56)
- ret = _rtl92e_eeprom_xfer(dev, (addr & 0xFF) | (0x6 << 8), 11);
- else
- ret = _rtl92e_eeprom_xfer(dev, (addr & 0x3F) | (0x6 << 6), 9);
-
- rtl92e_writeb(dev, EPROM_CMD,
- (EPROM_CMD_NORMAL << EPROM_CMD_OPERATING_MODE_SHIFT));
- return ret;
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
deleted file mode 100644
index 66f1979bb1d5..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#define EPROM_DELAY 10
-
-u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
deleted file mode 100644
index fab8932e67da..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-
-#include "rtl_core.h"
-
-static void _rtl92e_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
- strscpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info));
-}
-
-static u32 _rtl92e_ethtool_get_link(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return ((priv->rtllib->link_state == MAC80211_LINKED) ||
- (priv->rtllib->link_state == MAC80211_LINKED_SCANNING));
-}
-
-const struct ethtool_ops rtl819x_ethtool_ops = {
- .get_drvinfo = _rtl92e_ethtool_get_drvinfo,
- .get_link = _rtl92e_ethtool_get_link,
-};
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
deleted file mode 100644
index 1aa73561581b..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_pci.h"
-#include "rtl_core.h"
-
-static void _rtl92e_parse_pci_configuration(struct pci_dev *pdev,
- struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- u8 tmp;
- u16 link_ctrl_reg;
-
- pcie_capability_read_word(priv->pdev, PCI_EXP_LNKCTL, &link_ctrl_reg);
-
- pci_read_config_byte(pdev, 0x98, &tmp);
- tmp |= BIT(4);
- pci_write_config_byte(pdev, 0x98, tmp);
-
- tmp = 0x17;
- pci_write_config_byte(pdev, 0x70f, tmp);
-}
-
-bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- u16 device_id;
- u8 revision_id;
- u16 irq_line;
-
- device_id = pdev->device;
- revision_id = pdev->revision;
- pci_read_config_word(pdev, 0x3C, &irq_line);
-
- priv->card_8192 = NIC_8192E;
-
- if (device_id == 0x8192) {
- switch (revision_id) {
- case HAL_HW_PCI_REVISION_ID_8192PCIE:
- dev_info(&pdev->dev,
- "Adapter(8192 PCI-E) is found - DeviceID=%x\n",
- device_id);
- priv->card_8192 = NIC_8192E;
- break;
- case HAL_HW_PCI_REVISION_ID_8192SE:
- dev_info(&pdev->dev,
- "Adapter(8192SE) is found - DeviceID=%x\n",
- device_id);
- priv->card_8192 = NIC_8192SE;
- break;
- default:
- dev_info(&pdev->dev,
- "UNKNOWN nic type(%4x:%4x)\n",
- pdev->vendor, pdev->device);
- priv->card_8192 = NIC_UNKNOWN;
- return false;
- }
- }
-
- if (priv->card_8192 != NIC_8192E) {
- dev_info(&pdev->dev,
- "Detect info(%x) and hardware info(%x) not match!\n",
- NIC_8192E, priv->card_8192);
- dev_info(&pdev->dev,
- "Please select proper driver before install!!!!\n");
- return false;
- }
-
- _rtl92e_parse_pci_configuration(pdev, dev);
-
- return true;
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
deleted file mode 100644
index 3e39c4835ac8..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL_PCI_H
-#define _RTL_PCI_H
-
-#include <linux/types.h>
-#include <linux/pci.h>
-
-struct net_device;
-
-bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
deleted file mode 100644
index d124b5eee0cc..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_core.h"
-#include "r8192E_hw.h"
-#include "r8190P_rtl8256.h"
-#include "rtl_pm.h"
-
-int rtl92e_suspend(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 ulRegRead;
-
- netdev_info(dev, "============> r8192E suspend call.\n");
- del_timer_sync(&priv->gpio_polling_timer);
- cancel_delayed_work_sync(&priv->gpio_change_rf_wq);
- priv->polling_timer_on = 0;
-
- if (!netif_running(dev)) {
- netdev_info(dev,
- "RTL819XE:UI is open out of suspend function\n");
- goto out_pci_suspend;
- }
-
- if (dev->netdev_ops->ndo_stop)
- dev->netdev_ops->ndo_stop(dev);
- netif_device_detach(dev);
-
- if (!priv->rtllib->bSupportRemoteWakeUp) {
- rtl92e_set_rf_state(dev, rf_off, RF_CHANGE_BY_INIT);
- ulRegRead = rtl92e_readl(dev, CPU_GEN);
- ulRegRead |= CPU_GEN_SYSTEM_RESET;
- rtl92e_writel(dev, CPU_GEN, ulRegRead);
- } else {
- rtl92e_writel(dev, WFCRC0, 0xffffffff);
- rtl92e_writel(dev, WFCRC1, 0xffffffff);
- rtl92e_writel(dev, WFCRC2, 0xffffffff);
- rtl92e_writeb(dev, PMR, 0x5);
- rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa);
- }
-out_pci_suspend:
- netdev_info(dev, "WOL is %s\n", priv->rtllib->bSupportRemoteWakeUp ?
- "Supported" : "Not supported");
- device_set_wakeup_enable(dev_d, priv->rtllib->bSupportRemoteWakeUp);
-
- mdelay(20);
-
- return 0;
-}
-
-int rtl92e_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct r8192_priv *priv = rtllib_priv(dev);
- u32 val;
-
- netdev_info(dev, "================>r8192E resume call.\n");
-
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- device_wakeup_disable(dev_d);
-
- if (priv->polling_timer_on == 0)
- rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer);
-
- if (!netif_running(dev)) {
- netdev_info(dev,
- "RTL819XE:UI is open out of resume function\n");
- goto out;
- }
-
- netif_device_attach(dev);
- if (dev->netdev_ops->ndo_open)
- dev->netdev_ops->ndo_open(dev);
-
- if (!priv->rtllib->bSupportRemoteWakeUp)
- rtl92e_set_rf_state(dev, rf_on, RF_CHANGE_BY_INIT);
-
-out:
- return 0;
-}
-
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
deleted file mode 100644
index fd8611495975..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef R8192E_PM_H
-#define R8192E_PM_H
-
-#include <linux/types.h>
-#include <linux/pci.h>
-
-int rtl92e_suspend(struct device *dev_d);
-int rtl92e_resume(struct device *dev_d);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
deleted file mode 100644
index 7b6247acf6f4..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
+++ /dev/null
@@ -1,230 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtl_ps.h"
-#include "rtl_core.h"
-#include "r8192E_phy.h"
-#include "r8192E_phyreg.h"
-#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */
-#include "r8192E_cmdpkt.h"
-#include <linux/jiffies.h>
-
-static void _rtl92e_hw_sleep(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- unsigned long flags = 0;
-
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- if (priv->rf_change_in_progress) {
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- rtl92e_set_rf_state(dev, rf_sleep, RF_CHANGE_BY_PS);
-}
-
-void rtl92e_hw_sleep_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device, hw_sleep_wq);
- struct net_device *dev = ieee->dev;
-
- _rtl92e_hw_sleep(dev);
-}
-
-void rtl92e_hw_wakeup(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- unsigned long flags = 0;
-
- spin_lock_irqsave(&priv->rf_ps_lock, flags);
- if (priv->rf_change_in_progress) {
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- schedule_delayed_work(&priv->rtllib->hw_wakeup_wq,
- msecs_to_jiffies(10));
- return;
- }
- spin_unlock_irqrestore(&priv->rf_ps_lock, flags);
- rtl92e_set_rf_state(dev, rf_on, RF_CHANGE_BY_PS);
-}
-
-void rtl92e_hw_wakeup_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device, hw_wakeup_wq);
- struct net_device *dev = ieee->dev;
-
- rtl92e_hw_wakeup(dev);
-}
-
-#define MIN_SLEEP_TIME 50
-#define MAX_SLEEP_TIME 10000
-void rtl92e_enter_sleep(struct net_device *dev, u64 time)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- u32 tmp;
- unsigned long flags;
- unsigned long timeout;
-
- spin_lock_irqsave(&priv->ps_lock, flags);
-
- time -= msecs_to_jiffies(8 + 16 + 7);
-
- timeout = jiffies + msecs_to_jiffies(MIN_SLEEP_TIME);
- if (time_before((unsigned long)time, timeout)) {
- spin_unlock_irqrestore(&priv->ps_lock, flags);
- netdev_info(dev, "too short to sleep::%lld < %ld\n",
- time - jiffies, msecs_to_jiffies(MIN_SLEEP_TIME));
- return;
- }
- timeout = jiffies + msecs_to_jiffies(MAX_SLEEP_TIME);
- if (time_after((unsigned long)time, timeout)) {
- netdev_info(dev, "========>too long to sleep:%lld > %ld\n",
- time - jiffies, msecs_to_jiffies(MAX_SLEEP_TIME));
- spin_unlock_irqrestore(&priv->ps_lock, flags);
- return;
- }
- tmp = time - jiffies;
- schedule_delayed_work(&priv->rtllib->hw_wakeup_wq, tmp);
- schedule_delayed_work(&priv->rtllib->hw_sleep_wq, 0);
- spin_unlock_irqrestore(&priv->ps_lock, flags);
-}
-
-static void _rtl92e_ps_update_rf_state(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- &priv->rtllib->pwr_save_ctrl;
-
- psc->bSwRfProcessing = true;
- rtl92e_set_rf_state(dev, psc->eInactivePowerState, RF_CHANGE_BY_IPS);
-
- psc->bSwRfProcessing = false;
-}
-
-void rtl92e_ips_enter(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- &priv->rtllib->pwr_save_ctrl;
- enum rt_rf_power_state rt_state;
-
- rt_state = priv->rtllib->rf_power_state;
- if (rt_state == rf_on && !psc->bSwRfProcessing &&
- (priv->rtllib->link_state != MAC80211_LINKED)) {
- psc->eInactivePowerState = rf_off;
- _rtl92e_ps_update_rf_state(dev);
- }
-}
-
-void rtl92e_ips_leave(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- &priv->rtllib->pwr_save_ctrl;
- enum rt_rf_power_state rt_state;
-
- rt_state = priv->rtllib->rf_power_state;
- if (rt_state != rf_on && !psc->bSwRfProcessing &&
- priv->rtllib->rf_off_reason <= RF_CHANGE_BY_IPS) {
- psc->eInactivePowerState = rf_on;
- _rtl92e_ps_update_rf_state(dev);
- }
-}
-
-void rtl92e_ips_leave_wq(void *data)
-{
- struct rtllib_device *ieee = container_of(data, struct rtllib_device, ips_leave_wq);
- struct net_device *dev = ieee->dev;
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
-}
-
-void rtl92e_rtllib_ips_leave_wq(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
- enum rt_rf_power_state rt_state;
-
- rt_state = priv->rtllib->rf_power_state;
- if (rt_state == rf_off) {
- if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) {
- netdev_warn(dev, "%s(): RF is OFF.\n",
- __func__);
- return;
- }
- netdev_info(dev, "=========>%s(): rtl92e_ips_leave\n",
- __func__);
- schedule_work(&priv->rtllib->ips_leave_wq);
- }
-}
-
-void rtl92e_rtllib_ips_leave(struct net_device *dev)
-{
- struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
-
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
-}
-
-static bool _rtl92e_ps_set_mode(struct net_device *dev, u8 rtPsMode)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->rtllib->ps = rtPsMode;
- if (priv->rtllib->sta_sleep != LPS_IS_WAKE &&
- rtPsMode == RTLLIB_PS_DISABLED) {
- unsigned long flags;
-
- rtl92e_hw_wakeup(dev);
- priv->rtllib->sta_sleep = LPS_IS_WAKE;
-
- spin_lock_irqsave(&(priv->rtllib->mgmt_tx_lock), flags);
- rtllib_sta_ps_send_null_frame(priv->rtllib, 0);
- spin_unlock_irqrestore(&(priv->rtllib->mgmt_tx_lock), flags);
- }
-
- return true;
-}
-
-void rtl92e_leisure_ps_enter(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- &priv->rtllib->pwr_save_ctrl;
-
- if (!((priv->rtllib->iw_mode == IW_MODE_INFRA) &&
- (priv->rtllib->link_state == MAC80211_LINKED)))
- return;
-
- if (psc->bLeisurePs) {
- if (psc->lps_idle_count >= RT_CHECK_FOR_HANG_PERIOD) {
- if (priv->rtllib->ps == RTLLIB_PS_DISABLED)
- _rtl92e_ps_set_mode(dev, RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST);
- } else {
- psc->lps_idle_count++;
- }
- }
-}
-
-void rtl92e_leisure_ps_leave(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
- &priv->rtllib->pwr_save_ctrl;
-
- if (psc->bLeisurePs) {
- if (priv->rtllib->ps != RTLLIB_PS_DISABLED)
- _rtl92e_ps_set_mode(dev, RTLLIB_PS_DISABLED);
- }
-}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
deleted file mode 100644
index 70fe5d39be9a..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL_PS_H
-#define _RTL_PS_H
-
-#include <linux/types.h>
-
-struct net_device;
-
-#define RT_CHECK_FOR_HANG_PERIOD 2
-
-void rtl92e_hw_wakeup(struct net_device *dev);
-void rtl92e_enter_sleep(struct net_device *dev, u64 time);
-void rtl92e_rtllib_ips_leave_wq(struct net_device *dev);
-void rtl92e_rtllib_ips_leave(struct net_device *dev);
-void rtl92e_ips_leave_wq(void *data);
-
-void rtl92e_ips_enter(struct net_device *dev);
-void rtl92e_ips_leave(struct net_device *dev);
-
-void rtl92e_leisure_ps_enter(struct net_device *dev);
-void rtl92e_leisure_ps_leave(struct net_device *dev);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
deleted file mode 100644
index fe3a42a4fcd5..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ /dev/null
@@ -1,867 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include <linux/string.h>
-#include "rtl_core.h"
-#include "rtl_wx.h"
-
-#define RATE_COUNT 12
-static u32 rtl8192_rates[] = {
- 1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000,
- 18000000, 24000000, 36000000, 48000000, 54000000
-};
-
-#ifndef ENETDOWN
-#define ENETDOWN 1
-#endif
-
-static int _rtl92e_wx_get_freq(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_freq(priv->rtllib, a, wrqu, b);
-}
-
-static int _rtl92e_wx_get_mode(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_mode(priv->rtllib, a, wrqu, b);
-}
-
-static int _rtl92e_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_rate(priv->rtllib, info, wrqu, extra);
-}
-
-static int _rtl92e_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_rate(priv->rtllib, info, wrqu, extra);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_rts(priv->rtllib, info, wrqu, extra);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_rts(priv->rtllib, info, wrqu, extra);
-}
-
-static int _rtl92e_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off) {
- netdev_warn(dev, "%s(): Can't set Power: Radio is Off.\n",
- __func__);
- return 0;
- }
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_power(priv->rtllib, info, wrqu, extra);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_power(priv->rtllib, info, wrqu, extra);
-}
-
-static int _rtl92e_wx_set_mode(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- enum rt_rf_power_state rt_state;
- int ret;
-
- if (priv->hw_radio_off)
- return 0;
- rt_state = priv->rtllib->rf_power_state;
- mutex_lock(&priv->wx_mutex);
- if (wrqu->mode == IW_MODE_MONITOR) {
- if (rt_state == rf_off) {
- if (priv->rtllib->rf_off_reason >
- RF_CHANGE_BY_IPS) {
- netdev_warn(dev, "%s(): RF is OFF.\n",
- __func__);
- mutex_unlock(&priv->wx_mutex);
- return -1;
- }
- netdev_info(dev,
- "=========>%s(): rtl92e_ips_leave\n",
- __func__);
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
- }
- }
- ret = rtllib_wx_set_mode(priv->rtllib, a, wrqu, b);
-
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_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;
- struct r8192_priv *priv = rtllib_priv(dev);
- u16 val;
- int i;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* ~130 Mb/s real (802.11n) */
- range->throughput = 130 * 1000 * 1000;
-
- range->max_qual.qual = 100;
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
- range->avg_qual.level = 0;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
-
- range->num_bitrates = min(RATE_COUNT, IW_MAX_BITRATES);
-
- for (i = 0; i < range->num_bitrates; i++)
- range->bitrate[i] = rtl8192_rates[i];
-
- range->max_rts = DEFAULT_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->min_pmp = 0;
- range->max_pmp = 5000000;
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1000;
- 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;
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- for (i = 0, val = 0; i < 14; i++) {
- if ((priv->rtllib->active_channel_map)[i + 1]) {
- s32 freq_khz;
-
- range->freq[val].i = i + 1;
- freq_khz = ieee80211_channel_to_freq_khz(i + 1, NL80211_BAND_2GHZ);
- range->freq[val].m = freq_khz * 100;
- range->freq[val].e = 1;
- val++;
- }
-
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
- range->num_channels = val;
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
- range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
-
- /* Event capability (kernel + driver) */
-
- return 0;
-}
-
-static int _rtl92e_wx_set_scan(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- enum rt_rf_power_state rt_state;
- int ret;
-
- if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
- if ((ieee->link_state >= RTLLIB_ASSOCIATING) &&
- (ieee->link_state <= RTLLIB_ASSOCIATING_AUTHENTICATED))
- return 0;
- if ((priv->rtllib->link_state == MAC80211_LINKED) &&
- (priv->rtllib->cnt_after_link < 2))
- return 0;
- }
-
- if (priv->hw_radio_off) {
- netdev_info(dev, "================>%s(): hwradio off\n",
- __func__);
- return 0;
- }
- rt_state = priv->rtllib->rf_power_state;
- if (!priv->up)
- return -ENETDOWN;
- if (priv->rtllib->link_detect_info.busy_traffic)
- return -EAGAIN;
-
- if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- struct iw_scan_req *req = (struct iw_scan_req *)b;
-
- if (req->essid_len) {
- int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
-
- ieee->current_network.ssid_len = len;
- memcpy(ieee->current_network.ssid, req->essid, len);
- }
- }
-
- mutex_lock(&priv->wx_mutex);
-
- priv->rtllib->first_ie_in_scan = true;
-
- if (priv->rtllib->link_state != MAC80211_LINKED) {
- if (rt_state == rf_off) {
- if (priv->rtllib->rf_off_reason >
- RF_CHANGE_BY_IPS) {
- netdev_warn(dev, "%s(): RF is OFF.\n",
- __func__);
- mutex_unlock(&priv->wx_mutex);
- return -1;
- }
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
- }
- rtllib_stop_scan(priv->rtllib);
- if (priv->rtllib->rf_power_state != rf_off) {
- priv->rtllib->actscanning = true;
-
- ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_BACKUP);
-
- rtllib_start_scan_syncro(priv->rtllib);
-
- ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_RESTORE);
- }
- ret = 0;
- } else {
- priv->rtllib->actscanning = true;
- ret = rtllib_wx_set_scan(priv->rtllib, a, wrqu, b);
- }
-
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_get_scan(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (!priv->up)
- return -ENETDOWN;
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_get_scan(priv->rtllib, a, wrqu, b);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_set_essid(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
-
- if (priv->hw_radio_off) {
- netdev_info(dev,
- "=========>%s():hw radio off,or Rf state is rf_off, return\n",
- __func__);
- return 0;
- }
- mutex_lock(&priv->wx_mutex);
- ret = rtllib_wx_set_essid(priv->rtllib, a, wrqu, b);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_get_essid(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_get_essid(priv->rtllib, a, wrqu, b);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
- mutex_lock(&priv->wx_mutex);
- wrqu->data.length = min_t(size_t, wrqu->data.length,
- sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
- mutex_unlock(&priv->wx_mutex);
- return 0;
-}
-
-static int _rtl92e_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- mutex_lock(&priv->wx_mutex);
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
- mutex_unlock(&priv->wx_mutex);
- return 0;
-}
-
-static int _rtl92e_wx_set_freq(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_freq(priv->rtllib, a, wrqu, b);
-
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_name(priv->rtllib, info, wrqu, extra);
-}
-
-static int _rtl92e_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- if (wrqu->frag.disabled) {
- priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD;
- } else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD)
- return -EINVAL;
-
- priv->rtllib->fts = wrqu->frag.value & ~0x1;
- }
-
- return 0;
-}
-
-static int _rtl92e_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- wrqu->frag.value = priv->rtllib->fts;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD);
-
- return 0;
-}
-
-static int _rtl92e_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *awrq, char *extra)
-{
- int ret;
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_wap(priv->rtllib, info, awrq, extra);
-
- mutex_unlock(&priv->wx_mutex);
-
- return ret;
-}
-
-static int _rtl92e_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_wap(priv->rtllib, info, wrqu, extra);
-}
-
-static int _rtl92e_wx_get_enc(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- return rtllib_wx_get_encode(priv->rtllib, info, wrqu, key);
-}
-
-static int _rtl92e_wx_set_enc(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int ret;
-
- struct rtllib_device *ieee = priv->rtllib;
- u32 hwkey[4] = {0, 0, 0, 0};
- u8 mask = 0xff;
- u32 key_idx = 0;
- u8 zero_addr[4][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} };
- int i;
-
- if (priv->hw_radio_off)
- return 0;
-
- if (!priv->up)
- return -ENETDOWN;
-
- priv->rtllib->wx_set_enc = 1;
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
- mutex_lock(&priv->wx_mutex);
-
- ret = rtllib_wx_set_encode(priv->rtllib, info, wrqu, key);
- mutex_unlock(&priv->wx_mutex);
-
- if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
- ieee->pairwise_key_type = KEY_TYPE_NA;
- ieee->group_key_type = KEY_TYPE_NA;
- rtl92e_cam_reset(dev);
- memset(priv->rtllib->swcamtable, 0,
- sizeof(struct sw_cam_table) * 32);
- goto end_hw_sec;
- }
- if (wrqu->encoding.length != 0) {
- for (i = 0; i < 4; i++) {
- hwkey[i] |= key[4 * i + 0] & mask;
- if (i == 1 && (4 * i + 1) == wrqu->encoding.length)
- mask = 0x00;
- if (i == 3 && (4 * i + 1) == wrqu->encoding.length)
- mask = 0x00;
- hwkey[i] |= (key[4 * i + 1] & mask) << 8;
- hwkey[i] |= (key[4 * i + 2] & mask) << 16;
- hwkey[i] |= (key[4 * i + 3] & mask) << 24;
- }
-
- switch (wrqu->encoding.flags & IW_ENCODE_INDEX) {
- case 0:
- key_idx = ieee->crypt_info.tx_keyidx;
- break;
- case 1:
- key_idx = 0;
- break;
- case 2:
- key_idx = 1;
- break;
- case 3:
- key_idx = 2;
- break;
- case 4:
- key_idx = 3;
- break;
- default:
- break;
- }
- if (wrqu->encoding.length == 0x5) {
- ieee->pairwise_key_type = KEY_TYPE_WEP40;
- rtl92e_enable_hw_security_config(dev);
- }
-
- else if (wrqu->encoding.length == 0xd) {
- ieee->pairwise_key_type = KEY_TYPE_WEP104;
- rtl92e_enable_hw_security_config(dev);
- rtl92e_set_key(dev, key_idx, key_idx, KEY_TYPE_WEP104,
- zero_addr[key_idx], 0, hwkey);
- rtl92e_set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104,
- zero_addr[key_idx], hwkey);
- } else {
- netdev_info(dev,
- "wrong type in WEP, not WEP40 and WEP104\n");
- }
- }
-
-end_hw_sec:
- priv->rtllib->wx_set_enc = 0;
- return ret;
-}
-
-#define R8192_MAX_RETRY 255
-static int _rtl92e_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- int err = 0;
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
- wrqu->retry.disabled) {
- err = -EINVAL;
- goto exit;
- }
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) {
- err = -EINVAL;
- goto exit;
- }
-
- if (wrqu->retry.value > R8192_MAX_RETRY) {
- err = -EINVAL;
- goto exit;
- }
- if (wrqu->retry.flags & IW_RETRY_MAX)
- priv->retry_rts = wrqu->retry.value;
- else
- priv->retry_data = wrqu->retry.value;
-
- rtl92e_commit(dev);
-exit:
- mutex_unlock(&priv->wx_mutex);
-
- return err;
-}
-
-static int _rtl92e_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- wrqu->retry.disabled = 0; /* can't be disabled */
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
- IW_RETRY_LIFETIME)
- return -EINVAL;
-
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
- wrqu->retry.value = priv->retry_rts;
- } else {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
- wrqu->retry.value = priv->retry_data;
- }
- return 0;
-}
-
-static int _rtl92e_wx_set_encode_ext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret = 0;
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
-
- priv->rtllib->wx_set_enc = 1;
- mutex_lock(&priv->rtllib->ips_mutex);
- rtl92e_ips_leave(dev);
- mutex_unlock(&priv->rtllib->ips_mutex);
-
- ret = rtllib_wx_set_encode_ext(ieee, info, wrqu, extra);
- {
- const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 zero[ETH_ALEN] = {0};
- u32 key[4] = {0};
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct iw_point *encoding = &wrqu->encoding;
- u8 idx = 0, alg = 0, group = 0;
-
- if ((encoding->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- ieee->pairwise_key_type = KEY_TYPE_NA;
- ieee->group_key_type = KEY_TYPE_NA;
- rtl92e_cam_reset(dev);
- memset(priv->rtllib->swcamtable, 0,
- sizeof(struct sw_cam_table) * 32);
- goto end_hw_sec;
- }
- alg = (ext->alg == IW_ENCODE_ALG_CCMP) ? KEY_TYPE_CCMP :
- ext->alg;
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx)
- idx--;
- group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY;
-
- if ((!group) || (alg == KEY_TYPE_WEP40)) {
- if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40))
- alg = KEY_TYPE_WEP104;
- ieee->pairwise_key_type = alg;
- rtl92e_enable_hw_security_config(dev);
- }
- memcpy((u8 *)key, ext->key, 16);
-
- if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) {
- if (ext->key_len == 13)
- ieee->pairwise_key_type = alg = KEY_TYPE_WEP104;
- rtl92e_set_key(dev, idx, idx, alg, zero, 0, key);
- rtl92e_set_swcam(dev, idx, idx, alg, zero, key);
- } else if (group) {
- ieee->group_key_type = alg;
- rtl92e_set_key(dev, idx, idx, alg, broadcast_addr, 0,
- key);
- rtl92e_set_swcam(dev, idx, idx, alg, broadcast_addr, key);
- } else {
- if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) &&
- ieee->ht_info->current_ht_support)
- rtl92e_writeb(dev, 0x173, 1);
- rtl92e_set_key(dev, 4, idx, alg,
- (u8 *)ieee->ap_mac_addr, 0, key);
- rtl92e_set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, key);
- }
- }
-
-end_hw_sec:
- priv->rtllib->wx_set_enc = 0;
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- int ret = 0;
-
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
- ret = rtllib_wx_set_auth(priv->rtllib, info, &data->param, extra);
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret = 0;
-
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
- ret = rtllib_wx_set_mlme(priv->rtllib, info, wrqu, extra);
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_set_gen_ie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- int ret = 0;
-
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (priv->hw_radio_off)
- return 0;
-
- mutex_lock(&priv->wx_mutex);
- ret = rtllib_wx_set_gen_ie(priv->rtllib, extra, data->data.length);
- mutex_unlock(&priv->wx_mutex);
- return ret;
-}
-
-static int _rtl92e_wx_get_gen_ie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- int ret = 0;
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
-
- if (ieee->wpa_ie_len == 0 || !ieee->wpa_ie) {
- data->data.length = 0;
- return 0;
- }
-
- if (data->data.length < ieee->wpa_ie_len)
- return -E2BIG;
-
- data->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
- return ret;
-}
-
-#define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT)
-static iw_handler r8192_wx_handlers[] = {
- [IW_IOCTL(SIOCGIWNAME)] = _rtl92e_wx_get_name,
- [IW_IOCTL(SIOCSIWFREQ)] = _rtl92e_wx_set_freq,
- [IW_IOCTL(SIOCGIWFREQ)] = _rtl92e_wx_get_freq,
- [IW_IOCTL(SIOCSIWMODE)] = _rtl92e_wx_set_mode,
- [IW_IOCTL(SIOCGIWMODE)] = _rtl92e_wx_get_mode,
- [IW_IOCTL(SIOCGIWRANGE)] = _rtl92e_wx_get_range,
- [IW_IOCTL(SIOCSIWAP)] = _rtl92e_wx_set_wap,
- [IW_IOCTL(SIOCGIWAP)] = _rtl92e_wx_get_wap,
- [IW_IOCTL(SIOCSIWSCAN)] = _rtl92e_wx_set_scan,
- [IW_IOCTL(SIOCGIWSCAN)] = _rtl92e_wx_get_scan,
- [IW_IOCTL(SIOCSIWESSID)] = _rtl92e_wx_set_essid,
- [IW_IOCTL(SIOCGIWESSID)] = _rtl92e_wx_get_essid,
- [IW_IOCTL(SIOCSIWNICKN)] = _rtl92e_wx_set_nick,
- [IW_IOCTL(SIOCGIWNICKN)] = _rtl92e_wx_get_nick,
- [IW_IOCTL(SIOCSIWRATE)] = _rtl92e_wx_set_rate,
- [IW_IOCTL(SIOCGIWRATE)] = _rtl92e_wx_get_rate,
- [IW_IOCTL(SIOCSIWRTS)] = _rtl92e_wx_set_rts,
- [IW_IOCTL(SIOCGIWRTS)] = _rtl92e_wx_get_rts,
- [IW_IOCTL(SIOCSIWFRAG)] = _rtl92e_wx_set_frag,
- [IW_IOCTL(SIOCGIWFRAG)] = _rtl92e_wx_get_frag,
- [IW_IOCTL(SIOCSIWRETRY)] = _rtl92e_wx_set_retry,
- [IW_IOCTL(SIOCGIWRETRY)] = _rtl92e_wx_get_retry,
- [IW_IOCTL(SIOCSIWENCODE)] = _rtl92e_wx_set_enc,
- [IW_IOCTL(SIOCGIWENCODE)] = _rtl92e_wx_get_enc,
- [IW_IOCTL(SIOCSIWPOWER)] = _rtl92e_wx_set_power,
- [IW_IOCTL(SIOCGIWPOWER)] = _rtl92e_wx_get_power,
- [IW_IOCTL(SIOCSIWGENIE)] = _rtl92e_wx_set_gen_ie,
- [IW_IOCTL(SIOCGIWGENIE)] = _rtl92e_wx_get_gen_ie,
- [IW_IOCTL(SIOCSIWMLME)] = _rtl92e_wx_set_mlme,
- [IW_IOCTL(SIOCSIWAUTH)] = _rtl92e_wx_set_auth,
- [IW_IOCTL(SIOCSIWENCODEEXT)] = _rtl92e_wx_set_encode_ext,
-};
-
-static struct iw_statistics *_rtl92e_get_wireless_stats(struct net_device *dev)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
- struct rtllib_device *ieee = priv->rtllib;
- struct iw_statistics *wstats = &priv->wstats;
- int tmp_level = 0;
- int tmp_qual = 0;
- int tmp_noise = 0;
-
- if (ieee->link_state < MAC80211_LINKED) {
- wstats->qual.qual = 10;
- wstats->qual.level = 0;
- wstats->qual.noise = 0x100 - 100; /* -100 dBm */
- wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- return wstats;
- }
-
- tmp_level = (&ieee->current_network)->stats.rssi;
- tmp_qual = (&ieee->current_network)->stats.signal;
- tmp_noise = (&ieee->current_network)->stats.noise;
-
- wstats->qual.level = tmp_level;
- wstats->qual.qual = tmp_qual;
- wstats->qual.noise = tmp_noise;
- wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- return wstats;
-}
-
-const struct iw_handler_def r8192_wx_handlers_def = {
- .standard = r8192_wx_handlers,
- .num_standard = ARRAY_SIZE(r8192_wx_handlers),
- .get_wireless_stats = _rtl92e_get_wireless_stats,
-};
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h
deleted file mode 100644
index d70a747ac1dd..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef R819x_WX_H
-#define R819x_WX_H
-
-struct iw_handler_def;
-
-extern const struct iw_handler_def r8192_wx_handlers_def;
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/table.c b/drivers/staging/rtl8192e/rtl8192e/table.c
deleted file mode 100644
index 0b5cc6049232..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/table.c
+++ /dev/null
@@ -1,543 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "table.h"
-
-u32 RTL8192E_PHY_REG_1T2R_ARR[RTL8192E_PHY_REG_1T2R_ARR_LEN] = {
- 0x800, 0x00000000,
- 0x804, 0x00000001,
- 0x808, 0x0000fc00,
- 0x80c, 0x0000001c,
- 0x810, 0x801010aa,
- 0x814, 0x008514d0,
- 0x818, 0x00000040,
- 0x81c, 0x00000000,
- 0x820, 0x00000004,
- 0x824, 0x00690000,
- 0x828, 0x00000004,
- 0x82c, 0x00e90000,
- 0x830, 0x00000004,
- 0x834, 0x00690000,
- 0x838, 0x00000004,
- 0x83c, 0x00e90000,
- 0x840, 0x00000000,
- 0x844, 0x00000000,
- 0x848, 0x00000000,
- 0x84c, 0x00000000,
- 0x850, 0x00000000,
- 0x854, 0x00000000,
- 0x858, 0x65a965a9,
- 0x85c, 0x65a965a9,
- 0x860, 0x001f0010,
- 0x864, 0x007f0010,
- 0x868, 0x001f0010,
- 0x86c, 0x007f0010,
- 0x870, 0x0f100f70,
- 0x874, 0x0f100f70,
- 0x878, 0x00000000,
- 0x87c, 0x00000000,
- 0x880, 0x6870e36c,
- 0x884, 0xe3573600,
- 0x888, 0x4260c340,
- 0x88c, 0x0000ff00,
- 0x890, 0x00000000,
- 0x894, 0xfffffffe,
- 0x898, 0x4c42382f,
- 0x89c, 0x00656056,
- 0x8b0, 0x00000000,
- 0x8e0, 0x00000000,
- 0x8e4, 0x00000000,
- 0x900, 0x00000000,
- 0x904, 0x00000023,
- 0x908, 0x00000000,
- 0x90c, 0x31121311,
- 0xa00, 0x00d0c7d8,
- 0xa04, 0x811f0008,
- 0xa08, 0x80cd8300,
- 0xa0c, 0x2e62740f,
- 0xa10, 0x95009b78,
- 0xa14, 0x11145008,
- 0xa18, 0x00881117,
- 0xa1c, 0x89140fa0,
- 0xa20, 0x1a1b0000,
- 0xa24, 0x090e1317,
- 0xa28, 0x00000204,
- 0xa2c, 0x00000000,
- 0xc00, 0x00000040,
- 0xc04, 0x00005433,
- 0xc08, 0x000000e4,
- 0xc0c, 0x6c6c6c6c,
- 0xc10, 0x08800000,
- 0xc14, 0x40000100,
- 0xc18, 0x08000000,
- 0xc1c, 0x40000100,
- 0xc20, 0x08000000,
- 0xc24, 0x40000100,
- 0xc28, 0x08000000,
- 0xc2c, 0x40000100,
- 0xc30, 0x6de9ac44,
- 0xc34, 0x465c52cd,
- 0xc38, 0x497f5994,
- 0xc3c, 0x0a969764,
- 0xc40, 0x1f7c403f,
- 0xc44, 0x000100b7,
- 0xc48, 0xec020000,
- 0xc4c, 0x00000300,
- 0xc50, 0x69543420,
- 0xc54, 0x433c0094,
- 0xc58, 0x69543420,
- 0xc5c, 0x433c0094,
- 0xc60, 0x69543420,
- 0xc64, 0x433c0094,
- 0xc68, 0x69543420,
- 0xc6c, 0x433c0094,
- 0xc70, 0x2c7f000d,
- 0xc74, 0x0186175b,
- 0xc78, 0x0000001f,
- 0xc7c, 0x00b91612,
- 0xc80, 0x40000100,
- 0xc84, 0x20000000,
- 0xc88, 0x40000100,
- 0xc8c, 0x20200000,
- 0xc90, 0x40000100,
- 0xc94, 0x00000000,
- 0xc98, 0x40000100,
- 0xc9c, 0x00000000,
- 0xca0, 0x00492492,
- 0xca4, 0x00000000,
- 0xca8, 0x00000000,
- 0xcac, 0x00000000,
- 0xcb0, 0x00000000,
- 0xcb4, 0x00000000,
- 0xcb8, 0x00000000,
- 0xcbc, 0x00492492,
- 0xcc0, 0x00000000,
- 0xcc4, 0x00000000,
- 0xcc8, 0x00000000,
- 0xccc, 0x00000000,
- 0xcd0, 0x00000000,
- 0xcd4, 0x00000000,
- 0xcd8, 0x64b22427,
- 0xcdc, 0x00766932,
- 0xce0, 0x00222222,
- 0xd00, 0x00000750,
- 0xd04, 0x00000403,
- 0xd08, 0x0000907f,
- 0xd0c, 0x00000001,
- 0xd10, 0xa0633333,
- 0xd14, 0x33333c63,
- 0xd18, 0x6a8f5b6b,
- 0xd1c, 0x00000000,
- 0xd20, 0x00000000,
- 0xd24, 0x00000000,
- 0xd28, 0x00000000,
- 0xd2c, 0xcc979975,
- 0xd30, 0x00000000,
- 0xd34, 0x00000000,
- 0xd38, 0x00000000,
- 0xd3c, 0x00027293,
- 0xd40, 0x00000000,
- 0xd44, 0x00000000,
- 0xd48, 0x00000000,
- 0xd4c, 0x00000000,
- 0xd50, 0x6437140a,
- 0xd54, 0x024dbd02,
- 0xd58, 0x00000000,
- 0xd5c, 0x04032064,
- 0xe00, 0x161a1a1a,
- 0xe04, 0x12121416,
- 0xe08, 0x00001800,
- 0xe0c, 0x00000000,
- 0xe10, 0x161a1a1a,
- 0xe14, 0x12121416,
- 0xe18, 0x161a1a1a,
- 0xe1c, 0x12121416,
-};
-
-u32 RTL8192E_RADIO_A_ARR[RTL8192E_RADIO_A_ARR_LEN] = {
- 0x019, 0x00000003,
- 0x000, 0x000000bf,
- 0x001, 0x00000ee0,
- 0x002, 0x0000004c,
- 0x003, 0x000007f1,
- 0x004, 0x00000975,
- 0x005, 0x00000c58,
- 0x006, 0x00000ae6,
- 0x007, 0x000000ca,
- 0x008, 0x00000e1c,
- 0x009, 0x000007f0,
- 0x00a, 0x000009d0,
- 0x00b, 0x000001ba,
- 0x00c, 0x00000240,
- 0x00e, 0x00000020,
- 0x00f, 0x00000990,
- 0x012, 0x00000806,
- 0x014, 0x000005ab,
- 0x015, 0x00000f80,
- 0x016, 0x00000020,
- 0x017, 0x00000597,
- 0x018, 0x0000050a,
- 0x01a, 0x00000f80,
- 0x01b, 0x00000f5e,
- 0x01c, 0x00000008,
- 0x01d, 0x00000607,
- 0x01e, 0x000006cc,
- 0x01f, 0x00000000,
- 0x020, 0x000001a5,
- 0x01f, 0x00000001,
- 0x020, 0x00000165,
- 0x01f, 0x00000002,
- 0x020, 0x000000c6,
- 0x01f, 0x00000003,
- 0x020, 0x00000086,
- 0x01f, 0x00000004,
- 0x020, 0x00000046,
- 0x01f, 0x00000005,
- 0x020, 0x000001e6,
- 0x01f, 0x00000006,
- 0x020, 0x000001a6,
- 0x01f, 0x00000007,
- 0x020, 0x00000166,
- 0x01f, 0x00000008,
- 0x020, 0x000000c7,
- 0x01f, 0x00000009,
- 0x020, 0x00000087,
- 0x01f, 0x0000000a,
- 0x020, 0x000000f7,
- 0x01f, 0x0000000b,
- 0x020, 0x000000d7,
- 0x01f, 0x0000000c,
- 0x020, 0x000000b7,
- 0x01f, 0x0000000d,
- 0x020, 0x00000097,
- 0x01f, 0x0000000e,
- 0x020, 0x00000077,
- 0x01f, 0x0000000f,
- 0x020, 0x00000057,
- 0x01f, 0x00000010,
- 0x020, 0x00000037,
- 0x01f, 0x00000011,
- 0x020, 0x000000fb,
- 0x01f, 0x00000012,
- 0x020, 0x000000db,
- 0x01f, 0x00000013,
- 0x020, 0x000000bb,
- 0x01f, 0x00000014,
- 0x020, 0x000000ff,
- 0x01f, 0x00000015,
- 0x020, 0x000000e3,
- 0x01f, 0x00000016,
- 0x020, 0x000000c3,
- 0x01f, 0x00000017,
- 0x020, 0x000000a3,
- 0x01f, 0x00000018,
- 0x020, 0x00000083,
- 0x01f, 0x00000019,
- 0x020, 0x00000063,
- 0x01f, 0x0000001a,
- 0x020, 0x00000043,
- 0x01f, 0x0000001b,
- 0x020, 0x00000023,
- 0x01f, 0x0000001c,
- 0x020, 0x00000003,
- 0x01f, 0x0000001d,
- 0x020, 0x000001e3,
- 0x01f, 0x0000001e,
- 0x020, 0x000001c3,
- 0x01f, 0x0000001f,
- 0x020, 0x000001a3,
- 0x01f, 0x00000020,
- 0x020, 0x00000183,
- 0x01f, 0x00000021,
- 0x020, 0x00000163,
- 0x01f, 0x00000022,
- 0x020, 0x00000143,
- 0x01f, 0x00000023,
- 0x020, 0x00000123,
- 0x01f, 0x00000024,
- 0x020, 0x00000103,
- 0x023, 0x00000203,
- 0x024, 0x00000100,
- 0x00b, 0x000001ba,
- 0x02c, 0x000003d7,
- 0x02d, 0x00000ff0,
- 0x000, 0x00000037,
- 0x004, 0x00000160,
- 0x007, 0x00000080,
- 0x002, 0x0000088d,
- 0x0fe, 0x00000000,
- 0x0fe, 0x00000000,
- 0x016, 0x00000200,
- 0x016, 0x00000380,
- 0x016, 0x00000020,
- 0x016, 0x000001a0,
- 0x000, 0x000000bf,
- 0x00d, 0x0000001f,
- 0x00d, 0x00000c9f,
- 0x002, 0x0000004d,
- 0x000, 0x00000cbf,
- 0x004, 0x00000975,
- 0x007, 0x00000700,
-};
-
-u32 RTL8192E_RADIO_B_ARR[RTL8192E_RADIO_B_ARR_LEN] = {
- 0x019, 0x00000003,
- 0x000, 0x000000bf,
- 0x001, 0x000006e0,
- 0x002, 0x0000004c,
- 0x003, 0x000007f1,
- 0x004, 0x00000975,
- 0x005, 0x00000c58,
- 0x006, 0x00000ae6,
- 0x007, 0x000000ca,
- 0x008, 0x00000e1c,
- 0x000, 0x000000b7,
- 0x00a, 0x00000850,
- 0x000, 0x000000bf,
- 0x00b, 0x000001ba,
- 0x00c, 0x00000240,
- 0x00e, 0x00000020,
- 0x015, 0x00000f80,
- 0x016, 0x00000020,
- 0x017, 0x00000597,
- 0x018, 0x0000050a,
- 0x01a, 0x00000e00,
- 0x01b, 0x00000f5e,
- 0x01d, 0x00000607,
- 0x01e, 0x000006cc,
- 0x00b, 0x000001ba,
- 0x023, 0x00000203,
- 0x024, 0x00000100,
- 0x000, 0x00000037,
- 0x004, 0x00000160,
- 0x016, 0x00000200,
- 0x016, 0x00000380,
- 0x016, 0x00000020,
- 0x016, 0x000001a0,
- 0x00d, 0x00000ccc,
- 0x000, 0x000000bf,
- 0x002, 0x0000004d,
- 0x000, 0x00000cbf,
- 0x004, 0x00000975,
- 0x007, 0x00000700,
-};
-
-u32 RTL8192E_MACPHY_ARR[] = {
- 0x03c, 0xffff0000, 0x00000f0f,
- 0x340, 0xffffffff, 0x161a1a1a,
- 0x344, 0xffffffff, 0x12121416,
- 0x348, 0x0000ffff, 0x00001818,
- 0x12c, 0xffffffff, 0x04000802,
- 0x318, 0x00000fff, 0x00000100,
-};
-
-u32 RTL8192E_MACPHY_ARR_PG[] = {
- 0x03c, 0xffff0000, 0x00000f0f,
- 0xe00, 0xffffffff, 0x06090909,
- 0xe04, 0xffffffff, 0x00030306,
- 0xe08, 0x0000ff00, 0x00000000,
- 0xe10, 0xffffffff, 0x0a0c0d0f,
- 0xe14, 0xffffffff, 0x06070809,
- 0xe18, 0xffffffff, 0x0a0c0d0f,
- 0xe1c, 0xffffffff, 0x06070809,
- 0x12c, 0xffffffff, 0x04000802,
- 0x318, 0x00000fff, 0x00000800,
-};
-
-u32 RTL8192E_AGCTAB_ARR[RTL8192E_AGCTAB_ARR_LEN] = {
- 0xc78, 0x7d000001,
- 0xc78, 0x7d010001,
- 0xc78, 0x7d020001,
- 0xc78, 0x7d030001,
- 0xc78, 0x7d040001,
- 0xc78, 0x7d050001,
- 0xc78, 0x7c060001,
- 0xc78, 0x7b070001,
- 0xc78, 0x7a080001,
- 0xc78, 0x79090001,
- 0xc78, 0x780a0001,
- 0xc78, 0x770b0001,
- 0xc78, 0x760c0001,
- 0xc78, 0x750d0001,
- 0xc78, 0x740e0001,
- 0xc78, 0x730f0001,
- 0xc78, 0x72100001,
- 0xc78, 0x71110001,
- 0xc78, 0x70120001,
- 0xc78, 0x6f130001,
- 0xc78, 0x6e140001,
- 0xc78, 0x6d150001,
- 0xc78, 0x6c160001,
- 0xc78, 0x6b170001,
- 0xc78, 0x6a180001,
- 0xc78, 0x69190001,
- 0xc78, 0x681a0001,
- 0xc78, 0x671b0001,
- 0xc78, 0x661c0001,
- 0xc78, 0x651d0001,
- 0xc78, 0x641e0001,
- 0xc78, 0x491f0001,
- 0xc78, 0x48200001,
- 0xc78, 0x47210001,
- 0xc78, 0x46220001,
- 0xc78, 0x45230001,
- 0xc78, 0x44240001,
- 0xc78, 0x43250001,
- 0xc78, 0x28260001,
- 0xc78, 0x27270001,
- 0xc78, 0x26280001,
- 0xc78, 0x25290001,
- 0xc78, 0x242a0001,
- 0xc78, 0x232b0001,
- 0xc78, 0x222c0001,
- 0xc78, 0x212d0001,
- 0xc78, 0x202e0001,
- 0xc78, 0x0a2f0001,
- 0xc78, 0x08300001,
- 0xc78, 0x06310001,
- 0xc78, 0x05320001,
- 0xc78, 0x04330001,
- 0xc78, 0x03340001,
- 0xc78, 0x02350001,
- 0xc78, 0x01360001,
- 0xc78, 0x00370001,
- 0xc78, 0x00380001,
- 0xc78, 0x00390001,
- 0xc78, 0x003a0001,
- 0xc78, 0x003b0001,
- 0xc78, 0x003c0001,
- 0xc78, 0x003d0001,
- 0xc78, 0x003e0001,
- 0xc78, 0x003f0001,
- 0xc78, 0x7d400001,
- 0xc78, 0x7d410001,
- 0xc78, 0x7d420001,
- 0xc78, 0x7d430001,
- 0xc78, 0x7d440001,
- 0xc78, 0x7d450001,
- 0xc78, 0x7c460001,
- 0xc78, 0x7b470001,
- 0xc78, 0x7a480001,
- 0xc78, 0x79490001,
- 0xc78, 0x784a0001,
- 0xc78, 0x774b0001,
- 0xc78, 0x764c0001,
- 0xc78, 0x754d0001,
- 0xc78, 0x744e0001,
- 0xc78, 0x734f0001,
- 0xc78, 0x72500001,
- 0xc78, 0x71510001,
- 0xc78, 0x70520001,
- 0xc78, 0x6f530001,
- 0xc78, 0x6e540001,
- 0xc78, 0x6d550001,
- 0xc78, 0x6c560001,
- 0xc78, 0x6b570001,
- 0xc78, 0x6a580001,
- 0xc78, 0x69590001,
- 0xc78, 0x685a0001,
- 0xc78, 0x675b0001,
- 0xc78, 0x665c0001,
- 0xc78, 0x655d0001,
- 0xc78, 0x645e0001,
- 0xc78, 0x495f0001,
- 0xc78, 0x48600001,
- 0xc78, 0x47610001,
- 0xc78, 0x46620001,
- 0xc78, 0x45630001,
- 0xc78, 0x44640001,
- 0xc78, 0x43650001,
- 0xc78, 0x28660001,
- 0xc78, 0x27670001,
- 0xc78, 0x26680001,
- 0xc78, 0x25690001,
- 0xc78, 0x246a0001,
- 0xc78, 0x236b0001,
- 0xc78, 0x226c0001,
- 0xc78, 0x216d0001,
- 0xc78, 0x206e0001,
- 0xc78, 0x0a6f0001,
- 0xc78, 0x08700001,
- 0xc78, 0x06710001,
- 0xc78, 0x05720001,
- 0xc78, 0x04730001,
- 0xc78, 0x03740001,
- 0xc78, 0x02750001,
- 0xc78, 0x01760001,
- 0xc78, 0x00770001,
- 0xc78, 0x00780001,
- 0xc78, 0x00790001,
- 0xc78, 0x007a0001,
- 0xc78, 0x007b0001,
- 0xc78, 0x007c0001,
- 0xc78, 0x007d0001,
- 0xc78, 0x007e0001,
- 0xc78, 0x007f0001,
- 0xc78, 0x2e00001e,
- 0xc78, 0x2e01001e,
- 0xc78, 0x2e02001e,
- 0xc78, 0x2e03001e,
- 0xc78, 0x2e04001e,
- 0xc78, 0x2e05001e,
- 0xc78, 0x3006001e,
- 0xc78, 0x3407001e,
- 0xc78, 0x3908001e,
- 0xc78, 0x3c09001e,
- 0xc78, 0x3f0a001e,
- 0xc78, 0x420b001e,
- 0xc78, 0x440c001e,
- 0xc78, 0x450d001e,
- 0xc78, 0x460e001e,
- 0xc78, 0x460f001e,
- 0xc78, 0x4710001e,
- 0xc78, 0x4811001e,
- 0xc78, 0x4912001e,
- 0xc78, 0x4a13001e,
- 0xc78, 0x4b14001e,
- 0xc78, 0x4b15001e,
- 0xc78, 0x4c16001e,
- 0xc78, 0x4d17001e,
- 0xc78, 0x4e18001e,
- 0xc78, 0x4f19001e,
- 0xc78, 0x4f1a001e,
- 0xc78, 0x501b001e,
- 0xc78, 0x511c001e,
- 0xc78, 0x521d001e,
- 0xc78, 0x521e001e,
- 0xc78, 0x531f001e,
- 0xc78, 0x5320001e,
- 0xc78, 0x5421001e,
- 0xc78, 0x5522001e,
- 0xc78, 0x5523001e,
- 0xc78, 0x5624001e,
- 0xc78, 0x5725001e,
- 0xc78, 0x5726001e,
- 0xc78, 0x5827001e,
- 0xc78, 0x5828001e,
- 0xc78, 0x5929001e,
- 0xc78, 0x592a001e,
- 0xc78, 0x5a2b001e,
- 0xc78, 0x5b2c001e,
- 0xc78, 0x5c2d001e,
- 0xc78, 0x5c2e001e,
- 0xc78, 0x5d2f001e,
- 0xc78, 0x5e30001e,
- 0xc78, 0x5f31001e,
- 0xc78, 0x6032001e,
- 0xc78, 0x6033001e,
- 0xc78, 0x6134001e,
- 0xc78, 0x6235001e,
- 0xc78, 0x6336001e,
- 0xc78, 0x6437001e,
- 0xc78, 0x6438001e,
- 0xc78, 0x6539001e,
- 0xc78, 0x663a001e,
- 0xc78, 0x673b001e,
- 0xc78, 0x673c001e,
- 0xc78, 0x683d001e,
- 0xc78, 0x693e001e,
- 0xc78, 0x6a3f001e,
-};
diff --git a/drivers/staging/rtl8192e/rtl8192e/table.h b/drivers/staging/rtl8192e/rtl8192e/table.h
deleted file mode 100644
index 82be44a9d4e8..000000000000
--- a/drivers/staging/rtl8192e/rtl8192e/table.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef __INC_HAL8192PciE_FW_IMG_H
-#define __INC_HAL8192PciE_FW_IMG_H
-
-/*Created on 2008/11/18, 3: 7*/
-
-#include <linux/types.h>
-
-#define RTL8192E_PHY_REG_1T2R_ARR_LEN 296
-extern u32 RTL8192E_PHY_REG_1T2R_ARR[RTL8192E_PHY_REG_1T2R_ARR_LEN];
-#define RTL8192E_RADIO_A_ARR_LEN 246
-extern u32 RTL8192E_RADIO_A_ARR[RTL8192E_RADIO_A_ARR_LEN];
-#define RTL8192E_RADIO_B_ARR_LEN 78
-extern u32 RTL8192E_RADIO_B_ARR[RTL8192E_RADIO_B_ARR_LEN];
-#define RTL8192E_MACPHY_ARR_LEN 18
-extern u32 RTL8192E_MACPHY_ARR[RTL8192E_MACPHY_ARR_LEN];
-#define RTL8192E_MACPHY_ARR_PG_LEN 30
-extern u32 RTL8192E_MACPHY_ARR_PG[RTL8192E_MACPHY_ARR_PG_LEN];
-#define RTL8192E_AGCTAB_ARR_LEN 384
-extern u32 RTL8192E_AGCTAB_ARR[RTL8192E_AGCTAB_ARR_LEN];
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_BA.h b/drivers/staging/rtl8192e/rtl819x_BA.h
deleted file mode 100644
index 8a35d7a3eee1..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_BA.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _BATYPE_H_
-#define _BATYPE_H_
-
-#define BA_SETUP_TIMEOUT 200
-
-#define BA_POLICY_DELAYED 0
-#define BA_POLICY_IMMEDIATE 1
-
-#define ADDBA_STATUS_SUCCESS 0
-#define ADDBA_STATUS_REFUSED 37
-#define ADDBA_STATUS_INVALID_PARAM 38
-
-#define DELBA_REASON_END_BA 37
-#define DELBA_REASON_UNKNOWN_BA 38
-#define DELBA_REASON_TIMEOUT 39
-union sequence_control {
- u16 short_data;
- struct {
- u16 frag_num:4;
- u16 seq_num:12;
- } field;
-};
-
-union ba_param_set {
- u8 char_data[2];
- u16 short_data;
- struct {
- u16 amsdu_support:1;
- u16 ba_policy:1;
- u16 tid:4;
- u16 buffer_size:10;
- } field;
-};
-
-union delba_param_set {
- u8 char_data[2];
- u16 short_data;
- struct {
- u16 reserved:11;
- u16 initiator:1;
- u16 tid:4;
- } field;
-};
-
-struct ba_record {
- struct timer_list timer;
- u8 b_valid;
- u8 dialog_token;
- union ba_param_set ba_param_set;
- u16 ba_timeout_value;
- union sequence_control ba_start_seq_ctrl;
-};
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c
deleted file mode 100644
index c400d4f8ff9a..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_BAProc.c
+++ /dev/null
@@ -1,544 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include <asm/byteorder.h>
-#include <linux/unaligned.h>
-#include <linux/etherdevice.h>
-#include "rtllib.h"
-#include "rtl819x_BA.h"
-
-static void activate_ba_entry(struct ba_record *ba, u16 time)
-{
- ba->b_valid = true;
- if (time != 0)
- mod_timer(&ba->timer, jiffies + msecs_to_jiffies(time));
-}
-
-static void deactivate_ba_entry(struct rtllib_device *ieee, struct ba_record *ba)
-{
- ba->b_valid = false;
- del_timer_sync(&ba->timer);
-}
-
-static u8 tx_ts_delete_ba(struct rtllib_device *ieee, struct tx_ts_record *ts)
-{
- struct ba_record *admitted_ba = &ts->tx_admitted_ba_record;
- struct ba_record *pending_ba = &ts->tx_pending_ba_record;
- u8 send_del_ba = false;
-
- if (pending_ba->b_valid) {
- deactivate_ba_entry(ieee, pending_ba);
- send_del_ba = true;
- }
-
- if (admitted_ba->b_valid) {
- deactivate_ba_entry(ieee, admitted_ba);
- send_del_ba = true;
- }
- return send_del_ba;
-}
-
-static u8 rx_ts_delete_ba(struct rtllib_device *ieee, struct rx_ts_record *ts)
-{
- struct ba_record *ba = &ts->rx_admitted_ba_record;
- u8 send_del_ba = false;
-
- if (ba->b_valid) {
- deactivate_ba_entry(ieee, ba);
- send_del_ba = true;
- }
-
- return send_del_ba;
-}
-
-void rtllib_reset_ba_entry(struct ba_record *ba)
-{
- ba->b_valid = false;
- ba->ba_param_set.short_data = 0;
- ba->ba_timeout_value = 0;
- ba->dialog_token = 0;
- ba->ba_start_seq_ctrl.short_data = 0;
-}
-
-static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst,
- struct ba_record *ba,
- u16 status_code, u8 type)
-{
- struct sk_buff *skb = NULL;
- struct ieee80211_hdr_3addr *ba_req = NULL;
- u8 *tag = NULL;
- u16 len = ieee->tx_headroom + 9;
-
- netdev_dbg(ieee->dev, "%s(): frame(%d) sentd to: %pM, ieee->dev:%p\n",
- __func__, type, dst, ieee->dev);
-
- if (!ba) {
- netdev_warn(ieee->dev, "ba is NULL\n");
- return NULL;
- }
- skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr));
- if (!skb)
- return NULL;
-
- memset(skb->data, 0, sizeof(struct ieee80211_hdr_3addr));
-
- skb_reserve(skb, ieee->tx_headroom);
-
- ba_req = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
-
- ether_addr_copy(ba_req->addr1, dst);
- ether_addr_copy(ba_req->addr2, ieee->dev->dev_addr);
-
- ether_addr_copy(ba_req->addr3, ieee->current_network.bssid);
- ba_req->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
-
- tag = skb_put(skb, 9);
- *tag++ = ACT_CAT_BA;
- *tag++ = type;
- *tag++ = ba->dialog_token;
-
- if (type == ACT_ADDBARSP) {
- put_unaligned_le16(status_code, tag);
- tag += 2;
- }
-
- put_unaligned_le16(ba->ba_param_set.short_data, tag);
- tag += 2;
-
- put_unaligned_le16(ba->ba_timeout_value, tag);
- tag += 2;
-
- if (type == ACT_ADDBAREQ) {
- memcpy(tag, (u8 *)&ba->ba_start_seq_ctrl, 2);
- tag += 2;
- }
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
- __func__, skb->len);
-#endif
- return skb;
-}
-
-static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
- struct ba_record *ba,
- enum tr_select tx_rx_select, u16 reason_code)
-{
- union delba_param_set del_ba_param_set;
- struct sk_buff *skb = NULL;
- struct ieee80211_hdr_3addr *del_ba = NULL;
- u8 *tag = NULL;
- u16 len = 6 + ieee->tx_headroom;
-
- if (net_ratelimit())
- netdev_dbg(ieee->dev, "%s(): reason_code(%d) sentd to: %pM\n",
- __func__, reason_code, dst);
-
- memset(&del_ba_param_set, 0, 2);
-
- del_ba_param_set.field.initiator = (tx_rx_select == TX_DIR) ? 1 : 0;
- del_ba_param_set.field.tid = ba->ba_param_set.field.tid;
-
- skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr));
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- del_ba = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
-
- ether_addr_copy(del_ba->addr1, dst);
- ether_addr_copy(del_ba->addr2, ieee->dev->dev_addr);
- ether_addr_copy(del_ba->addr3, ieee->current_network.bssid);
- del_ba->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
-
- tag = skb_put(skb, 6);
-
- *tag++ = ACT_CAT_BA;
- *tag++ = ACT_DELBA;
-
- put_unaligned_le16(del_ba_param_set.short_data, tag);
- tag += 2;
-
- put_unaligned_le16(reason_code, tag);
- tag += 2;
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
- __func__, skb->len);
-#endif
- return skb;
-}
-
-static void rtllib_send_add_ba_req(struct rtllib_device *ieee, u8 *dst,
- struct ba_record *ba)
-{
- struct sk_buff *skb;
-
- skb = rtllib_ADDBA(ieee, dst, ba, 0, ACT_ADDBAREQ);
-
- if (skb)
- softmac_mgmt_xmit(skb, ieee);
- else
- netdev_dbg(ieee->dev, "Failed to generate ADDBAReq packet.\n");
-}
-
-static void rtllib_send_add_ba_rsp(struct rtllib_device *ieee, u8 *dst,
- struct ba_record *ba, u16 status_code)
-{
- struct sk_buff *skb;
-
- skb = rtllib_ADDBA(ieee, dst, ba, status_code, ACT_ADDBARSP);
- if (skb)
- softmac_mgmt_xmit(skb, ieee);
- else
- netdev_dbg(ieee->dev, "Failed to generate ADDBARsp packet.\n");
-}
-
-static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst,
- struct ba_record *ba, enum tr_select tx_rx_select,
- u16 reason_code)
-{
- struct sk_buff *skb;
-
- skb = rtllib_DELBA(ieee, dst, ba, tx_rx_select, reason_code);
- if (skb)
- softmac_mgmt_xmit(skb, ieee);
- else
- netdev_dbg(ieee->dev, "Failed to generate DELBA packet.\n");
-}
-
-int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- struct ieee80211_hdr_3addr *req = NULL;
- u16 rc = 0;
- u8 *dst = NULL, *dialog_token = NULL, *tag = NULL;
- struct ba_record *ba = NULL;
- union ba_param_set *ba_param_set = NULL;
- u16 *ba_timeout_value = NULL;
- union sequence_control *ba_start_seq_ctrl = NULL;
- struct rx_ts_record *ts = NULL;
-
- if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) {
- netdev_warn(ieee->dev, "Invalid skb len in BAREQ(%d / %d)\n",
- (int)skb->len,
- (int)(sizeof(struct ieee80211_hdr_3addr) + 9));
- return -1;
- }
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, __func__,
- skb->data, skb->len);
-#endif
-
- req = (struct ieee80211_hdr_3addr *)skb->data;
- tag = (u8 *)req;
- dst = (u8 *)(&req->addr2[0]);
- tag += sizeof(struct ieee80211_hdr_3addr);
- dialog_token = tag + 2;
- ba_param_set = (union ba_param_set *)(tag + 3);
- ba_timeout_value = (u16 *)(tag + 5);
- ba_start_seq_ctrl = (union sequence_control *)(req + 7);
-
- if (!ieee->current_network.qos_data.active ||
- !ieee->ht_info->current_ht_support ||
- (ieee->ht_info->iot_action & HT_IOT_ACT_REJECT_ADDBA_REQ)) {
- rc = ADDBA_STATUS_REFUSED;
- netdev_warn(ieee->dev,
- "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n",
- ieee->current_network.qos_data.active,
- ieee->ht_info->current_ht_support);
- goto on_add_ba_req_fail;
- }
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)(ba_param_set->field.tid), RX_DIR, true)) {
- rc = ADDBA_STATUS_REFUSED;
- netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
- goto on_add_ba_req_fail;
- }
- ba = &ts->rx_admitted_ba_record;
-
- if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) {
- rc = ADDBA_STATUS_INVALID_PARAM;
- netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n",
- __func__);
- goto on_add_ba_req_fail;
- }
-
- rtllib_flush_rx_ts_pending_pkts(ieee, ts);
-
- deactivate_ba_entry(ieee, ba);
- ba->dialog_token = *dialog_token;
- ba->ba_param_set = *ba_param_set;
- ba->ba_timeout_value = *ba_timeout_value;
- ba->ba_start_seq_ctrl = *ba_start_seq_ctrl;
-
- if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev) ||
- (ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
- ba->ba_param_set.field.buffer_size = 1;
- else
- ba->ba_param_set.field.buffer_size = 32;
-
- activate_ba_entry(ba, 0);
- rtllib_send_add_ba_rsp(ieee, dst, ba, ADDBA_STATUS_SUCCESS);
-
- return 0;
-
-on_add_ba_req_fail:
- {
- struct ba_record BA;
-
- BA.ba_param_set = *ba_param_set;
- BA.ba_timeout_value = *ba_timeout_value;
- BA.dialog_token = *dialog_token;
- BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE;
- rtllib_send_add_ba_rsp(ieee, dst, &BA, rc);
- return 0;
- }
-}
-
-int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- struct ieee80211_hdr_3addr *rsp = NULL;
- struct ba_record *pending_ba, *admitted_ba;
- struct tx_ts_record *ts = NULL;
- u8 *dst = NULL, *dialog_token = NULL, *tag = NULL;
- u16 *status_code = NULL, *ba_timeout_value = NULL;
- union ba_param_set *ba_param_set = NULL;
- u16 reason_code;
-
- if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) {
- netdev_warn(ieee->dev, "Invalid skb len in BARSP(%d / %d)\n",
- (int)skb->len,
- (int)(sizeof(struct ieee80211_hdr_3addr) + 9));
- return -1;
- }
- rsp = (struct ieee80211_hdr_3addr *)skb->data;
- tag = (u8 *)rsp;
- dst = (u8 *)(&rsp->addr2[0]);
- tag += sizeof(struct ieee80211_hdr_3addr);
- dialog_token = tag + 2;
- status_code = (u16 *)(tag + 3);
- ba_param_set = (union ba_param_set *)(tag + 5);
- ba_timeout_value = (u16 *)(tag + 7);
-
- if (!ieee->current_network.qos_data.active ||
- !ieee->ht_info->current_ht_support ||
- !ieee->ht_info->current_ampdu_enable) {
- netdev_warn(ieee->dev,
- "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",
- ieee->current_network.qos_data.active,
- ieee->ht_info->current_ht_support,
- ieee->ht_info->current_ampdu_enable);
- reason_code = DELBA_REASON_UNKNOWN_BA;
- goto on_add_ba_rsp_reject;
- }
-
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)(ba_param_set->field.tid), TX_DIR, false)) {
- netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
- reason_code = DELBA_REASON_UNKNOWN_BA;
- goto on_add_ba_rsp_reject;
- }
-
- ts->add_ba_req_in_progress = false;
- pending_ba = &ts->tx_pending_ba_record;
- admitted_ba = &ts->tx_admitted_ba_record;
-
- if (admitted_ba->b_valid) {
- netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n",
- __func__);
- return -1;
- } else if (!pending_ba->b_valid ||
- (*dialog_token != pending_ba->dialog_token)) {
- netdev_warn(ieee->dev,
- "%s(): ADDBA Rsp. BA invalid, DELBA!\n",
- __func__);
- reason_code = DELBA_REASON_UNKNOWN_BA;
- goto on_add_ba_rsp_reject;
- } else {
- netdev_dbg(ieee->dev,
- "%s(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n",
- __func__, *status_code);
- deactivate_ba_entry(ieee, pending_ba);
- }
-
- if (*status_code == ADDBA_STATUS_SUCCESS) {
- if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) {
- ts->add_ba_req_delayed = true;
- deactivate_ba_entry(ieee, admitted_ba);
- reason_code = DELBA_REASON_END_BA;
- goto on_add_ba_rsp_reject;
- }
-
- admitted_ba->dialog_token = *dialog_token;
- admitted_ba->ba_timeout_value = *ba_timeout_value;
- admitted_ba->ba_start_seq_ctrl = pending_ba->ba_start_seq_ctrl;
- admitted_ba->ba_param_set = *ba_param_set;
- deactivate_ba_entry(ieee, admitted_ba);
- activate_ba_entry(admitted_ba, *ba_timeout_value);
- } else {
- ts->add_ba_req_delayed = true;
- ts->disable_add_ba = true;
- reason_code = DELBA_REASON_END_BA;
- goto on_add_ba_rsp_reject;
- }
-
- return 0;
-
-on_add_ba_rsp_reject:
- {
- struct ba_record BA;
-
- BA.ba_param_set = *ba_param_set;
- rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, reason_code);
- return 0;
- }
-}
-
-int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- struct ieee80211_hdr_3addr *delba = NULL;
- union delba_param_set *del_ba_param_set = NULL;
- u8 *dst = NULL;
-
- if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 6) {
- netdev_warn(ieee->dev, "Invalid skb len in DELBA(%d / %d)\n",
- (int)skb->len,
- (int)(sizeof(struct ieee80211_hdr_3addr) + 6));
- return -1;
- }
-
- if (!ieee->current_network.qos_data.active ||
- !ieee->ht_info->current_ht_support) {
- netdev_warn(ieee->dev,
- "received DELBA while QOS or HT is not supported(%d, %d)\n",
- ieee->current_network. qos_data.active,
- ieee->ht_info->current_ht_support);
- return -1;
- }
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
- __func__, skb->len);
-#endif
- delba = (struct ieee80211_hdr_3addr *)skb->data;
- dst = (u8 *)(&delba->addr2[0]);
- del_ba_param_set = (union delba_param_set *)&delba->seq_ctrl + 2;
-
- if (del_ba_param_set->field.initiator == 1) {
- struct rx_ts_record *ts;
-
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)del_ba_param_set->field.tid, RX_DIR, false)) {
- netdev_warn(ieee->dev,
- "%s(): can't get TS for RXTS. dst:%pM TID:%d\n",
- __func__, dst,
- (u8)del_ba_param_set->field.tid);
- return -1;
- }
-
- rx_ts_delete_ba(ieee, ts);
- } else {
- struct tx_ts_record *ts;
-
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)del_ba_param_set->field.tid, TX_DIR, false)) {
- netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n",
- __func__);
- return -1;
- }
-
- ts->using_ba = false;
- ts->add_ba_req_in_progress = false;
- ts->add_ba_req_delayed = false;
- del_timer_sync(&ts->ts_add_ba_timer);
- tx_ts_delete_ba(ieee, ts);
- }
- return 0;
-}
-
-void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
- u8 policy, u8 overwrite_pending)
-{
- struct ba_record *ba = &ts->tx_pending_ba_record;
-
- if (ba->b_valid && !overwrite_pending)
- return;
-
- deactivate_ba_entry(ieee, ba);
-
- ba->dialog_token++;
- ba->ba_param_set.field.amsdu_support = 0;
- ba->ba_param_set.field.ba_policy = policy;
- ba->ba_param_set.field.tid = ts->ts_common_info.tspec.ts_id;
- ba->ba_param_set.field.buffer_size = 32;
- ba->ba_timeout_value = 0;
- ba->ba_start_seq_ctrl.field.seq_num = (ts->tx_cur_seq + 3) % 4096;
-
- activate_ba_entry(ba, BA_SETUP_TIMEOUT);
-
- rtllib_send_add_ba_req(ieee, ts->ts_common_info.addr, ba);
-}
-
-void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
- struct ts_common_info *ts_common_info,
- enum tr_select tx_rx_select)
-{
- if (tx_rx_select == TX_DIR) {
- struct tx_ts_record *ts =
- (struct tx_ts_record *)ts_common_info;
-
- if (tx_ts_delete_ba(ieee, ts))
- rtllib_send_DELBA(ieee, ts_common_info->addr,
- (ts->tx_admitted_ba_record.b_valid) ?
- (&ts->tx_admitted_ba_record) :
- (&ts->tx_pending_ba_record),
- tx_rx_select, DELBA_REASON_END_BA);
- } else if (tx_rx_select == RX_DIR) {
- struct rx_ts_record *ts =
- (struct rx_ts_record *)ts_common_info;
- if (rx_ts_delete_ba(ieee, ts))
- rtllib_send_DELBA(ieee, ts_common_info->addr,
- &ts->rx_admitted_ba_record,
- tx_rx_select, DELBA_REASON_END_BA);
- }
-}
-
-void rtllib_ba_setup_timeout(struct timer_list *t)
-{
- struct tx_ts_record *ts = from_timer(ts, t,
- tx_pending_ba_record.timer);
-
- ts->add_ba_req_in_progress = false;
- ts->add_ba_req_delayed = true;
- ts->tx_pending_ba_record.b_valid = false;
-}
-
-void rtllib_tx_ba_inact_timeout(struct timer_list *t)
-{
- struct tx_ts_record *ts = from_timer(ts, t,
- tx_admitted_ba_record.timer);
- struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- tx_ts_records[ts->num]);
- tx_ts_delete_ba(ieee, ts);
- rtllib_send_DELBA(ieee, ts->ts_common_info.addr,
- &ts->tx_admitted_ba_record, TX_DIR,
- DELBA_REASON_TIMEOUT);
-}
-
-void rtllib_rx_ba_inact_timeout(struct timer_list *t)
-{
- struct rx_ts_record *ts = from_timer(ts, t,
- rx_admitted_ba_record.timer);
- struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- rx_ts_records[ts->num]);
-
- rx_ts_delete_ba(ieee, ts);
- rtllib_send_DELBA(ieee, ts->ts_common_info.addr,
- &ts->rx_admitted_ba_record, RX_DIR,
- DELBA_REASON_TIMEOUT);
-}
diff --git a/drivers/staging/rtl8192e/rtl819x_HT.h b/drivers/staging/rtl8192e/rtl819x_HT.h
deleted file mode 100644
index a6e0077630c7..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_HT.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _RTL819XU_HTTYPE_H_
-#define _RTL819XU_HTTYPE_H_
-
-#define MIMO_PS_STATIC 0
-
-#define sHTCLng 4
-
-enum ht_channel_width {
- HT_CHANNEL_WIDTH_20 = 0,
- HT_CHANNEL_WIDTH_20_40 = 1,
-};
-
-enum ht_extchnl_offset {
- HT_EXTCHNL_OFFSET_NO_EXT = 0,
- HT_EXTCHNL_OFFSET_UPPER = 1,
- HT_EXTCHNL_OFFSET_NO_DEF = 2,
- HT_EXTCHNL_OFFSET_LOWER = 3,
-};
-
-struct ht_capab_ele {
- u8 adv_coding:1;
- u8 chl_width:1;
- u8 mimo_pwr_save:2;
- u8 green_field:1;
- u8 short_gi_20mhz:1;
- u8 short_gi_40mhz:1;
- u8 tx_stbc:1;
- u8 rx_stbc:2;
- u8 delay_ba:1;
- u8 max_amsdu_size:1;
- u8 dss_cck:1;
- u8 PSMP:1;
- u8 Rsvd1:1;
- u8 lsig_txop_protect:1;
-
- u8 max_rx_ampdu_factor:2;
- u8 mpdu_density:3;
- u8 Rsvd2:3;
-
- u8 MCS[16];
-
- u16 ext_ht_cap_info;
-
- u8 TxBFCap[4];
-
- u8 ASCap;
-
-} __packed;
-
-struct ht_info_ele {
- u8 ControlChl;
-
- u8 ExtChlOffset:2;
- u8 RecommemdedTxWidth:1;
- u8 RIFS:1;
- u8 PSMPAccessOnly:1;
- u8 SrvIntGranularity:3;
-
- u8 opt_mode:2;
- u8 NonGFDevPresent:1;
- u8 Revd1:5;
- u8 Revd2:8;
-
- u8 Rsvd3:6;
- u8 DualBeacon:1;
- u8 DualCTSProtect:1;
-
- u8 SecondaryBeacon:1;
- u8 LSigTxopProtectFull:1;
- u8 PcoActive:1;
- u8 PcoPhase:1;
- u8 Rsvd4:4;
-
- u8 BasicMSC[16];
-} __packed;
-
-enum ht_spec_ver {
- HT_SPEC_VER_IEEE = 0,
- HT_SPEC_VER_EWC = 1,
-};
-
-enum ht_aggre_mode {
- HT_AGG_AUTO = 0,
- HT_AGG_FORCE_ENABLE = 1,
- HT_AGG_FORCE_DISABLE = 2,
-};
-
-struct rt_hi_throughput {
- u8 enable_ht;
- u8 current_ht_support;
- u8 cur_bw_40mhz;
- u8 cur_short_gi_40mhz;
- u8 cur_short_gi_20mhz;
- enum ht_spec_ver peer_ht_spec_ver;
- struct ht_capab_ele self_ht_cap;
- u8 peer_ht_cap_buf[32];
- u8 peer_ht_info_buf[32];
- u8 ampdu_enable;
- u8 current_ampdu_enable;
- u8 ampdu_factor;
- u8 current_ampdu_factor;
- u8 current_mpdu_density;
- u8 forced_ampdu_factor;
- u8 forced_mpdu_density;
- u8 current_op_mode;
- enum ht_extchnl_offset cur_sta_ext_chnl_offset;
- u8 cur_tx_bw40mhz;
- u8 sw_bw_in_progress;
- u8 current_rt2rt_aggregation;
- u8 current_rt2rt_long_slot_time;
- u8 sz_rt2rt_agg_buf[10];
- u8 cur_rx_reorder_enable;
- u8 rx_reorder_win_size;
- u8 rx_reorder_pending_time;
- u16 rx_reorder_drop_counter;
- u8 iot_peer;
- u32 iot_action;
- u8 iot_ra_func;
-} __packed;
-
-struct bss_ht {
- u8 bd_support_ht;
-
- u8 bd_ht_cap_buf[32];
- u16 bd_ht_cap_len;
- u8 bd_ht_info_buf[32];
- u16 bd_ht_info_len;
-
- enum ht_spec_ver bd_ht_spec_ver;
- enum ht_channel_width bd_bandwidth;
-
- u8 bd_rt2rt_aggregation;
- u8 bd_rt2rt_long_slot_time;
- u8 rt2rt_ht_mode;
- u8 bd_ht_1r;
-};
-
-extern u8 MCS_FILTER_ALL[16];
-extern u8 MCS_FILTER_1SS[16];
-
-#define RATE_ADPT_1SS_MASK 0xFF
-#define RATE_ADPT_2SS_MASK 0xF0
-#define RATE_ADPT_MCS32_MASK 0x01
-
-enum ht_aggre_size {
- HT_AGG_SIZE_8K = 0,
- HT_AGG_SIZE_16K = 1,
- HT_AGG_SIZE_32K = 2,
- HT_AGG_SIZE_64K = 3,
-};
-
-enum ht_iot_peer {
- HT_IOT_PEER_UNKNOWN = 0,
- HT_IOT_PEER_REALTEK = 1,
- HT_IOT_PEER_REALTEK_92SE = 2,
- HT_IOT_PEER_BROADCOM = 3,
- HT_IOT_PEER_RALINK = 4,
- HT_IOT_PEER_ATHEROS = 5,
- HT_IOT_PEER_CISCO = 6,
- HT_IOT_PEER_MARVELL = 7,
- HT_IOT_PEER_92U_SOFTAP = 8,
- HT_IOT_PEER_SELF_SOFTAP = 9,
- HT_IOT_PEER_AIRGO = 10,
- HT_IOT_PEER_MAX = 11,
-};
-
-enum ht_iot_action {
- HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001,
- HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002,
- HT_IOT_ACT_DISABLE_MCS14 = 0x00000004,
- HT_IOT_ACT_DISABLE_MCS15 = 0x00000008,
- HT_IOT_ACT_DISABLE_ALL_2SS = 0x00000010,
- HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000020,
- HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000040,
- HT_IOT_ACT_CDD_FSYNC = 0x00000080,
- HT_IOT_ACT_PURE_N_MODE = 0x00000100,
- HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200,
- HT_IOT_ACT_FORCED_RTS = 0x00000400,
- HT_IOT_ACT_AMSDU_ENABLE = 0x00000800,
- HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00001000,
- HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00002000,
- HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00004000,
-
- HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000,
- HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000,
- HT_IOT_ACT_DISABLE_HIGH_POWER = 0x00040000,
- HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000,
- HT_IOT_ACT_TX_NO_AGGREGATION = 0x00100000,
- HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000,
-
- HT_IOT_ACT_MID_HIGHPOWER = 0x00400000,
- HT_IOT_ACT_NULL_DATA_POWER_SAVING = 0x00800000,
-
- HT_IOT_ACT_DISABLE_CCK_RATE = 0x01000000,
- HT_IOT_ACT_FORCED_ENABLE_BE_TXOP = 0x02000000,
- HT_IOT_ACT_WA_IOT_Broadcom = 0x04000000,
-
- HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI = 0x08000000,
-
-};
-
-enum ht_iot_rafunc {
- HT_IOT_RAFUNC_DISABLE_ALL = 0x00,
- HT_IOT_RAFUNC_PEER_1R = 0x01,
- HT_IOT_RAFUNC_TX_AMSDU = 0x02,
-};
-
-enum rt_ht_capability {
- RT_HT_CAP_USE_TURBO_AGGR = 0x01,
- RT_HT_CAP_USE_LONG_PREAMBLE = 0x02,
- RT_HT_CAP_USE_AMPDU = 0x04,
- RT_HT_CAP_USE_WOW = 0x8,
- RT_HT_CAP_USE_SOFTAP = 0x10,
- RT_HT_CAP_USE_92SE = 0x20,
-};
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c
deleted file mode 100644
index 9c9c0bc0cfde..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_HTProc.c
+++ /dev/null
@@ -1,699 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtllib.h"
-#include "rtl819x_HT.h"
-u8 MCS_FILTER_ALL[16] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-u8 MCS_FILTER_1SS[16] = {
- 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-;
-
-u16 MCS_DATA_RATE[2][2][77] = {
- {{13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234,
- 260, 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416,
- 468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182,
- 182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156,
- 181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273,
- 312, 351, 312, 351, 390, 390, 429},
- {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289,
- 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520,
- 578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231,
- 173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260,
- 231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390,
- 433, 433, 477} },
- {{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486,
- 540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648,
- 864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324,
- 378, 378, 432, 324, 405, 405, 486, 567, 567, 648, 270, 324, 378, 324,
- 378, 432, 486, 432, 486, 540, 540, 594, 405, 486, 567, 486, 567, 648,
- 729, 648, 729, 810, 810, 891},
- {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540,
- 600, 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720,
- 960, 1080, 1200, 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360,
- 420, 420, 480, 360, 450, 450, 540, 630, 630, 720, 300, 360, 420, 360,
- 420, 480, 540, 480, 540, 600, 600, 660, 450, 540, 630, 540, 630, 720,
- 810, 720, 810, 900, 900, 990} }
-};
-
-static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf};
-
-static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70};
-
-static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e};
-
-static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f};
-
-static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf};
-
-static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc};
-
-static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e};
-
-static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02};
-
-static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0};
-
-static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91};
-
-static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94};
-
-static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4};
-
-void ht_update_default_setting(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- ht_info->ampdu_enable = 1;
- ht_info->ampdu_factor = 2;
-
- ieee->tx_dis_rate_fallback = 0;
- ieee->tx_use_drv_assinged_rate = 0;
-
- ieee->tx_enable_fw_calc_dur = 1;
-
- ht_info->rx_reorder_win_size = 64;
- ht_info->rx_reorder_pending_time = 30;
-}
-
-static u16 ht_mcs_to_data_rate(struct rtllib_device *ieee, u8 mcs_rate)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- u8 is40MHz = (ht_info->cur_bw_40mhz) ? 1 : 0;
- u8 isShortGI = (ht_info->cur_bw_40mhz) ?
- ((ht_info->cur_short_gi_40mhz) ? 1 : 0) :
- ((ht_info->cur_short_gi_20mhz) ? 1 : 0);
- return MCS_DATA_RATE[is40MHz][isShortGI][(mcs_rate & 0x7f)];
-}
-
-u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 data_rate)
-{
- u16 cck_of_dm_rate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18,
- 0x24, 0x30, 0x48, 0x60, 0x6c};
- u8 is40MHz = 0;
- u8 isShortGI = 0;
-
- if (data_rate < 12)
- return cck_of_dm_rate[data_rate];
- if (data_rate >= 0x10 && data_rate <= 0x1f) {
- is40MHz = 0;
- isShortGI = 0;
- } else if (data_rate >= 0x20 && data_rate <= 0x2f) {
- is40MHz = 1;
- isShortGI = 0;
- } else if (data_rate >= 0x30 && data_rate <= 0x3f) {
- is40MHz = 0;
- isShortGI = 1;
- } else if (data_rate >= 0x40 && data_rate <= 0x4f) {
- is40MHz = 1;
- isShortGI = 1;
- }
- return MCS_DATA_RATE[is40MHz][isShortGI][data_rate & 0xf];
-}
-
-bool is_ht_half_nmode_aps(struct rtllib_device *ieee)
-{
- bool retValue = false;
- struct rtllib_network *net = &ieee->current_network;
-
- if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) ||
- (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) ||
- (memcmp(net->bssid, PCI_RALINK, 3) == 0) ||
- (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) ||
- (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) ||
- (net->ralink_cap_exist))
- retValue = true;
- else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) ||
- !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) ||
- !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) ||
- (net->broadcom_cap_exist))
- retValue = true;
- else if (net->bssht.bd_rt2rt_aggregation)
- retValue = true;
- else
- retValue = false;
-
- return retValue;
-}
-
-static void ht_iot_peer_determine(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct rtllib_network *net = &ieee->current_network;
-
- if (net->bssht.bd_rt2rt_aggregation) {
- ht_info->iot_peer = HT_IOT_PEER_REALTEK;
- if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_92SE)
- ht_info->iot_peer = HT_IOT_PEER_REALTEK_92SE;
- if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_SOFTAP)
- ht_info->iot_peer = HT_IOT_PEER_92U_SOFTAP;
- } else if (net->broadcom_cap_exist) {
- ht_info->iot_peer = HT_IOT_PEER_BROADCOM;
- } else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) ||
- !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) ||
- !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) {
- ht_info->iot_peer = HT_IOT_PEER_BROADCOM;
- } else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) ||
- (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) ||
- (memcmp(net->bssid, PCI_RALINK, 3) == 0) ||
- (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) ||
- (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) ||
- net->ralink_cap_exist) {
- ht_info->iot_peer = HT_IOT_PEER_RALINK;
- } else if ((net->atheros_cap_exist) ||
- (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) ||
- (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) {
- ht_info->iot_peer = HT_IOT_PEER_ATHEROS;
- } else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) ||
- net->cisco_cap_exist) {
- ht_info->iot_peer = HT_IOT_PEER_CISCO;
- } else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) ||
- net->marvell_cap_exist) {
- ht_info->iot_peer = HT_IOT_PEER_MARVELL;
- } else if (net->airgo_cap_exist) {
- ht_info->iot_peer = HT_IOT_PEER_AIRGO;
- } else {
- ht_info->iot_peer = HT_IOT_PEER_UNKNOWN;
- }
-
- netdev_dbg(ieee->dev, "IOTPEER: %x\n", ht_info->iot_peer);
-}
-
-static u8 ht_iot_act_is_mgnt_use_cck_6m(struct rtllib_device *ieee,
- struct rtllib_network *network)
-{
- u8 retValue = 0;
-
- if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM)
- retValue = 1;
-
- return retValue;
-}
-
-static u8 ht_iot_act_is_ccd_fsync(struct rtllib_device *ieee)
-{
- u8 retValue = 0;
-
- if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM)
- retValue = 1;
- return retValue;
-}
-
-static void ht_iot_act_determine_ra_func(struct rtllib_device *ieee, bool bPeerRx2ss)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- ht_info->iot_ra_func &= HT_IOT_RAFUNC_DISABLE_ALL;
-
- if (ht_info->iot_peer == HT_IOT_PEER_RALINK && !bPeerRx2ss)
- ht_info->iot_ra_func |= HT_IOT_RAFUNC_PEER_1R;
-
- if (ht_info->iot_action & HT_IOT_ACT_AMSDU_ENABLE)
- ht_info->iot_ra_func |= HT_IOT_RAFUNC_TX_AMSDU;
-}
-
-void ht_reset_iot_setting(struct rt_hi_throughput *ht_info)
-{
- ht_info->iot_action = 0;
- ht_info->iot_peer = HT_IOT_PEER_UNKNOWN;
- ht_info->iot_ra_func = 0;
-}
-
-void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap,
- u8 *len, u8 is_encrypt, bool assoc)
-{
- struct rt_hi_throughput *ht = ieee->ht_info;
- struct ht_capab_ele *cap_ele = NULL;
-
- if (!pos_ht_cap || !ht) {
- netdev_warn(ieee->dev,
- "%s(): pos_ht_cap and ht_info are null\n", __func__);
- return;
- }
- memset(pos_ht_cap, 0, *len);
-
- if ((assoc) && (ht->peer_ht_spec_ver == HT_SPEC_VER_EWC)) {
- static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 };
-
- memcpy(pos_ht_cap, EWC11NHTCap, sizeof(EWC11NHTCap));
- cap_ele = (struct ht_capab_ele *)&pos_ht_cap[4];
- *len = 30 + 2;
- } else {
- cap_ele = (struct ht_capab_ele *)pos_ht_cap;
- *len = 26 + 2;
- }
-
- cap_ele->adv_coding = 0;
- if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
- cap_ele->chl_width = 0;
- else
- cap_ele->chl_width = 1;
-
- cap_ele->mimo_pwr_save = 3;
- cap_ele->green_field = 0;
- cap_ele->short_gi_20mhz = 1;
- cap_ele->short_gi_40mhz = 1;
-
- cap_ele->tx_stbc = 1;
- cap_ele->rx_stbc = 0;
- cap_ele->delay_ba = 0;
- cap_ele->max_amsdu_size = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0;
- cap_ele->dss_cck = 1;
- cap_ele->PSMP = 0;
- cap_ele->lsig_txop_protect = 0;
-
- netdev_dbg(ieee->dev,
- "TX HT cap/info ele BW=%d max_amsdu_size:%d dss_cck:%d\n",
- cap_ele->chl_width, cap_ele->max_amsdu_size, cap_ele->dss_cck);
-
- if (is_encrypt) {
- cap_ele->mpdu_density = 7;
- cap_ele->max_rx_ampdu_factor = 2;
- } else {
- cap_ele->max_rx_ampdu_factor = 3;
- cap_ele->mpdu_density = 0;
- }
-
- memcpy(cap_ele->MCS, ieee->reg_dot11ht_oper_rate_set, 16);
- memset(&cap_ele->ext_ht_cap_info, 0, 2);
- memset(cap_ele->TxBFCap, 0, 4);
-
- cap_ele->ASCap = 0;
-
- if (assoc) {
- if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS15)
- cap_ele->MCS[1] &= 0x7f;
-
- if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS14)
- cap_ele->MCS[1] &= 0xbf;
-
- if (ht->iot_action & HT_IOT_ACT_DISABLE_ALL_2SS)
- cap_ele->MCS[1] &= 0x00;
-
- if (ht->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI)
- cap_ele->short_gi_40mhz = 0;
-
- if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) {
- cap_ele->chl_width = 0;
- cap_ele->MCS[1] = 0;
- }
- }
-}
-
-void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg,
- u8 *len)
-{
- if (!posRT2RTAgg) {
- netdev_warn(ieee->dev, "%s(): posRT2RTAgg is null\n", __func__);
- return;
- }
- memset(posRT2RTAgg, 0, *len);
- *posRT2RTAgg++ = 0x00;
- *posRT2RTAgg++ = 0xe0;
- *posRT2RTAgg++ = 0x4c;
- *posRT2RTAgg++ = 0x02;
- *posRT2RTAgg++ = 0x01;
-
- *posRT2RTAgg = 0x30;
-
- if (ieee->bSupportRemoteWakeUp)
- *posRT2RTAgg |= RT_HT_CAP_USE_WOW;
-
- *len = 6 + 2;
-}
-
-static u8 ht_pick_mcs_rate(struct rtllib_device *ieee, u8 *pOperateMCS)
-{
- u8 i;
-
- if (!pOperateMCS) {
- netdev_warn(ieee->dev, "%s(): pOperateMCS is null\n", __func__);
- return false;
- }
-
- switch (ieee->mode) {
- case WIRELESS_MODE_B:
- case WIRELESS_MODE_G:
- for (i = 0; i <= 15; i++)
- pOperateMCS[i] = 0;
- break;
- case WIRELESS_MODE_N_24G:
- pOperateMCS[0] &= RATE_ADPT_1SS_MASK;
- pOperateMCS[1] &= RATE_ADPT_2SS_MASK;
- pOperateMCS[3] &= RATE_ADPT_MCS32_MASK;
- break;
- default:
- break;
- }
-
- return true;
-}
-
-u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet,
- u8 *pMCSFilter)
-{
- u8 i, j;
- u8 bitMap;
- u8 mcsRate = 0;
- u8 availableMcsRate[16];
-
- if (!pMCSRateSet || !pMCSFilter) {
- netdev_warn(ieee->dev,
- "%s(): pMCSRateSet and pMCSFilter are null\n",
- __func__);
- return false;
- }
- for (i = 0; i < 16; i++)
- availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i];
-
- for (i = 0; i < 16; i++) {
- if (availableMcsRate[i] != 0)
- break;
- }
- if (i == 16)
- return false;
-
- for (i = 0; i < 16; i++) {
- if (availableMcsRate[i] != 0) {
- bitMap = availableMcsRate[i];
- for (j = 0; j < 8; j++) {
- if ((bitMap % 2) != 0) {
- if (ht_mcs_to_data_rate(ieee, (8 * i + j)) >
- ht_mcs_to_data_rate(ieee, mcsRate))
- mcsRate = 8 * i + j;
- }
- bitMap >>= 1;
- }
- }
- }
- return mcsRate | 0x80;
-}
-
-static u8 ht_filter_mcs_rate(struct rtllib_device *ieee, u8 *pSupportMCS,
- u8 *pOperateMCS)
-{
- u8 i;
-
- for (i = 0; i <= 15; i++)
- pOperateMCS[i] = ieee->reg_dot11tx_ht_oper_rate_set[i] &
- pSupportMCS[i];
-
- ht_pick_mcs_rate(ieee, pOperateMCS);
-
- if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
- pOperateMCS[1] = 0;
-
- for (i = 2; i <= 15; i++)
- pOperateMCS[i] = 0;
-
- return true;
-}
-
-void ht_set_connect_bw_mode(struct rtllib_device *ieee,
- enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset);
-
-void ht_on_assoc_rsp(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct ht_capab_ele *pPeerHTCap = NULL;
- struct ht_info_ele *pPeerHTInfo = NULL;
- u8 *pMcsFilter = NULL;
-
- static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 };
- static const u8 EWC11NHTInfo[] = { 0x00, 0x90, 0x4c, 0x34 };
-
- if (!ht_info->current_ht_support) {
- netdev_warn(ieee->dev, "%s(): HT_DISABLE\n", __func__);
- return;
- }
- netdev_dbg(ieee->dev, "%s(): HT_ENABLE\n", __func__);
-
- if (!memcmp(ht_info->peer_ht_cap_buf, EWC11NHTCap, sizeof(EWC11NHTCap)))
- pPeerHTCap = (struct ht_capab_ele *)(&ht_info->peer_ht_cap_buf[4]);
- else
- pPeerHTCap = (struct ht_capab_ele *)(ht_info->peer_ht_cap_buf);
-
- if (!memcmp(ht_info->peer_ht_info_buf, EWC11NHTInfo, sizeof(EWC11NHTInfo)))
- pPeerHTInfo = (struct ht_info_ele *)
- (&ht_info->peer_ht_info_buf[4]);
- else
- pPeerHTInfo = (struct ht_info_ele *)(ht_info->peer_ht_info_buf);
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE,
- pPeerHTCap, sizeof(struct ht_capab_ele));
-#endif
- ht_set_connect_bw_mode(ieee, (enum ht_channel_width)(pPeerHTCap->chl_width),
- (enum ht_extchnl_offset)(pPeerHTInfo->ExtChlOffset));
- ht_info->cur_tx_bw40mhz = ((pPeerHTInfo->RecommemdedTxWidth == 1) ?
- true : false);
-
- ht_info->cur_short_gi_20mhz = ((pPeerHTCap->short_gi_20mhz == 1) ? true : false);
- ht_info->cur_short_gi_40mhz = ((pPeerHTCap->short_gi_40mhz == 1) ? true : false);
-
- ht_info->current_ampdu_enable = ht_info->ampdu_enable;
- if (ieee->rtllib_ap_sec_type &&
- (ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_WEP | SEC_ALG_TKIP))) {
- if ((ht_info->iot_peer == HT_IOT_PEER_ATHEROS) ||
- (ht_info->iot_peer == HT_IOT_PEER_UNKNOWN))
- ht_info->current_ampdu_enable = false;
- }
-
- if (ieee->current_network.bssht.bd_rt2rt_aggregation) {
- if (ieee->pairwise_key_type != KEY_TYPE_NA)
- ht_info->current_ampdu_factor =
- pPeerHTCap->max_rx_ampdu_factor;
- else
- ht_info->current_ampdu_factor = HT_AGG_SIZE_64K;
- } else {
- ht_info->current_ampdu_factor = min_t(u32, pPeerHTCap->max_rx_ampdu_factor,
- HT_AGG_SIZE_32K);
- }
-
- ht_info->current_mpdu_density = pPeerHTCap->mpdu_density;
- if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K)
- ht_info->current_ampdu_enable = false;
-
- ht_info->cur_rx_reorder_enable = 1;
-
- if (pPeerHTCap->MCS[0] == 0)
- pPeerHTCap->MCS[0] = 0xff;
-
- ht_iot_act_determine_ra_func(ieee, ((pPeerHTCap->MCS[1]) != 0));
-
- ht_filter_mcs_rate(ieee, pPeerHTCap->MCS, ieee->dot11ht_oper_rate_set);
-
- pMcsFilter = MCS_FILTER_ALL;
- ieee->HTHighestOperaRate = ht_get_highest_mcs_rate(ieee,
- ieee->dot11ht_oper_rate_set,
- pMcsFilter);
- ieee->ht_curr_op_rate = ieee->HTHighestOperaRate;
-
- ht_info->current_op_mode = pPeerHTInfo->opt_mode;
-}
-
-void ht_initialize_ht_info(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- ht_info->current_ht_support = false;
-
- ht_info->cur_bw_40mhz = false;
- ht_info->cur_tx_bw40mhz = false;
-
- ht_info->cur_short_gi_20mhz = false;
- ht_info->cur_short_gi_40mhz = false;
-
- ht_info->current_mpdu_density = 0;
- ht_info->current_ampdu_factor = ht_info->ampdu_factor;
-
- memset((void *)(&ht_info->self_ht_cap), 0,
- sizeof(ht_info->self_ht_cap));
- memset((void *)(&ht_info->peer_ht_cap_buf), 0,
- sizeof(ht_info->peer_ht_cap_buf));
- memset((void *)(&ht_info->peer_ht_info_buf), 0,
- sizeof(ht_info->peer_ht_info_buf));
-
- ht_info->sw_bw_in_progress = false;
-
- ht_info->peer_ht_spec_ver = HT_SPEC_VER_IEEE;
-
- ht_info->current_rt2rt_aggregation = false;
- ht_info->current_rt2rt_long_slot_time = false;
-
- ht_info->iot_peer = 0;
- ht_info->iot_action = 0;
- ht_info->iot_ra_func = 0;
-
- {
- u8 *RegHTSuppRateSets = &ieee->reg_ht_supp_rate_set[0];
-
- RegHTSuppRateSets[0] = 0xFF;
- RegHTSuppRateSets[1] = 0xFF;
- RegHTSuppRateSets[4] = 0x01;
- }
-}
-
-void ht_initialize_bss_desc(struct bss_ht *bss_ht)
-{
- bss_ht->bd_support_ht = false;
- memset(bss_ht->bd_ht_cap_buf, 0, sizeof(bss_ht->bd_ht_cap_buf));
- bss_ht->bd_ht_cap_len = 0;
- memset(bss_ht->bd_ht_info_buf, 0, sizeof(bss_ht->bd_ht_info_buf));
- bss_ht->bd_ht_info_len = 0;
-
- bss_ht->bd_ht_spec_ver = HT_SPEC_VER_IEEE;
-
- bss_ht->bd_rt2rt_aggregation = false;
- bss_ht->bd_rt2rt_long_slot_time = false;
- bss_ht->rt2rt_ht_mode = (enum rt_ht_capability)0;
-}
-
-void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee,
- struct rtllib_network *network)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- u8 bIOTAction = 0;
-
- /* unmark enable_ht flag here is the same reason why unmarked in
- * function rtllib_softmac_new_net. WB 2008.09.10
- */
- if (network->bssht.bd_support_ht) {
- ht_info->current_ht_support = true;
- ht_info->peer_ht_spec_ver = network->bssht.bd_ht_spec_ver;
-
- if (network->bssht.bd_ht_cap_len > 0 &&
- network->bssht.bd_ht_cap_len <= sizeof(ht_info->peer_ht_cap_buf))
- memcpy(ht_info->peer_ht_cap_buf,
- network->bssht.bd_ht_cap_buf,
- network->bssht.bd_ht_cap_len);
-
- if (network->bssht.bd_ht_info_len > 0 &&
- network->bssht.bd_ht_info_len <=
- sizeof(ht_info->peer_ht_info_buf))
- memcpy(ht_info->peer_ht_info_buf,
- network->bssht.bd_ht_info_buf,
- network->bssht.bd_ht_info_len);
-
- ht_info->current_rt2rt_aggregation =
- network->bssht.bd_rt2rt_aggregation;
- ht_info->current_rt2rt_long_slot_time =
- network->bssht.bd_rt2rt_long_slot_time;
-
- ht_iot_peer_determine(ieee);
-
- ht_info->iot_action = 0;
- bIOTAction = ht_iot_act_is_mgnt_use_cck_6m(ieee, network);
- if (bIOTAction)
- ht_info->iot_action |= HT_IOT_ACT_MGNT_USE_CCK_6M;
- bIOTAction = ht_iot_act_is_ccd_fsync(ieee);
- if (bIOTAction)
- ht_info->iot_action |= HT_IOT_ACT_CDD_FSYNC;
- } else {
- ht_info->current_ht_support = false;
- ht_info->current_rt2rt_aggregation = false;
- ht_info->current_rt2rt_long_slot_time = false;
-
- ht_info->iot_action = 0;
- ht_info->iot_ra_func = 0;
- }
-}
-
-void HT_update_self_and_peer_setting(struct rtllib_device *ieee,
- struct rtllib_network *network)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct ht_info_ele *pPeerHTInfo =
- (struct ht_info_ele *)network->bssht.bd_ht_info_buf;
-
- if (ht_info->current_ht_support) {
- if (network->bssht.bd_ht_info_len != 0)
- ht_info->current_op_mode = pPeerHTInfo->opt_mode;
- }
-}
-EXPORT_SYMBOL(HT_update_self_and_peer_setting);
-
-u8 ht_c_check(struct rtllib_device *ieee, u8 *frame)
-{
- if (ieee->ht_info->current_ht_support) {
- if ((is_qos_data_frame(frame) && frame_order(frame)) == 1) {
- netdev_dbg(ieee->dev, "HT CONTROL FILED EXIST!!\n");
- return true;
- }
- }
- return false;
-}
-
-static void ht_set_connect_bw_mode_callback(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- if (ht_info->cur_bw_40mhz) {
- if (ht_info->cur_sta_ext_chnl_offset == HT_EXTCHNL_OFFSET_UPPER)
- ieee->set_chan(ieee->dev,
- ieee->current_network.channel + 2);
- else if (ht_info->cur_sta_ext_chnl_offset ==
- HT_EXTCHNL_OFFSET_LOWER)
- ieee->set_chan(ieee->dev,
- ieee->current_network.channel - 2);
- else
- ieee->set_chan(ieee->dev,
- ieee->current_network.channel);
-
- ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20_40,
- ht_info->cur_sta_ext_chnl_offset);
- } else {
- ieee->set_chan(ieee->dev, ieee->current_network.channel);
- ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20,
- HT_EXTCHNL_OFFSET_NO_EXT);
- }
-
- ht_info->sw_bw_in_progress = false;
-}
-
-void ht_set_connect_bw_mode(struct rtllib_device *ieee,
- enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
- bandwidth = HT_CHANNEL_WIDTH_20;
-
- if (ht_info->sw_bw_in_progress) {
- pr_info("%s: sw_bw_in_progress!!\n", __func__);
- return;
- }
- if (bandwidth == HT_CHANNEL_WIDTH_20_40) {
- if (ieee->current_network.channel < 2 &&
- Offset == HT_EXTCHNL_OFFSET_LOWER)
- Offset = HT_EXTCHNL_OFFSET_NO_EXT;
- if (Offset == HT_EXTCHNL_OFFSET_UPPER ||
- Offset == HT_EXTCHNL_OFFSET_LOWER) {
- ht_info->cur_bw_40mhz = true;
- ht_info->cur_sta_ext_chnl_offset = Offset;
- } else {
- ht_info->cur_bw_40mhz = false;
- ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT;
- }
- } else {
- ht_info->cur_bw_40mhz = false;
- ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT;
- }
-
- netdev_dbg(ieee->dev, "%s():ht_info->bCurBW40MHz:%x\n", __func__,
- ht_info->cur_bw_40mhz);
-
- ht_info->sw_bw_in_progress = true;
-
- ht_set_connect_bw_mode_callback(ieee);
-}
diff --git a/drivers/staging/rtl8192e/rtl819x_Qos.h b/drivers/staging/rtl8192e/rtl819x_Qos.h
deleted file mode 100644
index dc991100742f..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_Qos.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef __INC_QOS_TYPE_H
-#define __INC_QOS_TYPE_H
-
-struct qos_tsinfo {
- u8 ts_id:4;
- u8 ucDirection:2;
-};
-
-struct octet_string {
- u8 *octet;
- u16 Length;
-};
-
-#define AC0_BE 0
-#define AC1_BK 1
-#define AC2_VI 2
-#define AC3_VO 3
-
-enum direction_value {
- DIR_UP = 0,
- DIR_DOWN = 1,
- DIR_DIRECT = 2,
- DIR_BI_DIR = 3,
-};
-
-union aci_aifsn {
- u8 charData;
-
- struct {
- u8 AIFSN:4;
- u8 acm:1;
- u8 ACI:2;
- u8 Reserved:1;
- } f;
-};
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_TS.h b/drivers/staging/rtl8192e/rtl819x_TS.h
deleted file mode 100644
index 5b0e4cb572d2..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_TS.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#ifndef _TSTYPE_H_
-#define _TSTYPE_H_
-#include "rtl819x_Qos.h"
-#define TS_ADDBA_DELAY 60
-
-#define TOTAL_TS_NUM 16
-
-enum tr_select {
- TX_DIR = 0,
- RX_DIR = 1,
-};
-
-struct ts_common_info {
- struct list_head list;
- u8 addr[ETH_ALEN];
- struct qos_tsinfo tspec;
-};
-
-struct tx_ts_record {
- struct ts_common_info ts_common_info;
- u16 tx_cur_seq;
- struct ba_record tx_pending_ba_record;
- struct ba_record tx_admitted_ba_record;
- u8 add_ba_req_in_progress;
- u8 add_ba_req_delayed;
- u8 using_ba;
- u8 disable_add_ba;
- struct timer_list ts_add_ba_timer;
- u8 num;
-};
-
-struct rx_ts_record {
- struct ts_common_info ts_common_info;
- u16 rx_indicate_seq;
- u16 rx_timeout_indicate_seq;
- struct list_head rx_pending_pkt_list;
- struct timer_list rx_pkt_pending_timer;
- struct ba_record rx_admitted_ba_record;
- u16 rx_last_seq_num;
- u8 rx_last_frag_num;
- u8 num;
-};
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c
deleted file mode 100644
index 89092cd434de..000000000000
--- a/drivers/staging/rtl8192e/rtl819x_TSProc.c
+++ /dev/null
@@ -1,450 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information: wlanfae <wlanfae@realtek.com>
- */
-#include "rtllib.h"
-#include <linux/etherdevice.h>
-#include "rtl819x_TS.h"
-
-static void RxPktPendingTimeout(struct timer_list *t)
-{
- struct rx_ts_record *ts = from_timer(ts, t, rx_pkt_pending_timer);
- struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- rx_ts_records[ts->num]);
-
- struct rx_reorder_entry *reorder_entry = NULL;
-
- unsigned long flags = 0;
- u8 index = 0;
- bool pkt_in_buf = false;
-
- spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
- if (ts->rx_timeout_indicate_seq != 0xffff) {
- while (!list_empty(&ts->rx_pending_pkt_list)) {
- reorder_entry = (struct rx_reorder_entry *)
- list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, list);
- if (index == 0)
- ts->rx_indicate_seq = reorder_entry->seq_num;
-
- if (SN_LESS(reorder_entry->seq_num,
- ts->rx_indicate_seq) ||
- SN_EQUAL(reorder_entry->seq_num,
- ts->rx_indicate_seq)) {
- list_del_init(&reorder_entry->list);
-
- if (SN_EQUAL(reorder_entry->seq_num,
- ts->rx_indicate_seq))
- ts->rx_indicate_seq =
- (ts->rx_indicate_seq + 1) % 4096;
-
- netdev_dbg(ieee->dev,
- "%s(): Indicate seq_num: %d\n",
- __func__, reorder_entry->seq_num);
- ieee->stats_IndicateArray[index] =
- reorder_entry->prxb;
- index++;
-
- list_add_tail(&reorder_entry->list,
- &ieee->RxReorder_Unused_List);
- } else {
- pkt_in_buf = true;
- break;
- }
- }
- }
-
- if (index > 0) {
- ts->rx_timeout_indicate_seq = 0xffff;
-
- if (index > REORDER_WIN_SIZE) {
- netdev_warn(ieee->dev,
- "%s(): Rx Reorder struct buffer full\n",
- __func__);
- spin_unlock_irqrestore(&(ieee->reorder_spinlock),
- flags);
- return;
- }
- rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index);
- pkt_in_buf = false;
- }
-
- if (pkt_in_buf && (ts->rx_timeout_indicate_seq == 0xffff)) {
- ts->rx_timeout_indicate_seq = ts->rx_indicate_seq;
- mod_timer(&ts->rx_pkt_pending_timer, jiffies +
- msecs_to_jiffies(ieee->ht_info->rx_reorder_pending_time)
- );
- }
- spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
-}
-
-static void TsAddBaProcess(struct timer_list *t)
-{
- struct tx_ts_record *ts = from_timer(ts, t, ts_add_ba_timer);
- u8 num = ts->num;
- struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- tx_ts_records[num]);
-
- rtllib_ts_init_add_ba(ieee, ts, BA_POLICY_IMMEDIATE, false);
- netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
-}
-
-static void ResetTsCommonInfo(struct ts_common_info *ts_common_info)
-{
- eth_zero_addr(ts_common_info->addr);
- memset(&ts_common_info->tspec, 0, sizeof(struct qos_tsinfo));
-}
-
-static void ResetTxTsEntry(struct tx_ts_record *ts)
-{
- ResetTsCommonInfo(&ts->ts_common_info);
- ts->tx_cur_seq = 0;
- ts->add_ba_req_in_progress = false;
- ts->add_ba_req_delayed = false;
- ts->using_ba = false;
- ts->disable_add_ba = false;
- rtllib_reset_ba_entry(&ts->tx_admitted_ba_record);
- rtllib_reset_ba_entry(&ts->tx_pending_ba_record);
-}
-
-static void ResetRxTsEntry(struct rx_ts_record *ts)
-{
- ResetTsCommonInfo(&ts->ts_common_info);
- ts->rx_indicate_seq = 0xffff;
- ts->rx_timeout_indicate_seq = 0xffff;
- rtllib_reset_ba_entry(&ts->rx_admitted_ba_record);
-}
-
-void rtllib_ts_init(struct rtllib_device *ieee)
-{
- struct tx_ts_record *pTxTS = ieee->tx_ts_records;
- struct rx_ts_record *rxts = ieee->rx_ts_records;
- struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
- u8 count = 0;
-
- INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
- INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
- INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
-
- for (count = 0; count < TOTAL_TS_NUM; count++) {
- pTxTS->num = count;
- timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0);
-
- timer_setup(&pTxTS->tx_pending_ba_record.timer, rtllib_ba_setup_timeout,
- 0);
- timer_setup(&pTxTS->tx_admitted_ba_record.timer,
- rtllib_tx_ba_inact_timeout, 0);
-
- ResetTxTsEntry(pTxTS);
- list_add_tail(&pTxTS->ts_common_info.list,
- &ieee->Tx_TS_Unused_List);
- pTxTS++;
- }
-
- INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
- INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
- INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
- for (count = 0; count < TOTAL_TS_NUM; count++) {
- rxts->num = count;
- INIT_LIST_HEAD(&rxts->rx_pending_pkt_list);
- timer_setup(&rxts->rx_admitted_ba_record.timer,
- rtllib_rx_ba_inact_timeout, 0);
-
- timer_setup(&rxts->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
-
- ResetRxTsEntry(rxts);
- list_add_tail(&rxts->ts_common_info.list,
- &ieee->Rx_TS_Unused_List);
- rxts++;
- }
- INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
- for (count = 0; count < REORDER_ENTRY_NUM; count++) {
- list_add_tail(&pRxReorderEntry->list,
- &ieee->RxReorder_Unused_List);
- if (count == (REORDER_ENTRY_NUM - 1))
- break;
- pRxReorderEntry = &ieee->RxReorderEntry[count + 1];
- }
-}
-
-static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
- u8 *addr, u8 TID,
- enum tr_select tx_rx_select)
-{
- u8 dir;
- bool search_dir[4] = {0};
- struct list_head *psearch_list;
- struct ts_common_info *pRet = NULL;
-
- if (tx_rx_select == TX_DIR) {
- search_dir[DIR_UP] = true;
- search_dir[DIR_BI_DIR] = true;
- search_dir[DIR_DIRECT] = true;
- } else {
- search_dir[DIR_DOWN] = true;
- search_dir[DIR_BI_DIR] = true;
- search_dir[DIR_DIRECT] = true;
- }
-
- if (tx_rx_select == TX_DIR)
- psearch_list = &ieee->Tx_TS_Admit_List;
- else
- psearch_list = &ieee->Rx_TS_Admit_List;
-
- for (dir = 0; dir <= DIR_BI_DIR; dir++) {
- if (!search_dir[dir])
- continue;
- list_for_each_entry(pRet, psearch_list, list) {
- if (memcmp(pRet->addr, addr, 6) == 0 &&
- pRet->tspec.ts_id == TID &&
- pRet->tspec.ucDirection == dir)
- break;
- }
- if (&pRet->list != psearch_list)
- break;
- }
-
- if (pRet && &pRet->list != psearch_list)
- return pRet;
- return NULL;
-}
-
-static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr,
- struct qos_tsinfo *pTSPEC)
-{
- if (!ts_common_info)
- return;
-
- memcpy(ts_common_info->addr, addr, 6);
-
- if (pTSPEC)
- memcpy((u8 *)(&(ts_common_info->tspec)), (u8 *)pTSPEC,
- sizeof(struct qos_tsinfo));
-}
-
-bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
- u8 *addr, u8 TID, enum tr_select tx_rx_select, bool add_new_ts)
-{
- u8 UP = 0;
- struct qos_tsinfo tspec;
- struct qos_tsinfo *ts_info = &tspec;
- struct list_head *pUnusedList;
- struct list_head *pAddmitList;
- enum direction_value Dir;
-
- if (is_multicast_ether_addr(addr)) {
- netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n");
- return false;
- }
- if (ieee->current_network.qos_data.supported == 0) {
- UP = 0;
- } else {
- switch (TID) {
- case 0:
- case 3:
- UP = 0;
- break;
- case 1:
- case 2:
- UP = 2;
- break;
- case 4:
- case 5:
- UP = 5;
- break;
- case 6:
- case 7:
- UP = 7;
- break;
- default:
- netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n",
- __func__, TID);
- return false;
- }
- }
-
- *ppTS = SearchAdmitTRStream(ieee, addr, UP, tx_rx_select);
- if (*ppTS)
- return true;
-
- if (!add_new_ts) {
- netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP);
- return false;
- }
-
- pUnusedList = (tx_rx_select == TX_DIR) ?
- (&ieee->Tx_TS_Unused_List) :
- (&ieee->Rx_TS_Unused_List);
-
- pAddmitList = (tx_rx_select == TX_DIR) ?
- (&ieee->Tx_TS_Admit_List) :
- (&ieee->Rx_TS_Admit_List);
-
- Dir = ((tx_rx_select == TX_DIR) ? DIR_UP : DIR_DOWN);
-
- if (!list_empty(pUnusedList)) {
- (*ppTS) = list_entry(pUnusedList->next,
- struct ts_common_info, list);
- list_del_init(&(*ppTS)->list);
- if (tx_rx_select == TX_DIR) {
- struct tx_ts_record *tmp =
- container_of(*ppTS,
- struct tx_ts_record,
- ts_common_info);
- ResetTxTsEntry(tmp);
- } else {
- struct rx_ts_record *ts =
- container_of(*ppTS,
- struct rx_ts_record,
- ts_common_info);
- ResetRxTsEntry(ts);
- }
-
- netdev_dbg(ieee->dev,
- "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n",
- UP, Dir, addr, *ppTS);
- ts_info->ts_id = UP;
- ts_info->ucDirection = Dir;
-
- MakeTSEntry(*ppTS, addr, &tspec);
- list_add_tail(&((*ppTS)->list), pAddmitList);
-
- return true;
- }
-
- netdev_warn(ieee->dev,
- "There is not enough dir=%d(0=up down=1) TS record to be used!",
- Dir);
- return false;
-}
-
-static void RemoveTsEntry(struct rtllib_device *ieee,
- struct ts_common_info *pTs, enum tr_select tx_rx_select)
-{
- rtllib_ts_init_del_ba(ieee, pTs, tx_rx_select);
-
- if (tx_rx_select == RX_DIR) {
- struct rx_reorder_entry *pRxReorderEntry;
- struct rx_ts_record *ts = (struct rx_ts_record *)pTs;
-
- if (timer_pending(&ts->rx_pkt_pending_timer))
- del_timer_sync(&ts->rx_pkt_pending_timer);
-
- while (!list_empty(&ts->rx_pending_pkt_list)) {
- pRxReorderEntry = (struct rx_reorder_entry *)
- list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, list);
- netdev_dbg(ieee->dev, "%s(): Delete seq_num %d!\n",
- __func__, pRxReorderEntry->seq_num);
- list_del_init(&pRxReorderEntry->list);
- {
- int i = 0;
- struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
-
- if (unlikely(!prxb))
- return;
- for (i = 0; i < prxb->nr_subframes; i++)
- dev_kfree_skb(prxb->subframes[i]);
- kfree(prxb);
- prxb = NULL;
- }
- list_add_tail(&pRxReorderEntry->list,
- &ieee->RxReorder_Unused_List);
- }
- } else {
- struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
-
- del_timer_sync(&pTxTS->ts_add_ba_timer);
- }
-}
-
-void remove_peer_ts(struct rtllib_device *ieee, u8 *addr)
-{
- struct ts_common_info *ts, *pTmpTS;
-
- netdev_info(ieee->dev, "===========>%s, %pM\n", __func__, addr);
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
- if (memcmp(ts->addr, addr, 6) == 0) {
- RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
- }
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
- if (memcmp(ts->addr, addr, 6) == 0) {
- netdev_info(ieee->dev,
- "====>remove Tx_TS_admin_list\n");
- RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
- }
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
- if (memcmp(ts->addr, addr, 6) == 0) {
- RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
- }
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
- if (memcmp(ts->addr, addr, 6) == 0) {
- RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
- }
- }
-}
-EXPORT_SYMBOL(remove_peer_ts);
-
-void remove_all_ts(struct rtllib_device *ieee)
-{
- struct ts_common_info *ts, *pTmpTS;
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
- RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
- RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
- RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
- }
-
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
- RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->list);
- list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
- }
-}
-
-void rtllib_ts_start_add_ba_process(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
-{
- if (pTxTS->add_ba_req_in_progress == false) {
- pTxTS->add_ba_req_in_progress = true;
-
- if (pTxTS->add_ba_req_delayed) {
- netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
- mod_timer(&pTxTS->ts_add_ba_timer, jiffies +
- msecs_to_jiffies(TS_ADDBA_DELAY));
- } else {
- netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
- mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10);
- }
- } else {
- netdev_dbg(ieee->dev, "BA timer is already added\n");
- }
-}
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
deleted file mode 100644
index d6615f787d53..000000000000
--- a/drivers/staging/rtl8192e/rtllib.h
+++ /dev/null
@@ -1,1799 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Merged with mainline rtllib.h in Aug 2004. Original ieee802_11
- * remains copyright by the original authors
- *
- * Portions of the merged code are based on 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
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno@linux.intel.com>
- * Copyright (c) 2004, Intel Corporation
- *
- * Modified for Realtek's wi-fi cards by Andrea Merello
- * <andrea.merello@gmail.com>
- */
-#ifndef RTLLIB_H
-#define RTLLIB_H
-#include <linux/if_ether.h> /* ETH_ALEN */
-#include <linux/kernel.h> /* ARRAY_SIZE */
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-
-#include <linux/delay.h>
-#include <linux/wireless.h>
-
-#include "rtl819x_HT.h"
-#include "rtl819x_BA.h"
-#include "rtl819x_TS.h"
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-#include <net/cfg80211.h>
-#include <net/lib80211.h>
-
-#define MAX_PRECMD_CNT 16
-#define MAX_RFDEPENDCMD_CNT 16
-#define MAX_POSTCMD_CNT 16
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY
-#endif
-#include <net/iw_handler.h>
-
-#ifndef IW_MODE_MONITOR
-#define IW_MODE_MONITOR 6
-#endif
-
-#ifndef IWEVCUSTOM
-#define IWEVCUSTOM 0x8c02
-#endif
-
-#ifndef IW_CUSTOM_MAX
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX 256 /* In bytes */
-#endif
-
-#define container_of_dwork_rsl(x, y, z) \
- container_of(to_delayed_work(x), y, z)
-
-static inline void *netdev_priv_rsl(struct net_device *dev)
-{
- return netdev_priv(dev);
-}
-
-#define KEY_TYPE_NA 0x0
-#define KEY_TYPE_WEP40 0x1
-#define KEY_TYPE_TKIP 0x2
-#define KEY_TYPE_CCMP 0x4
-#define KEY_TYPE_WEP104 0x5
-/* added for rtl819x tx procedure */
-#define MAX_QUEUE_SIZE 0x10
-
-#define BK_QUEUE 0
-#define BE_QUEUE 1
-#define VI_QUEUE 2
-#define VO_QUEUE 3
-#define HCCA_QUEUE 4
-#define TXCMD_QUEUE 5
-#define MGNT_QUEUE 6
-#define HIGH_QUEUE 7
-#define BEACON_QUEUE 8
-
-#define IE_CISCO_FLAG_POSITION 0x08
-#define SUPPORT_CKIP_MIC 0x08
-#define SUPPORT_CKIP_PK 0x10
-#define RT_RF_OFF_LEVL_HALT_NIC BIT(3)
-#define RT_IN_PS_LEVEL(psc, _PS_FLAG) \
- ((psc->cur_ps_level & _PS_FLAG) ? true : false)
-#define RT_CLEAR_PS_LEVEL(psc, _PS_FLAG) \
- (psc->cur_ps_level &= (~(_PS_FLAG)))
-
-/* defined for skb cb field */
-/* At most 28 byte */
-struct cb_desc {
- /* Tx Desc Related flags (8-9) */
- u8 last_ini_pkt:1;
- u8 cmd_or_init:1;
- u8 tx_dis_rate_fallback:1;
- u8 tx_use_drv_assinged_rate:1;
- u8 hw_sec:1;
-
- u8 stuck_count;
-
- /* Tx Firmware Related flags (10-11)*/
- u8 cts_enable:1;
- u8 rts_enable:1;
- u8 use_short_gi:1;
- u8 use_short_preamble:1;
- u8 tx_enable_fw_calc_dur:1;
- u8 ampdu_enable:1;
- u8 rtsstbc:1;
- u8 RTSSC:1;
-
- u8 rts_bw:1;
- u8 packet_bw:1;
- u8 rts_use_short_preamble:1;
- u8 rts_use_short_gi:1;
- u8 multicast:1;
- u8 broadcast:1;
- u8 drv_agg_enable:1;
- u8 reserved2:1;
-
- /* Tx Desc related element(12-19) */
- u8 rata_index;
- u8 queue_index;
- u16 txbuf_size;
- u8 ratr_index;
- u8 bAMSDU:1;
- u8 bFromAggrQ:1;
- u8 reserved6:6;
- u8 priority;
-
- /* Tx firmware related element(20-27) */
- u8 data_rate;
- u8 rts_rate;
- u8 ampdu_factor;
- u8 ampdu_density;
- u8 DrvAggrNum;
- u8 bdhcp;
- u16 pkt_size;
- u8 bIsSpecialDataFrame;
-
- u8 bBTTxPacket;
- u8 bIsBTProbRsp;
-};
-
-enum sw_chnl_cmd_id {
- cmd_id_end,
- cmd_id_set_tx_power_level,
- cmd_id_bbreg_write10,
- cmd_id_write_port_ulong,
- cmd_id_write_port_ushort,
- cmd_id_write_port_uchar,
- cmd_id_rf_write_reg,
-};
-
-struct sw_chnl_cmd {
- enum sw_chnl_cmd_id cmd_id;
- u32 para1;
- u32 para2;
- u32 ms_delay;
-};
-
-/*--------------------------Define -------------------------------------------*/
-#define MGN_1M 0x02
-#define MGN_2M 0x04
-#define MGN_5_5M 0x0b
-#define MGN_11M 0x16
-
-#define MGN_6M 0x0c
-#define MGN_9M 0x12
-#define MGN_12M 0x18
-#define MGN_18M 0x24
-#define MGN_24M 0x30
-#define MGN_36M 0x48
-#define MGN_48M 0x60
-#define MGN_54M 0x6c
-
-#define MGN_MCS0 0x80
-#define MGN_MCS1 0x81
-#define MGN_MCS2 0x82
-#define MGN_MCS3 0x83
-#define MGN_MCS4 0x84
-#define MGN_MCS5 0x85
-#define MGN_MCS6 0x86
-#define MGN_MCS7 0x87
-#define MGN_MCS8 0x88
-#define MGN_MCS9 0x89
-#define MGN_MCS10 0x8a
-#define MGN_MCS11 0x8b
-#define MGN_MCS12 0x8c
-#define MGN_MCS13 0x8d
-#define MGN_MCS14 0x8e
-#define MGN_MCS15 0x8f
-
-enum hw_variables {
- HW_VAR_ETHER_ADDR,
- HW_VAR_MULTICAST_REG,
- HW_VAR_BASIC_RATE,
- HW_VAR_BSSID,
- HW_VAR_MEDIA_STATUS,
- HW_VAR_SECURITY_CONF,
- HW_VAR_BEACON_INTERVAL,
- HW_VAR_ATIM_WINDOW,
- HW_VAR_LISTEN_INTERVAL,
- HW_VAR_CS_COUNTER,
- HW_VAR_DEFAULTKEY0,
- HW_VAR_DEFAULTKEY1,
- HW_VAR_DEFAULTKEY2,
- HW_VAR_DEFAULTKEY3,
- HW_VAR_SIFS,
- HW_VAR_DIFS,
- HW_VAR_EIFS,
- HW_VAR_SLOT_TIME,
- HW_VAR_ACK_PREAMBLE,
- HW_VAR_CW_CONFIG,
- HW_VAR_CW_VALUES,
- HW_VAR_RATE_FALLBACK_CONTROL,
- HW_VAR_CONTENTION_WINDOW,
- HW_VAR_RETRY_COUNT,
- HW_VAR_TR_SWITCH,
- HW_VAR_COMMAND,
- HW_VAR_WPA_CONFIG,
- HW_VAR_AMPDU_MIN_SPACE,
- HW_VAR_SHORTGI_DENSITY,
- HW_VAR_AMPDU_FACTOR,
- HW_VAR_MCS_RATE_AVAILABLE,
- HW_VAR_AC_PARAM,
- HW_VAR_ACM_CTRL,
- HW_VAR_DIS_Req_Qsize,
- HW_VAR_CCX_CHNL_LOAD,
- HW_VAR_CCX_NOISE_HISTOGRAM,
- HW_VAR_CCX_CLM_NHM,
- HW_VAR_TxOPLimit,
- HW_VAR_TURBO_MODE,
- HW_VAR_RF_STATE,
- HW_VAR_RF_OFF_BY_HW,
- HW_VAR_BUS_SPEED,
- HW_VAR_SET_DEV_POWER,
-
- HW_VAR_RCR,
- HW_VAR_RATR_0,
- HW_VAR_RRSR,
- HW_VAR_CPU_RST,
- HW_VAR_CECHK_BSSID,
- HW_VAR_LBK_MODE,
- HW_VAR_AES_11N_FIX,
- HW_VAR_USB_RX_AGGR,
- HW_VAR_USER_CONTROL_TURBO_MODE,
- HW_VAR_RETRY_LIMIT,
- HW_VAR_INIT_TX_RATE,
- HW_VAR_TX_RATE_REG,
- HW_VAR_EFUSE_USAGE,
- HW_VAR_EFUSE_BYTES,
- HW_VAR_AUTOLOAD_STATUS,
- HW_VAR_RF_2R_DISABLE,
- HW_VAR_SET_RPWM,
- HW_VAR_H2C_FW_PWRMODE,
- HW_VAR_H2C_FW_JOINBSSRPT,
- HW_VAR_1X1_RECV_COMBINE,
- HW_VAR_STOP_SEND_BEACON,
- HW_VAR_TSF_TIMER,
- HW_VAR_IO_CMD,
-
- HW_VAR_RF_RECOVERY,
- HW_VAR_H2C_FW_UPDATE_GTK,
- HW_VAR_WF_MASK,
- HW_VAR_WF_CRC,
- HW_VAR_WF_IS_MAC_ADDR,
- HW_VAR_H2C_FW_OFFLOAD,
- HW_VAR_RESET_WFCRC,
-
- HW_VAR_HANDLE_FW_C2H,
- HW_VAR_DL_FW_RSVD_PAGE,
- HW_VAR_AID,
- HW_VAR_HW_SEQ_ENABLE,
- HW_VAR_CORRECT_TSF,
- HW_VAR_BCN_VALID,
- HW_VAR_FWLPS_RF_ON,
- HW_VAR_DUAL_TSF_RST,
- HW_VAR_SWITCH_EPHY_WoWLAN,
- HW_VAR_INT_MIGRATION,
- HW_VAR_INT_AC,
- HW_VAR_RF_TIMING,
-};
-
-enum rt_op_mode {
- RT_OP_MODE_AP,
- RT_OP_MODE_INFRASTRUCTURE,
- RT_OP_MODE_IBSS,
- RT_OP_MODE_NO_LINK,
-};
-
-#define asifs_time \
- ((priv->rtllib->current_network.mode == WIRELESS_MODE_N_24G) ? 16 : 10)
-
-#define MGMT_QUEUE_NUM 5
-
-#define MAX_IE_LEN 0xff
-
-#define msleep_interruptible_rsl msleep_interruptible
-
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- * 6.2.1.1.2.
- *
- * The figure in section 7.1.2 suggests a body size of up to 2312
- * bytes is allowed, which is a bit confusing, I suspect this
- * represents the 2304 bytes of real data, plus a possible 8 bytes of
- * WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro)
- */
-#define RTLLIB_1ADDR_LEN 10
-#define RTLLIB_2ADDR_LEN 16
-#define RTLLIB_3ADDR_LEN 24
-#define RTLLIB_4ADDR_LEN 30
-#define RTLLIB_FCS_LEN 4
-
-#define RTLLIB_SKBBUFFER_SIZE 2500
-
-#define MIN_FRAG_THRESHOLD 256U
-#define MAX_FRAG_THRESHOLD 2346U
-
-#define RTLLIB_FTYPE_MGMT 0x0000
-#define RTLLIB_FTYPE_CTL 0x0004
-#define RTLLIB_FTYPE_DATA 0x0008
-
-#define RTLLIB_SCTL_FRAG 0x000F
-#define RTLLIB_SCTL_SEQ 0xFFF0
-
-/* QOS control */
-#define RTLLIB_QCTL_TID 0x000F
-
-#define FC_QOS_BIT BIT(7)
-#define is_data_frame(pdu) (((pdu[0] & 0x0C) == 0x08) ? true : false)
-#define is_legacy_data_frame(pdu) (is_data_frame(pdu) && (!(pdu[0] & FC_QOS_BIT)))
-#define is_qos_data_frame(pframe) \
- ((*(u16 *)pframe & (IEEE80211_STYPE_QOS_DATA | RTLLIB_FTYPE_DATA)) == \
- (IEEE80211_STYPE_QOS_DATA | RTLLIB_FTYPE_DATA))
-#define frame_order(pframe) (*(u16 *)pframe & IEEE80211_FCTL_ORDER)
-#define SN_LESS(a, b) (((a - b) & 0x800) != 0)
-#define SN_EQUAL(a, b) (a == b)
-#define MAX_DEV_ADDR_SIZE 8
-
-enum act_category {
- ACT_CAT_QOS = 1,
- ACT_CAT_DLS = 2,
- ACT_CAT_BA = 3,
- ACT_CAT_HT = 7,
- ACT_CAT_WMM = 17,
-};
-
-enum ba_action {
- ACT_ADDBAREQ = 0,
- ACT_ADDBARSP = 1,
- ACT_DELBA = 2,
-};
-
-enum init_gain_op_type {
- IG_Backup = 0,
- IG_Restore,
- IG_Max
-};
-
-enum wireless_mode {
- WIRELESS_MODE_UNKNOWN = 0x00,
- WIRELESS_MODE_A = 0x01,
- WIRELESS_MODE_B = 0x02,
- WIRELESS_MODE_G = 0x04,
- WIRELESS_MODE_AUTO = 0x08,
- WIRELESS_MODE_N_24G = 0x10,
-};
-
-#ifndef ETH_P_PAE
-#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#endif /* ETH_P_PAE */
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
-/* IEEE 802.11 defines */
-
-#define P80211_OUI_LEN 3
-
-struct rtllib_snap_hdr {
- u8 dsap; /* always 0xAA */
- u8 ssap; /* always 0xAA */
- u8 ctrl; /* always 0x03 */
- u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-
-} __packed;
-
-enum _REG_PREAMBLE_MODE {
- PREAMBLE_LONG = 1,
- PREAMBLE_AUTO = 2,
- PREAMBLE_SHORT = 3,
-};
-
-#define SNAP_SIZE sizeof(struct rtllib_snap_hdr)
-
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTLLIB_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) (((seq) & RTLLIB_SCTL_SEQ) >> 4)
-
-#define RTLLIB_STATMASK_SIGNAL (1 << 0)
-#define RTLLIB_STATMASK_RSSI (1 << 1)
-#define RTLLIB_STATMASK_NOISE (1 << 2)
-#define RTLLIB_STATMASK_WEMASK 0x7
-
-#define RTLLIB_CCK_MODULATION (1 << 0)
-#define RTLLIB_OFDM_MODULATION (1 << 1)
-
-#define RTLLIB_CCK_RATE_LEN 4
-#define RTLLIB_CCK_RATE_1MB 0x02
-#define RTLLIB_CCK_RATE_2MB 0x04
-#define RTLLIB_CCK_RATE_5MB 0x0B
-#define RTLLIB_CCK_RATE_11MB 0x16
-#define RTLLIB_OFDM_RATE_LEN 8
-#define RTLLIB_OFDM_RATE_6MB 0x0C
-#define RTLLIB_OFDM_RATE_9MB 0x12
-#define RTLLIB_OFDM_RATE_12MB 0x18
-#define RTLLIB_OFDM_RATE_18MB 0x24
-#define RTLLIB_OFDM_RATE_24MB 0x30
-#define RTLLIB_OFDM_RATE_36MB 0x48
-#define RTLLIB_OFDM_RATE_48MB 0x60
-#define RTLLIB_OFDM_RATE_54MB 0x6C
-#define RTLLIB_BASIC_RATE_MASK 0x80
-
-/* this is stolen and modified from the madwifi driver*/
-#define RTLLIB_FC0_TYPE_MASK 0x0c
-#define RTLLIB_FC0_TYPE_DATA 0x08
-#define RTLLIB_FC0_SUBTYPE_MASK 0xB0
-#define RTLLIB_FC0_SUBTYPE_QOS 0x80
-
-#define RTLLIB_QOS_HAS_SEQ(fc) \
- (((fc) & (RTLLIB_FC0_TYPE_MASK | RTLLIB_FC0_SUBTYPE_MASK)) == \
- (RTLLIB_FC0_TYPE_DATA | RTLLIB_FC0_SUBTYPE_QOS))
-
-/* this is stolen from ipw2200 driver */
-#define IEEE_IBSS_MAC_HASH_SIZE 31
-
-/* NOTE: This data is for statistical purposes; not all hardware provides this
- * information for frames received. Not setting these will not cause
- * any adverse affects.
- */
-struct rtllib_rx_stats {
- s8 rssi;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
- u8 control;
- u8 mask;
- u16 len;
- u16 Length;
- u8 signal_quality;
- s32 RecvSignalPower;
- u8 signal_strength;
- u16 hw_error:1;
- u16 bCRC:1;
- u16 bICV:1;
- u16 decrypted:1;
- u32 time_stamp_low;
- u32 time_stamp_high;
-
- u8 rx_drv_info_size;
- u8 rx_buf_shift;
- bool bIsAMPDU;
- bool bFirstMPDU;
- bool contain_htc;
- u32 RxPWDBAll;
- u8 RxMIMOSignalStrength[2];
- s8 RxMIMOSignalQuality[2];
- bool bPacketMatchBSSID;
- bool bIsCCK;
- bool packet_to_self;
- bool bPacketBeacon;
- bool bToSelfBA;
-};
-
-/* 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 RTLLIB_FRAG_CACHE_LEN 4
-
-struct rtllib_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 rtllib_device;
-
-#define SEC_ACTIVE_KEY (1 << 4)
-#define SEC_AUTH_MODE (1 << 5)
-#define SEC_UNICAST_GROUP (1 << 6)
-#define SEC_LEVEL (1 << 7)
-#define SEC_ENABLED (1 << 8)
-
-#define SEC_LEVEL_0 0 /* None */
-#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
-#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
-
-#define SEC_ALG_NONE 0
-#define SEC_ALG_WEP 1
-#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 4
-
-#define WEP_KEY_LEN 13
-#define SCM_KEY_LEN 32
-
-struct rtllib_security {
- u16 active_key:2,
- enabled:1,
- auth_mode:2,
- auth_algo:4,
- unicast_uses_group:1,
- encrypt:1;
- u8 key_sizes[NUM_WEP_KEYS];
- u8 keys[NUM_WEP_KEYS][SCM_KEY_LEN];
- u8 level;
- u16 flags;
-} __packed;
-
-/* 802.11 data frame from AP
- * ,-------------------------------------------------------------------.
- * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- * |------|------|---------|---------|---------|------|---------|------|
- * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
- * | | tion | (BSSID) | | | ence | data | |
- * `-------------------------------------------------------------------'
- * Total: 28-2340 bytes
- */
-
-/* Management Frame Information Element Types */
-enum rtllib_mfie {
- MFIE_TYPE_SSID = 0,
- MFIE_TYPE_RATES = 1,
- MFIE_TYPE_FH_SET = 2,
- MFIE_TYPE_DS_SET = 3,
- MFIE_TYPE_CF_SET = 4,
- MFIE_TYPE_TIM = 5,
- MFIE_TYPE_IBSS_SET = 6,
- MFIE_TYPE_COUNTRY = 7,
- MFIE_TYPE_HOP_PARAMS = 8,
- MFIE_TYPE_HOP_TABLE = 9,
- MFIE_TYPE_REQUEST = 10,
- MFIE_TYPE_CHALLENGE = 16,
- MFIE_TYPE_POWER_CONSTRAINT = 32,
- MFIE_TYPE_POWER_CAPABILITY = 33,
- MFIE_TYPE_TPC_REQUEST = 34,
- MFIE_TYPE_TPC_REPORT = 35,
- MFIE_TYPE_SUPP_CHANNELS = 36,
- MFIE_TYPE_CSA = 37,
- MFIE_TYPE_MEASURE_REQUEST = 38,
- MFIE_TYPE_MEASURE_REPORT = 39,
- MFIE_TYPE_QUIET = 40,
- MFIE_TYPE_IBSS_DFS = 41,
- MFIE_TYPE_ERP = 42,
- MFIE_TYPE_HT_CAP = 45,
- MFIE_TYPE_RSN = 48,
- MFIE_TYPE_RATES_EX = 50,
- MFIE_TYPE_HT_INFO = 61,
- MFIE_TYPE_AIRONET = 133,
- MFIE_TYPE_GENERIC = 221,
- MFIE_TYPE_QOS_PARAMETER = 222,
-};
-
-/* Minimal header; can be used for passing 802.11 frames with sufficient
- * information to determine what type of underlying data type is actually
- * stored in the data.
- */
-struct rtllib_info_element {
- u8 id;
- u8 len;
- u8 data[];
-} __packed;
-
-struct rtllib_authentication {
- struct ieee80211_hdr_3addr header;
- __le16 algorithm;
- __le16 transaction;
- __le16 status;
- /*challenge*/
- struct rtllib_info_element info_element[];
-} __packed __aligned(2);
-
-struct rtllib_disauth {
- struct ieee80211_hdr_3addr header;
- __le16 reason;
-} __packed __aligned(2);
-
-struct rtllib_disassoc {
- struct ieee80211_hdr_3addr header;
- __le16 reason;
-} __packed __aligned(2);
-
-struct rtllib_probe_request {
- struct ieee80211_hdr_3addr header;
- /* SSID, supported rates */
- struct rtllib_info_element info_element[];
-} __packed __aligned(2);
-
-struct rtllib_probe_response {
- struct ieee80211_hdr_3addr header;
- u32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- /* SSID, supported rates, FH params, DS params,
- * CF params, IBSS params, TIM (if beacon), RSN
- */
- struct rtllib_info_element info_element[];
-} __packed __aligned(2);
-
-/* Alias beacon for probe_response */
-#define rtllib_beacon rtllib_probe_response
-
-struct rtllib_assoc_request_frame {
- struct ieee80211_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- /* SSID, supported rates, RSN */
- struct rtllib_info_element info_element[];
-} __packed __aligned(2);
-
-struct rtllib_assoc_response_frame {
- struct ieee80211_hdr_3addr header;
- __le16 capability;
- __le16 status;
- __le16 aid;
- struct rtllib_info_element info_element[]; /* supported rates */
-} __packed __aligned(2);
-
-struct rtllib_txb {
- u8 nr_frags;
- u8 encrypted;
- u8 queue_index;
- u8 rts_included;
- u16 reserved;
- __le16 frag_size;
- __le16 payload_size;
- struct sk_buff *fragments[] __counted_by(nr_frags);
-};
-
-#define MAX_SUBFRAME_COUNT 64
-struct rtllib_rxb {
- u8 nr_subframes;
- struct sk_buff *subframes[MAX_SUBFRAME_COUNT];
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
-};
-
-union frameqos {
- u16 shortdata;
- u8 chardata[2];
- struct {
- u16 tid:4;
- u16 eosp:1;
- u16 ack_policy:2;
- u16 reserved:1;
- u16 txop:8;
- } field;
-};
-
-/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
- * only use 8, and then use extended rates for the remaining supported
- * rates. Other APs, however, stick all of their supported rates on the
- * main rates information element...
- */
-#define MAX_RATES_LENGTH ((u8)12)
-#define MAX_RATES_EX_LENGTH ((u8)16)
-#define MAX_NETWORK_COUNT 96
-
-#define MAX_CHANNEL_NUMBER 161
-#define RTLLIB_SOFTMAC_SCAN_TIME 100
-#define RTLLIB_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2)
-
-#define MAX_WPA_IE_LEN 64
-#define MAX_WZC_IE_LEN 256
-
-#define NETWORK_EMPTY_ESSID (1 << 0)
-#define NETWORK_HAS_OFDM (1 << 1)
-#define NETWORK_HAS_CCK (1 << 2)
-
-/* QoS structure */
-#define NETWORK_HAS_QOS_PARAMETERS (1 << 3)
-#define NETWORK_HAS_QOS_INFORMATION (1 << 4)
-#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \
- NETWORK_HAS_QOS_INFORMATION)
-/* 802.11h */
-#define NETWORK_HAS_ERP_VALUE (1 << 10)
-
-#define QOS_QUEUE_NUM 4
-#define QOS_OUI_LEN 3
-#define QOS_OUI_TYPE 2
-#define QOS_ELEMENT_ID 221
-#define QOS_OUI_INFO_SUB_TYPE 0
-#define QOS_OUI_PARAM_SUB_TYPE 1
-#define QOS_VERSION_1 1
-
-struct rtllib_qos_information_element {
- u8 element_id;
- u8 length;
- u8 qui[QOS_OUI_LEN];
- u8 qui_type;
- u8 qui_subtype;
- u8 version;
- u8 ac_info;
-} __packed;
-
-struct rtllib_qos_ac_parameter {
- u8 aci_aifsn;
- u8 ecw_min_max;
- __le16 tx_op_limit;
-} __packed;
-
-struct rtllib_qos_parameter_info {
- struct rtllib_qos_information_element info_element;
- u8 reserved;
- struct rtllib_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __packed;
-
-struct rtllib_qos_parameters {
- __le16 cw_min[QOS_QUEUE_NUM];
- __le16 cw_max[QOS_QUEUE_NUM];
- u8 aifs[QOS_QUEUE_NUM];
- u8 flag[QOS_QUEUE_NUM];
- __le16 tx_op_limit[QOS_QUEUE_NUM];
-} __packed;
-
-struct rtllib_qos_data {
- struct rtllib_qos_parameters parameters;
- unsigned int wmm_acm;
- int active;
- int supported;
- u8 param_count;
- u8 old_param_count;
-};
-
-struct rtllib_tim_parameters {
- u8 tim_count;
- u8 tim_period;
-} __packed;
-
-struct rtllib_wmm_ac_param {
- u8 ac_aci_acm_aifsn;
- u8 ac_ecwmin_ecwmax;
- u16 ac_txop_limit;
-};
-
-enum eap_type {
- EAP_PACKET = 0,
- EAPOL_START,
- EAPOL_LOGOFF,
- EAPOL_KEY,
- EAPOL_ENCAP_ASF_ALERT
-};
-
-static const char * const eap_types[] = {
- [EAP_PACKET] = "EAP-Packet",
- [EAPOL_START] = "EAPOL-Start",
- [EAPOL_LOGOFF] = "EAPOL-Logoff",
- [EAPOL_KEY] = "EAPOL-Key",
- [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
-};
-
-static inline const char *eap_get_type(int type)
-{
- return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" :
- eap_types[type];
-}
-
-static inline u8 frame_qos_tid(u8 *buf)
-{
- struct ieee80211_hdr_3addr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr_3addr *)buf;
- fc = le16_to_cpu(hdr->frame_control);
- return (u8)((union frameqos *)(buf + (((fc & IEEE80211_FCTL_TODS) &&
- (fc & IEEE80211_FCTL_FROMDS)) ? 30 : 24)))->field.tid;
-}
-
-struct eapol {
- u8 snap[6];
- u16 ethertype;
- u8 version;
- u8 type;
- u16 length;
-} __packed;
-
-struct rtllib_softmac_stats {
- unsigned int rx_ass_ok;
- unsigned int rx_ass_err;
- unsigned int rx_probe_rq;
- unsigned int tx_probe_rs;
- unsigned int tx_beacons;
- unsigned int rx_auth_rq;
- unsigned int rx_auth_rs_ok;
- unsigned int rx_auth_rs_err;
- unsigned int tx_auth_rq;
- unsigned int no_auth_rs;
- unsigned int no_ass_rs;
- unsigned int tx_ass_rq;
- unsigned int rx_ass_rq;
- unsigned int tx_probe_rq;
- unsigned int reassoc;
- unsigned int swtxstop;
- unsigned int swtxawake;
- unsigned char CurrentShowTxate;
- unsigned char last_packet_rate;
- unsigned int txretrycount;
-};
-
-/* These are the data types that can make up management packets
- *
- * u16 auth_algorithm;
- * u16 auth_sequence;
- * u16 beacon_interval;
- * u16 capability;
- * u8 current_ap[ETH_ALEN];
- * u16 listen_interval;
- * struct {
- * u16 association_id:14, reserved:2;
- * } __packed;
- * u32 time_stamp[2];
- * u16 reason;
- * u16 status;
- */
-
-#define RTLLIB_DEFAULT_TX_ESSID "Penguin"
-#define RTLLIB_DEFAULT_BASIC_RATE 2
-
-enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame};
-#define MAX_SP_Len (WMM_all_frame << 4)
-#define RTLLIB_QOS_TID 0x0f
-#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5)
-
-#define RTLLIB_DTIM_MBCAST 4
-#define RTLLIB_DTIM_UCAST 2
-#define RTLLIB_DTIM_VALID 1
-#define RTLLIB_DTIM_INVALID 0
-
-#define RTLLIB_PS_DISABLED 0
-#define RTLLIB_PS_UNICAST RTLLIB_DTIM_UCAST
-#define RTLLIB_PS_MBCAST RTLLIB_DTIM_MBCAST
-
-#define WME_AC_BK 0x00
-#define WME_AC_BE 0x01
-#define WME_AC_VI 0x02
-#define WME_AC_VO 0x03
-#define WME_AC_PRAM_LEN 16
-
-#define MAX_RECEIVE_BUFFER_SIZE 9100
-
-#define UP2AC(up) ( \
- ((up) < 1) ? WME_AC_BE : \
- ((up) < 3) ? WME_AC_BK : \
- ((up) < 4) ? WME_AC_BE : \
- ((up) < 6) ? WME_AC_VI : \
- WME_AC_VO)
-
-#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address
- * plus ether type
- */
-
-enum erp_t {
- ERP_NonERPpresent = 0x01,
- ERP_UseProtection = 0x02,
- ERP_BarkerPreambleMode = 0x04,
-};
-
-struct rtllib_network {
- /* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- /* Ensure null-terminated for any debug msgs */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
- u8 hidden_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 hidden_ssid_len;
- struct rtllib_qos_data qos_data;
-
- bool with_aironet_ie;
- bool ckip_supported;
- bool ccx_rm_enable;
- u8 ccx_rm_state[2];
- bool mb_ssid_valid;
- u8 mb_ssid_mask;
- u8 mb_ssid[ETH_ALEN];
- bool with_ccx_ver_num;
- u8 bss_ccx_ver_number;
- /* These are network statistics */
- struct rtllib_rx_stats stats;
- u16 capability;
- u8 rates[MAX_RATES_LENGTH];
- u8 rates_len;
- u8 rates_ex[MAX_RATES_EX_LENGTH];
- u8 rates_ex_len;
- unsigned long last_scanned;
- u8 mode;
- u32 flags;
- u32 time_stamp[2];
- u16 beacon_interval;
- u16 listen_interval;
- u16 atim_window;
- u8 erp_value;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- u8 wzc_ie[MAX_WZC_IE_LEN];
- size_t wzc_ie_len;
-
- struct rtllib_tim_parameters tim;
- u8 dtim_period;
- u8 dtim_data;
- u64 last_dtim_sta_time;
-
- u8 wmm_info;
- struct rtllib_wmm_ac_param wmm_param[4];
- u8 turbo_enable;
- u16 country_ie_len;
- u8 country_ie_buf[MAX_IE_LEN];
- struct bss_ht bssht;
- bool broadcom_cap_exist;
- bool realtek_cap_exit;
- bool marvell_cap_exist;
- bool ralink_cap_exist;
- bool atheros_cap_exist;
- bool cisco_cap_exist;
- bool airgo_cap_exist;
- bool unknown_cap_exist;
- bool berp_info_valid;
- bool buseprotection;
- u8 signal_strength;
- u8 RSSI;
- struct list_head list;
-};
-
-enum rtl_link_state {
- /* the card is not linked at all */
- MAC80211_NOLINK = 0,
-
- /* RTLLIB_ASSOCIATING* are for BSS client mode
- * the driver shall not perform RX filtering unless
- * the state is LINKED.
- * The driver shall just check for the state LINKED and
- * defaults to NOLINK for ALL the other states (including
- * LINKED_SCANNING)
- */
-
- /* the association procedure will start (wq scheduling)*/
- RTLLIB_ASSOCIATING,
- RTLLIB_ASSOCIATING_RETRY,
-
- /* the association procedure is sending AUTH request*/
- RTLLIB_ASSOCIATING_AUTHENTICATING,
-
- /* the association procedure has successfully authenticated
- * and is sending association request
- */
- RTLLIB_ASSOCIATING_AUTHENTICATED,
-
- /* the link is ok. the card associated to a BSS or linked
- * to a ibss cell or acting as an AP and creating the bss
- */
- MAC80211_LINKED,
-
- /* same as LINKED, but the driver shall apply RX filter
- * rules as we are in NO_LINK mode. As the card is still
- * logically linked, but it is doing a syncro site survey
- * then it will be back to LINKED state.
- */
- MAC80211_LINKED_SCANNING,
-};
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-#define DEFAULT_FTS 2346
-
-#define CFG_RTLLIB_RESERVE_FCS (1 << 0)
-#define CFG_RTLLIB_COMPUTE_FCS (1 << 1)
-
-struct tx_pending {
- int frag;
- struct rtllib_txb *txb;
-};
-
-struct bandwidth_autoswitch {
- long threshold_20Mhzto40Mhz;
- long threshold_40Mhzto20Mhz;
- bool forced_tx_20MHz;
- bool bautoswitch_enable;
-};
-
-#define REORDER_WIN_SIZE 128
-#define REORDER_ENTRY_NUM 128
-struct rx_reorder_entry {
- struct list_head list;
- u16 seq_num;
- struct rtllib_rxb *prxb;
-};
-
-enum fsync_state {
- DEFAULT_FSYNC,
- HW_FSYNC,
- SW_FSYNC
-};
-
-enum ips_callback_function {
- IPS_CALLBACK_NONE = 0,
- IPS_CALLBACK_MGNT_LINK_REQUEST = 1,
- IPS_CALLBACK_JOIN_REQUEST = 2,
-};
-
-enum rt_rf_power_state {
- rf_on,
- rf_sleep,
- rf_off
-};
-
-struct rt_pwr_save_ctrl {
- bool bSwRfProcessing;
- enum rt_rf_power_state eInactivePowerState;
- enum ips_callback_function return_point;
-
- bool bLeisurePs;
- u8 lps_idle_count;
- u8 lps_awake_intvl;
-
- u32 cur_ps_level;
-};
-
-#define RT_RF_CHANGE_SOURCE u32
-
-#define RF_CHANGE_BY_SW BIT(31)
-#define RF_CHANGE_BY_HW BIT(30)
-#define RF_CHANGE_BY_PS BIT(29)
-#define RF_CHANGE_BY_IPS BIT(28)
-#define RF_CHANGE_BY_INIT 0
-
-enum country_code_type {
- COUNTRY_CODE_FCC = 0,
- COUNTRY_CODE_IC = 1,
- COUNTRY_CODE_ETSI = 2,
- COUNTRY_CODE_SPAIN = 3,
- COUNTRY_CODE_FRANCE = 4,
- COUNTRY_CODE_MKK = 5,
- COUNTRY_CODE_MKK1 = 6,
- COUNTRY_CODE_ISRAEL = 7,
- COUNTRY_CODE_TELEC = 8,
- COUNTRY_CODE_MIC = 9,
- COUNTRY_CODE_GLOBAL_DOMAIN = 10,
- COUNTRY_CODE_WORLD_WIDE_13 = 11,
- COUNTRY_CODE_TELEC_NETGEAR = 12,
- COUNTRY_CODE_MAX
-};
-
-enum scan_op_backup_opt {
- SCAN_OPT_BACKUP = 0,
- SCAN_OPT_RESTORE,
- SCAN_OPT_MAX
-};
-
-#define RT_MAX_LD_SLOT_NUM 10
-struct rt_link_detect {
- u32 num_recv_bcn_in_period;
- u32 num_recv_data_in_period;
-
- u32 RxBcnNum[RT_MAX_LD_SLOT_NUM];
- u32 RxDataNum[RT_MAX_LD_SLOT_NUM];
- u16 slot_num;
- u16 slot_index;
-
- u32 num_tx_ok_in_period;
- u32 num_rx_ok_in_period;
- u32 num_rx_unicast_ok_in_period;
- bool busy_traffic;
- bool bHigherBusyTraffic;
- bool bHigherBusyRxTraffic;
-};
-
-struct sw_cam_table {
- u8 macaddr[ETH_ALEN];
- bool bused;
- u8 key_buf[16];
- u16 key_type;
- u8 useDK;
- u8 key_index;
-
-};
-
-#define TOTAL_CAM_ENTRY 32
-struct rate_adaptive {
- u8 ratr_state;
- u16 reserve;
-
- u32 high_rssi_thresh_for_ra;
- u32 high2low_rssi_thresh_for_ra;
- u8 low2high_rssi_thresh_for_ra40M;
- u32 low_rssi_thresh_for_ra40M;
- u8 low2high_rssi_thresh_for_ra20M;
- u32 low_rssi_thresh_for_ra20M;
- u32 upper_rssi_threshold_ratr;
- u32 middle_rssi_threshold_ratr;
- u32 low_rssi_threshold_ratr;
- u32 low_rssi_threshold_ratr_40M;
- u32 low_rssi_threshold_ratr_20M;
- u8 ping_rssi_enable;
- u32 ping_rssi_ratr;
- u32 ping_rssi_thresh_for_ra;
- u8 PreRATRState;
-
-};
-
-#define NUM_PMKID_CACHE 16
-struct rt_pmkid_list {
- u8 bssid[ETH_ALEN];
- u8 PMKID[16];
- u8 SsidBuf[33];
- u8 used;
-};
-
-/*************** DRIVER STATUS *****/
-#define STATUS_SCANNING 0
-/*************** DRIVER STATUS *****/
-
-enum {
- LPS_IS_WAKE = 0,
- LPS_IS_SLEEP = 1,
- LPS_WAIT_NULL_DATA_SEND = 2,
-};
-
-struct rtllib_device {
- struct pci_dev *pdev;
- struct net_device *dev;
- struct rtllib_security sec;
-
- bool disable_mgnt_queue;
-
- unsigned long status;
- u8 cnt_after_link;
-
- enum rt_op_mode op_mode;
-
- /* The last AssocReq/Resp IEs */
- u8 *assocreq_ies, *assocresp_ies;
- size_t assocreq_ies_len, assocresp_ies_len;
-
- bool forced_bg_mode;
-
- u8 hwsec_active;
- bool is_roaming;
- bool ieee_up;
- bool cannot_notify;
- bool bSupportRemoteWakeUp;
- bool actscanning;
- bool first_ie_in_scan;
- bool be_scan_inprogress;
- bool beinretry;
- enum rt_rf_power_state rf_power_state;
- RT_RF_CHANGE_SOURCE rf_off_reason;
- bool is_set_key;
- bool wx_set_enc;
- struct rt_hi_throughput *ht_info;
-
- spinlock_t reorder_spinlock;
- u8 reg_dot11ht_oper_rate_set[16];
- u8 reg_dot11tx_ht_oper_rate_set[16];
- u8 dot11ht_oper_rate_set[16];
- u8 reg_ht_supp_rate_set[16];
- u8 ht_curr_op_rate;
- u8 HTHighestOperaRate;
- u8 tx_dis_rate_fallback;
- u8 tx_use_drv_assinged_rate;
- u8 tx_enable_fw_calc_dur;
- atomic_t atm_swbw;
-
- struct list_head Tx_TS_Admit_List;
- struct list_head Tx_TS_Pending_List;
- struct list_head Tx_TS_Unused_List;
- struct tx_ts_record tx_ts_records[TOTAL_TS_NUM];
- struct list_head Rx_TS_Admit_List;
- struct list_head Rx_TS_Pending_List;
- struct list_head Rx_TS_Unused_List;
- struct rx_ts_record rx_ts_records[TOTAL_TS_NUM];
- struct rx_reorder_entry RxReorderEntry[128];
- struct list_head RxReorder_Unused_List;
-
- /* Bookkeeping structures */
- struct net_device_stats stats;
- struct rtllib_softmac_stats softmac_stats;
-
- /* Probe / Beacon management */
- struct list_head network_free_list;
- struct list_head network_list;
- struct rtllib_network *networks;
- int scans;
- int scan_age;
-
- int iw_mode; /* operating mode (IW_MODE_*) */
-
- spinlock_t lock;
- spinlock_t wpax_suitlist_lock;
-
- int tx_headroom; /* Set to size of any additional room needed at front
- * of allocated Tx SKBs
- */
- u32 config;
-
- /* WEP and other encryption related settings at the device level */
- int open_wep; /* Set to 1 to allow unencrypted frames */
- int auth_mode;
- int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
- * WEP key changes
- */
-
- int ieee802_1x; /* is IEEE 802.1X used */
-
- /* WPA data */
- bool half_wireless_n24g_mode;
- int wpa_enabled;
- int drop_unencrypted;
- int tkip_countermeasures;
- int privacy_invoked;
- size_t wpa_ie_len;
- u8 *wpa_ie;
- size_t wps_ie_len;
- u8 *wps_ie;
- u8 ap_mac_addr[ETH_ALEN];
- u16 pairwise_key_type;
- u16 group_key_type;
-
- struct lib80211_crypt_info crypt_info;
-
- struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY];
-
- struct rt_pmkid_list pmkid_list[NUM_PMKID_CACHE];
-
- /* Fragmentation structures */
- struct rtllib_frag_entry frag_cache[17][RTLLIB_FRAG_CACHE_LEN];
- unsigned int frag_next_idx[17];
- u16 fts; /* Fragmentation Threshold */
-#define DEFAULT_RTS_THRESHOLD 2346U
-#define MIN_RTS_THRESHOLD 1
-#define MAX_RTS_THRESHOLD 2346U
- u16 rts; /* RTS threshold */
-
- /* Association info */
- u8 bssid[ETH_ALEN];
-
- /* This stores infos for the current network.
- * Either the network we are associated in INFRASTRUCTURE
- * or the network that we are creating in MASTER mode.
- * ad-hoc is a mixture ;-).
- * Note that in infrastructure mode, even when not associated,
- * fields bssid and essid may be valid (if wpa_set and essid_set
- * are true) as thy carry the value set by the user via iwconfig
- */
- struct rtllib_network current_network;
-
- enum rtl_link_state link_state;
-
- int mode; /* A, B, G */
-
- /* used for forcing the ibss workqueue to terminate
- * without wait for the syncro scan to terminate
- */
- short sync_scan_hurryup;
- u16 scan_watch_dog;
-
- /* map of allowed channels. 0 is dummy */
- u8 active_channel_map[MAX_CHANNEL_NUMBER + 1];
-
- int rate; /* current rate */
- int basic_rate;
-
- /* this contains flags for selectively enable softmac support */
- u16 softmac_features;
-
- /* if the sequence control field is not filled by HW */
- u16 seq_ctrl[5];
-
- /* association procedure transaction sequence number */
- u16 associate_seq;
-
- /* AID for RTXed association responses */
- u16 assoc_id;
-
- /* power save mode related*/
- u8 ack_tx_to_ieee;
- short ps;
- short sta_sleep;
- int ps_timeout;
- int ps_period;
- struct work_struct ps_task;
- u64 ps_time;
- bool polling;
-
- /* used if IEEE_SOFTMAC_TX_QUEUE is set */
- short queue_stop;
- short scanning_continue;
- short proto_started;
- short proto_stoppping;
-
- struct mutex wx_mutex;
- struct mutex scan_mutex;
- struct mutex ips_mutex;
-
- spinlock_t mgmt_tx_lock;
- spinlock_t beacon_lock;
-
- short beacon_txing;
-
- short wap_set;
- short ssid_set;
-
- /* set on initialization */
- unsigned int wmm_acm;
-
- /* for discarding duplicated packets in IBSS */
- struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE];
-
- /* for discarding duplicated packets in BSS */
- u16 last_rxseq_num[17]; /* rx seq previous per-tid */
- u16 last_rxfrag_num[17];/* tx frag previous per-tid */
- unsigned long last_packet_time[17];
-
- /* for PS mode */
- unsigned long last_rx_ps_time;
- bool awake_pkt_sent;
- u8 lps_delay_cnt;
-
- /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */
- struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM];
- int mgmt_queue_head;
- int mgmt_queue_tail;
- u8 asoc_retry_count;
- struct sk_buff_head skb_waitq[MAX_QUEUE_SIZE];
-
- bool bdynamic_txpower_enable;
-
- bool bCTSToSelfEnable;
-
- u32 fsync_time_interval;
- u32 fsync_rate_bitmap;
- u8 fsync_rssi_threshold;
- bool bfsync_enable;
-
- u8 fsync_multiple_timeinterval;
- u32 fsync_firstdiff_ratethreshold;
- u32 fsync_seconddiff_ratethreshold;
- enum fsync_state fsync_state;
- bool bis_any_nonbepkts;
- struct bandwidth_autoswitch bandwidth_auto_switch;
- bool FwRWRF;
-
- struct rt_link_detect link_detect_info;
- bool is_aggregate_frame;
- struct rt_pwr_save_ctrl pwr_save_ctrl;
-
- /* used if IEEE_SOFTMAC_TX_QUEUE is set */
- struct tx_pending tx_pending;
-
- /* used if IEEE_SOFTMAC_ASSOCIATE is set */
- struct timer_list associate_timer;
-
- /* used if IEEE_SOFTMAC_BEACONS is set */
- u8 need_sw_enc;
- struct work_struct associate_complete_wq;
- struct work_struct ips_leave_wq;
- struct delayed_work associate_procedure_wq;
- struct delayed_work softmac_scan_wq;
- struct delayed_work associate_retry_wq;
- struct delayed_work hw_wakeup_wq;
- struct delayed_work hw_sleep_wq;
- struct delayed_work link_change_wq;
- struct work_struct wx_sync_scan_wq;
-
- union {
- struct rtllib_rxb *rfd_array[REORDER_WIN_SIZE];
- struct rtllib_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
- struct rtllib_rxb *prxb_indicate_array[REORDER_WIN_SIZE];
- struct {
- struct sw_chnl_cmd PreCommonCmd[MAX_PRECMD_CNT];
- struct sw_chnl_cmd PostCommonCmd[MAX_POSTCMD_CNT];
- struct sw_chnl_cmd RfDependCmd[MAX_RFDEPENDCMD_CNT];
- };
- };
-
- /* Callback functions */
-
- /* Softmac-generated frames (management) are TXed via this
- * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
- * not set. As some cards may have different HW queues that
- * one might want to use for data and management frames
- * the option to have two callbacks might be useful.
- * This function can't sleep.
- */
- int (*softmac_hard_start_xmit)(struct sk_buff *skb,
- struct net_device *dev);
-
- /* used instead of hard_start_xmit (not softmac_hard_start_xmit)
- * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
- * then also management frames are sent via this callback.
- * This function can't sleep.
- */
- void (*softmac_data_hard_start_xmit)(struct sk_buff *skb,
- struct net_device *dev, int rate);
-
- /* ask to the driver to retune the radio.
- * This function can sleep. the driver should ensure
- * the radio has been switched before return.
- */
- void (*set_chan)(struct net_device *dev, u8 ch);
-
- /* indicate the driver that the link state is changed
- * for example it may indicate the card is associated now.
- * Driver might be interested in this to apply RX filter
- * rules or simply light the LINK led
- */
- void (*link_change)(struct net_device *dev);
-
- /* power save mode related */
- void (*sta_wake_up)(struct net_device *dev);
- void (*enter_sleep_state)(struct net_device *dev, u64 time);
- short (*ps_is_queue_empty)(struct net_device *dev);
- int (*handle_beacon)(struct net_device *dev,
- struct rtllib_beacon *beacon,
- struct rtllib_network *network);
- int (*handle_assoc_response)(struct net_device *dev,
- struct rtllib_assoc_response_frame *resp,
- struct rtllib_network *network);
-
- /* check whether Tx hw resource available */
- short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
- void (*set_bw_mode_handler)(struct net_device *dev,
- enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset);
- bool (*get_nmode_support_by_sec_cfg)(struct net_device *dev);
- void (*set_wireless_mode)(struct net_device *dev, u8 wireless_mode);
- bool (*get_half_nmode_support_by_aps_handler)(struct net_device *dev);
- u8 (*rtllib_ap_sec_type)(struct rtllib_device *ieee);
- void (*init_gain_handler)(struct net_device *dev, u8 operation);
- void (*scan_operation_backup_handler)(struct net_device *dev,
- u8 operation);
- void (*set_hw_reg_handler)(struct net_device *dev, u8 variable, u8 *val);
-
- void (*allow_all_dest_addr_handler)(struct net_device *dev,
- bool allow_all_da,
- bool write_into_reg);
-
- void (*rtllib_ips_leave_wq)(struct net_device *dev);
- void (*rtllib_ips_leave)(struct net_device *dev);
- void (*leisure_ps_leave)(struct net_device *dev);
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_rtllib
- */
- u8 priv[];
-};
-
-#define IEEE_MODE_MASK (WIRELESS_MODE_B | WIRELESS_MODE_G)
-
-/* Generate a 802.11 header */
-
-/* Uses the channel change callback directly
- * instead of [start/stop] scan callbacks
- */
-#define IEEE_SOFTMAC_SCAN (1 << 2)
-
-/* Perform authentication and association handshake */
-#define IEEE_SOFTMAC_ASSOCIATE (1 << 3)
-
-/* Generate probe requests */
-#define IEEE_SOFTMAC_PROBERQ (1 << 4)
-
-/* Generate response to probe requests */
-#define IEEE_SOFTMAC_PROBERS (1 << 5)
-
-/* The ieee802.11 stack will manage the netif queue
- * wake/stop for the driver, taking care of 802.11
- * fragmentation. See softmac.c for details.
- */
-#define IEEE_SOFTMAC_TX_QUEUE (1 << 7)
-
-/* Uses only the softmac_data_hard_start_xmit
- * even for TX management frames.
- */
-#define IEEE_SOFTMAC_SINGLE_QUEUE (1 << 8)
-
-/* Generate beacons. The stack will enqueue beacons
- * to the card
- */
-#define IEEE_SOFTMAC_BEACONS (1 << 6)
-
-static inline void *rtllib_priv(struct net_device *dev)
-{
- return ((struct rtllib_device *)netdev_priv(dev))->priv;
-}
-
-static inline int rtllib_is_empty_essid(const char *essid, int essid_len)
-{
- /* Single white space is for Linksys APs */
- if (essid_len == 1 && essid[0] == ' ')
- return 1;
-
- /* Otherwise, if the entire essid is 0, we assume it is hidden */
- while (essid_len) {
- essid_len--;
- if (essid[essid_len] != '\0')
- return 0;
- }
-
- return 1;
-}
-
-static inline int rtllib_get_hdrlen(u16 fc)
-{
- int hdrlen = RTLLIB_3ADDR_LEN;
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case RTLLIB_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = RTLLIB_4ADDR_LEN; /* Addr4 */
- if (RTLLIB_QOS_HAS_SEQ(fc))
- hdrlen += 2; /* QOS ctrl*/
- break;
- case RTLLIB_FTYPE_CTL:
- switch (WLAN_FC_GET_STYPE(fc)) {
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = RTLLIB_1ADDR_LEN;
- break;
- default:
- hdrlen = RTLLIB_2ADDR_LEN;
- break;
- }
- break;
- }
-
- return hdrlen;
-}
-
-static inline int rtllib_is_ofdm_rate(u8 rate)
-{
- switch (rate & ~RTLLIB_BASIC_RATE_MASK) {
- case RTLLIB_OFDM_RATE_6MB:
- case RTLLIB_OFDM_RATE_9MB:
- case RTLLIB_OFDM_RATE_12MB:
- case RTLLIB_OFDM_RATE_18MB:
- case RTLLIB_OFDM_RATE_24MB:
- case RTLLIB_OFDM_RATE_36MB:
- case RTLLIB_OFDM_RATE_48MB:
- case RTLLIB_OFDM_RATE_54MB:
- return 1;
- }
- return 0;
-}
-
-static inline int rtllib_is_cck_rate(u8 rate)
-{
- switch (rate & ~RTLLIB_BASIC_RATE_MASK) {
- case RTLLIB_CCK_RATE_1MB:
- case RTLLIB_CCK_RATE_2MB:
- case RTLLIB_CCK_RATE_5MB:
- case RTLLIB_CCK_RATE_11MB:
- return 1;
- }
- return 0;
-}
-
-/* rtllib.c */
-void free_rtllib(struct net_device *dev);
-struct net_device *alloc_rtllib(int sizeof_priv);
-
-/* rtllib_tx.c */
-
-int rtllib_encrypt_fragment(struct rtllib_device *ieee,
- struct sk_buff *frag,
- int hdr_len);
-
-netdev_tx_t rtllib_xmit(struct sk_buff *skb, struct net_device *dev);
-void rtllib_txb_free(struct rtllib_txb *txb);
-
-/* rtllib_rx.c */
-int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats);
-int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel);
-
-/* rtllib_wx.c */
-int rtllib_wx_get_scan(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int rtllib_wx_set_encode(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int rtllib_wx_get_encode(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int rtllib_wx_set_auth(struct rtllib_device *ieee,
- struct iw_request_info *info,
- struct iw_param *data, char *extra);
-int rtllib_wx_set_mlme(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len);
-
-/* rtllib_softmac.c */
-int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats, u16 type,
- u16 stype);
-void rtllib_softmac_new_net(struct rtllib_device *ieee,
- struct rtllib_network *net);
-
-void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn);
-void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee);
-
-int rtllib_softmac_init(struct rtllib_device *ieee);
-void rtllib_softmac_free(struct rtllib_device *ieee);
-void rtllib_disassociate(struct rtllib_device *ieee);
-void rtllib_stop_scan(struct rtllib_device *ieee);
-bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan);
-void rtllib_stop_scan_syncro(struct rtllib_device *ieee);
-void rtllib_start_scan_syncro(struct rtllib_device *ieee);
-void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr);
-void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee);
-void rtllib_start_protocol(struct rtllib_device *ieee);
-void rtllib_stop_protocol(struct rtllib_device *ieee);
-
-void rtllib_enable_net_monitor_mode(struct net_device *dev, bool init_state);
-void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state);
-
-void rtllib_softmac_stop_protocol(struct rtllib_device *ieee);
-void rtllib_softmac_start_protocol(struct rtllib_device *ieee);
-
-void rtllib_reset_queue(struct rtllib_device *ieee);
-void rtllib_wake_all_queues(struct rtllib_device *ieee);
-void rtllib_stop_all_queues(struct rtllib_device *ieee);
-
-void notify_wx_assoc_event(struct rtllib_device *ieee);
-void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success);
-
-void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee);
-u8 rtllib_ap_sec_type(struct rtllib_device *ieee);
-
-/* rtllib_softmac_wx.c */
-
-int rtllib_wx_get_wap(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *ext);
-
-int rtllib_wx_set_wap(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *awrq, char *extra);
-
-int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-int rtllib_wx_set_rate(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_get_rate(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-int rtllib_wx_set_essid(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-
-int rtllib_wx_get_freq(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b);
-void rtllib_wx_sync_scan_wq(void *data);
-
-int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_set_power(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_get_power(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_set_rts(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-int rtllib_wx_get_rts(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-#define MAX_RECEIVE_BUFFER_SIZE 9100
-
-void ht_set_connect_bw_mode(struct rtllib_device *ieee,
- enum ht_channel_width bandwidth,
- enum ht_extchnl_offset Offset);
-void ht_update_default_setting(struct rtllib_device *ieee);
-void ht_construct_capability_element(struct rtllib_device *ieee,
- u8 *pos_ht_cap, u8 *len,
- u8 is_encrypt, bool assoc);
-void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee,
- u8 *posRT2RTAgg, u8 *len);
-void ht_on_assoc_rsp(struct rtllib_device *ieee);
-void ht_initialize_ht_info(struct rtllib_device *ieee);
-void ht_initialize_bss_desc(struct bss_ht *bss_ht);
-void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee,
- struct rtllib_network *network);
-void HT_update_self_and_peer_setting(struct rtllib_device *ieee,
- struct rtllib_network *network);
-u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet,
- u8 *pMCSFilter);
-extern u8 MCS_FILTER_ALL[];
-extern u16 MCS_DATA_RATE[2][2][77];
-u8 ht_c_check(struct rtllib_device *ieee, u8 *frame);
-void ht_reset_iot_setting(struct rt_hi_throughput *ht_info);
-bool is_ht_half_nmode_aps(struct rtllib_device *ieee);
-u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 nDataRate);
-int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb);
-int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb);
-int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb);
-void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
- u8 policy, u8 overwrite_pending);
-void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
- struct ts_common_info *ts_common_info,
- enum tr_select tx_rx_select);
-void rtllib_ba_setup_timeout(struct timer_list *t);
-void rtllib_tx_ba_inact_timeout(struct timer_list *t);
-void rtllib_rx_ba_inact_timeout(struct timer_list *t);
-void rtllib_reset_ba_entry(struct ba_record *ba);
-bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS, u8 *addr,
- u8 TID, enum tr_select tx_rx_select, bool add_new_ts);
-void rtllib_ts_init(struct rtllib_device *ieee);
-void rtllib_ts_start_add_ba_process(struct rtllib_device *ieee,
- struct tx_ts_record *pTxTS);
-void remove_peer_ts(struct rtllib_device *ieee, u8 *addr);
-void remove_all_ts(struct rtllib_device *ieee);
-
-static inline const char *escape_essid(const char *essid, u8 essid_len)
-{
- static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-
- if (rtllib_is_empty_essid(essid, essid_len)) {
- memcpy(escaped, "<hidden>", sizeof("<hidden>"));
- return escaped;
- }
-
- snprintf(escaped, sizeof(escaped), "%*pE", essid_len, essid);
- return escaped;
-}
-
-/* fun with the built-in rtllib stack... */
-bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn);
-
-/* For the function is more related to hardware setting, it's better to use the
- * ieee handler to refer to it.
- */
-void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee,
- struct rx_ts_record *ts);
-int rtllib_parse_info_param(struct rtllib_device *ieee,
- struct rtllib_info_element *info_element,
- u16 length,
- struct rtllib_network *network,
- struct rtllib_rx_stats *stats);
-
-void rtllib_indicate_packets(struct rtllib_device *ieee,
- struct rtllib_rxb **prxb_indicate_array, u8 index);
-#define RT_ASOC_RETRY_LIMIT 5
-u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee);
-
-#endif /* RTLLIB_H */
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
deleted file mode 100644
index 138733cb00e2..000000000000
--- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c
+++ /dev/null
@@ -1,411 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Host AP crypt: host-based CCMP encryption implementation for Host AP driver
- *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/string.h>
-#include <linux/wireless.h>
-#include "rtllib.h"
-
-#include <linux/crypto.h>
-#include <crypto/aead.h>
-
-#include <linux/scatterlist.h>
-
-#define AES_BLOCK_LEN 16
-#define CCMP_HDR_LEN 8
-#define CCMP_MIC_LEN 8
-#define CCMP_TK_LEN 16
-#define CCMP_PN_LEN 6
-
-struct rtllib_ccmp_data {
- u8 key[CCMP_TK_LEN];
- int key_set;
-
- u8 tx_pn[CCMP_PN_LEN];
- u8 rx_pn[CCMP_PN_LEN];
-
- u32 dot11rsna_stats_ccmp_format_errors;
- u32 dot11rsna_stats_ccmp_replays;
- u32 dot11rsna_stats_ccmp_decrypt_errors;
-
- int key_idx;
-
- struct crypto_aead *tfm;
-
- /* scratch buffers for virt_to_page() (crypto API) */
- u8 tx_aad[2 * AES_BLOCK_LEN];
- u8 rx_aad[2 * AES_BLOCK_LEN];
-};
-
-static void *rtllib_ccmp_init(int key_idx)
-{
- struct rtllib_ccmp_data *priv;
-
- priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
- if (!priv)
- goto fail;
- priv->key_idx = key_idx;
-
- priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(priv->tfm)) {
- pr_debug("Could not allocate crypto API aes\n");
- priv->tfm = NULL;
- goto fail;
- }
- return priv;
-
-fail:
- if (priv) {
- if (priv->tfm)
- crypto_free_aead(priv->tfm);
- kfree(priv);
- }
-
- return NULL;
-}
-
-static void rtllib_ccmp_deinit(void *priv)
-{
- struct rtllib_ccmp_data *_priv = priv;
-
- if (_priv && _priv->tfm)
- crypto_free_aead(_priv->tfm);
- kfree(priv);
-}
-
-static int ccmp_init_iv_and_aad(struct ieee80211_hdr *hdr,
- u8 *pn, u8 *iv, u8 *aad)
-{
- u8 *pos, qc = 0;
- size_t aad_len;
- u16 fc;
- int a4_included, qc_included;
-
- fc = le16_to_cpu(hdr->frame_control);
- a4_included = ieee80211_has_a4(hdr->frame_control);
-
- qc_included = ((WLAN_FC_GET_TYPE(fc) == RTLLIB_FTYPE_DATA) &&
- (WLAN_FC_GET_STYPE(fc) & 0x80));
- aad_len = 22;
- if (a4_included)
- aad_len += 6;
- if (qc_included) {
- pos = (u8 *)&hdr->addr4;
- if (a4_included)
- pos += 6;
- qc = *pos & 0x0f;
- aad_len += 2;
- }
- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
- * mode authentication are not allowed to collide, yet both are derived
- * from the same vector. We only set L := 1 here to indicate that the
- * data size can be represented in (L+1) bytes. The CCM layer will take
- * care of storing the data length in the top (L+1) bytes and setting
- * and clearing the other bits as is required to derive the two IVs.
- */
- iv[0] = 0x1;
-
- /* Nonce: QC | A2 | PN */
- iv[1] = qc;
- memcpy(iv + 2, hdr->addr2, ETH_ALEN);
- memcpy(iv + 8, pn, CCMP_PN_LEN);
-
- /* AAD:
- * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
- * A1 | A2 | A3
- * SC with bits 4..15 (seq#) masked to zero
- * A4 (if present)
- * QC (if present)
- */
- pos = (u8 *)hdr;
- aad[0] = pos[0] & 0x8f;
- aad[1] = pos[1] & 0xc7;
- memcpy(&aad[2], &hdr->addr1, ETH_ALEN);
- memcpy(&aad[8], &hdr->addr2, ETH_ALEN);
- memcpy(&aad[14], &hdr->addr3, ETH_ALEN);
- pos = (u8 *)&hdr->seq_ctrl;
- aad[20] = pos[0] & 0x0f;
- aad[21] = 0; /* all bits masked */
- memset(aad + 22, 0, 8);
- if (a4_included)
- memcpy(aad + 22, hdr->addr4, ETH_ALEN);
- if (qc_included) {
- aad[a4_included ? 28 : 22] = qc;
- /* rest of QC masked */
- }
-
- return aad_len;
-}
-
-static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct rtllib_ccmp_data *key = priv;
- int i;
- u8 *pos;
- struct ieee80211_hdr *hdr;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- if (skb_headroom(skb) < CCMP_HDR_LEN ||
- skb_tailroom(skb) < CCMP_MIC_LEN ||
- skb->len < hdr_len)
- return -1;
-
- pos = skb_push(skb, CCMP_HDR_LEN);
- memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
- pos += hdr_len;
-
- i = CCMP_PN_LEN - 1;
- while (i >= 0) {
- key->tx_pn[i]++;
- if (key->tx_pn[i] != 0)
- break;
- i--;
- }
-
- *pos++ = key->tx_pn[5];
- *pos++ = key->tx_pn[4];
- *pos++ = 0;
- *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */;
- *pos++ = key->tx_pn[3];
- *pos++ = key->tx_pn[2];
- *pos++ = key->tx_pn[1];
- *pos++ = key->tx_pn[0];
-
- hdr = (struct ieee80211_hdr *)skb->data;
- if (!tcb_desc->hw_sec) {
- struct aead_request *req;
- struct scatterlist sg[2];
- u8 *aad = key->tx_aad;
- u8 iv[AES_BLOCK_LEN];
- int aad_len, ret;
- int data_len = skb->len - hdr_len - CCMP_HDR_LEN;
-
- req = aead_request_alloc(key->tfm, GFP_ATOMIC);
- if (!req)
- return -ENOMEM;
-
- aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad);
-
- skb_put(skb, CCMP_MIC_LEN);
- sg_init_table(sg, 2);
- sg_set_buf(&sg[0], aad, aad_len);
- sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN,
- data_len + CCMP_MIC_LEN);
-
- aead_request_set_callback(req, 0, NULL, NULL);
- aead_request_set_ad(req, aad_len);
- aead_request_set_crypt(req, sg, sg, data_len, iv);
-
- ret = crypto_aead_encrypt(req);
- aead_request_free(req);
-
- return ret;
- }
-
- return 0;
-}
-
-static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct rtllib_ccmp_data *key = priv;
- u8 keyidx, *pos;
- struct ieee80211_hdr *hdr;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u8 pn[6];
-
- if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
- key->dot11rsna_stats_ccmp_format_errors++;
- return -1;
- }
-
- hdr = (struct ieee80211_hdr *)skb->data;
- pos = skb->data + hdr_len;
- keyidx = pos[3];
- if (!(keyidx & (1 << 5))) {
- if (net_ratelimit()) {
- pr_debug("CCMP: received packet without ExtIV flag from %pM\n",
- hdr->addr2);
- }
- key->dot11rsna_stats_ccmp_format_errors++;
- return -2;
- }
- keyidx >>= 6;
- if (key->key_idx != keyidx) {
- pr_debug("CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n",
- key->key_idx, keyidx, priv);
- return -6;
- }
- if (!key->key_set) {
- if (net_ratelimit()) {
- pr_debug("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n",
- hdr->addr2, keyidx);
- }
- return -3;
- }
-
- pn[0] = pos[7];
- pn[1] = pos[6];
- pn[2] = pos[5];
- pn[3] = pos[4];
- pn[4] = pos[1];
- pn[5] = pos[0];
- pos += 8;
- if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
- key->dot11rsna_stats_ccmp_replays++;
- return -4;
- }
- if (!tcb_desc->hw_sec) {
- size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN;
- struct aead_request *req;
- struct scatterlist sg[2];
- u8 *aad = key->rx_aad;
- u8 iv[AES_BLOCK_LEN];
- int aad_len, ret;
-
- req = aead_request_alloc(key->tfm, GFP_ATOMIC);
- if (!req)
- return -ENOMEM;
-
- aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad);
-
- sg_init_table(sg, 2);
- sg_set_buf(&sg[0], aad, aad_len);
- sg_set_buf(&sg[1], pos, data_len);
-
- aead_request_set_callback(req, 0, NULL, NULL);
- aead_request_set_ad(req, aad_len);
- aead_request_set_crypt(req, sg, sg, data_len, iv);
-
- ret = crypto_aead_decrypt(req);
- aead_request_free(req);
-
- if (ret) {
- if (net_ratelimit()) {
- pr_debug("CCMP: decrypt failed: STA= %pM\n",
- hdr->addr2);
- }
- key->dot11rsna_stats_ccmp_decrypt_errors++;
- return -5;
- }
-
- memcpy(key->rx_pn, pn, CCMP_PN_LEN);
- }
- /* Remove hdr and MIC */
- memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
- skb_pull(skb, CCMP_HDR_LEN);
- skb_trim(skb, skb->len - CCMP_MIC_LEN);
-
- return keyidx;
-}
-
-static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
-{
- struct rtllib_ccmp_data *data = priv;
- int keyidx;
- struct crypto_aead *tfm = data->tfm;
-
- keyidx = data->key_idx;
- memset(data, 0, sizeof(*data));
- data->key_idx = keyidx;
- data->tfm = tfm;
- if (len == CCMP_TK_LEN) {
- memcpy(data->key, key, CCMP_TK_LEN);
- data->key_set = 1;
- if (seq) {
- data->rx_pn[0] = seq[5];
- data->rx_pn[1] = seq[4];
- data->rx_pn[2] = seq[3];
- data->rx_pn[3] = seq[2];
- data->rx_pn[4] = seq[1];
- data->rx_pn[5] = seq[0];
- }
- if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) ||
- crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN))
- return -1;
- } else if (len == 0) {
- data->key_set = 0;
- } else {
- return -1;
- }
-
- return 0;
-}
-
-static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
-{
- struct rtllib_ccmp_data *data = priv;
-
- if (len < CCMP_TK_LEN)
- return -1;
-
- if (!data->key_set)
- return 0;
- memcpy(key, data->key, CCMP_TK_LEN);
-
- if (seq) {
- seq[0] = data->tx_pn[5];
- seq[1] = data->tx_pn[4];
- seq[2] = data->tx_pn[3];
- seq[3] = data->tx_pn[2];
- seq[4] = data->tx_pn[1];
- seq[5] = data->tx_pn[0];
- }
-
- return CCMP_TK_LEN;
-}
-
-static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv)
-{
- struct rtllib_ccmp_data *ccmp = priv;
-
- seq_printf(m,
- "key[%d] alg=CCMP key_set=%d tx_pn=%pM rx_pn=%pM format_errors=%d replays=%d decrypt_errors=%d\n",
- ccmp->key_idx, ccmp->key_set,
- ccmp->tx_pn, ccmp->rx_pn,
- ccmp->dot11rsna_stats_ccmp_format_errors,
- ccmp->dot11rsna_stats_ccmp_replays,
- ccmp->dot11rsna_stats_ccmp_decrypt_errors);
-}
-
-static const struct lib80211_crypto_ops rtllib_crypt_ccmp = {
- .name = "R-CCMP",
- .init = rtllib_ccmp_init,
- .deinit = rtllib_ccmp_deinit,
- .encrypt_mpdu = rtllib_ccmp_encrypt,
- .decrypt_mpdu = rtllib_ccmp_decrypt,
- .encrypt_msdu = NULL,
- .decrypt_msdu = NULL,
- .set_key = rtllib_ccmp_set_key,
- .get_key = rtllib_ccmp_get_key,
- .print_stats = rtllib_ccmp_print_stats,
- .extra_mpdu_prefix_len = CCMP_HDR_LEN,
- .extra_mpdu_postfix_len = CCMP_MIC_LEN,
- .owner = THIS_MODULE,
-};
-
-static int __init rtllib_crypto_ccmp_init(void)
-{
- return lib80211_register_crypto_ops(&rtllib_crypt_ccmp);
-}
-
-static void __exit rtllib_crypto_ccmp_exit(void)
-{
- lib80211_unregister_crypto_ops(&rtllib_crypt_ccmp);
-}
-
-module_init(rtllib_crypto_ccmp_init);
-module_exit(rtllib_crypto_ccmp_exit);
-
-MODULE_DESCRIPTION("Support module for rtllib CCMP crypto");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
deleted file mode 100644
index e544379bfa91..000000000000
--- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c
+++ /dev/null
@@ -1,706 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
- *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- */
-
-#include <crypto/arc4.h>
-#include <crypto/hash.h>
-#include <linux/fips.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/if_ether.h>
-#include <linux/if_arp.h>
-#include <linux/string.h>
-#include <linux/crc32.h>
-#include <linux/etherdevice.h>
-
-#include "rtllib.h"
-
-struct rtllib_tkip_data {
-#define TKIP_KEY_LEN 32
- u8 key[TKIP_KEY_LEN];
- int key_set;
-
- u32 tx_iv32;
- u16 tx_iv16;
- u16 tx_ttak[5];
- int tx_phase1_done;
-
- u32 rx_iv32;
- u16 rx_iv16;
- bool initialized;
- u16 rx_ttak[5];
- int rx_phase1_done;
- u32 rx_iv32_new;
- u16 rx_iv16_new;
-
- u32 dot11RSNAStatsTKIPReplays;
- u32 dot11RSNAStatsTKIPICVErrors;
- u32 dot11RSNAStatsTKIPLocalMICFailures;
-
- int key_idx;
- struct arc4_ctx rx_ctx_arc4;
- struct arc4_ctx tx_ctx_arc4;
- struct crypto_shash *rx_tfm_michael;
- struct crypto_shash *tx_tfm_michael;
- /* scratch buffers for virt_to_page() (crypto API) */
- u8 rx_hdr[16];
- u8 tx_hdr[16];
-};
-
-static void *rtllib_tkip_init(int key_idx)
-{
- struct rtllib_tkip_data *priv;
-
- if (fips_enabled)
- return NULL;
-
- priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
- if (!priv)
- goto fail;
- priv->key_idx = key_idx;
-
- priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->tx_tfm_michael)) {
- pr_debug("Could not allocate crypto API michael_mic\n");
- priv->tx_tfm_michael = NULL;
- goto fail;
- }
-
- priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->rx_tfm_michael)) {
- pr_debug("Could not allocate crypto API michael_mic\n");
- priv->rx_tfm_michael = NULL;
- goto fail;
- }
- return priv;
-
-fail:
- if (priv) {
- crypto_free_shash(priv->tx_tfm_michael);
- crypto_free_shash(priv->rx_tfm_michael);
- kfree(priv);
- }
-
- return NULL;
-}
-
-static void rtllib_tkip_deinit(void *priv)
-{
- struct rtllib_tkip_data *_priv = priv;
-
- if (_priv) {
- crypto_free_shash(_priv->tx_tfm_michael);
- crypto_free_shash(_priv->rx_tfm_michael);
- }
- kfree_sensitive(priv);
-}
-
-static inline u16 RotR1(u16 val)
-{
- return (val >> 1) | (val << 15);
-}
-
-static inline u8 Lo8(u16 val)
-{
- return val & 0xff;
-}
-
-static inline u8 Hi8(u16 val)
-{
- return val >> 8;
-}
-
-static inline u16 Lo16(u32 val)
-{
- return val & 0xffff;
-}
-
-static inline u16 Hi16(u32 val)
-{
- return val >> 16;
-}
-
-static inline u16 Mk16(u8 hi, u8 lo)
-{
- return lo | (hi << 8);
-}
-
-static inline u16 Mk16_le(u16 *v)
-{
- return *v;
-}
-
-static const u16 Sbox[256] = {
- 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
- 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
- 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
- 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
- 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
- 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
- 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
- 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
- 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
- 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
- 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
- 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
- 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
- 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
- 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
- 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
- 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
- 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
- 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
- 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
- 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
- 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
- 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
- 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
- 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
- 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
- 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
- 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
- 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
- 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
- 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
- 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
-};
-
-static inline u16 _S_(u16 v)
-{
- u16 t = Sbox[Hi8(v)];
- return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
-}
-
-#define PHASE1_LOOP_COUNT 8
-
-static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
-{
- int i, j;
-
- /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
- TTAK[0] = Lo16(IV32);
- TTAK[1] = Hi16(IV32);
- TTAK[2] = Mk16(TA[1], TA[0]);
- TTAK[3] = Mk16(TA[3], TA[2]);
- TTAK[4] = Mk16(TA[5], TA[4]);
-
- for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
- j = 2 * (i & 1);
- TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
- TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
- TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
- TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
- TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
- }
-}
-
-static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
- u16 IV16)
-{
- /* Make temporary area overlap WEP seed so that the final copy can be
- * avoided on little endian hosts.
- */
- u16 *PPK = (u16 *)&WEPSeed[4];
-
- /* Step 1 - make copy of TTAK and bring in TSC */
- PPK[0] = TTAK[0];
- PPK[1] = TTAK[1];
- PPK[2] = TTAK[2];
- PPK[3] = TTAK[3];
- PPK[4] = TTAK[4];
- PPK[5] = TTAK[4] + IV16;
-
- /* Step 2 - 96-bit bijective mixing using S-box */
- PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *)&TK[0]));
- PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *)&TK[2]));
- PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *)&TK[4]));
- PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *)&TK[6]));
- PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *)&TK[8]));
- PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *)&TK[10]));
-
- PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *)&TK[12]));
- PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *)&TK[14]));
- PPK[2] += RotR1(PPK[1]);
- PPK[3] += RotR1(PPK[2]);
- PPK[4] += RotR1(PPK[3]);
- PPK[5] += RotR1(PPK[4]);
-
- /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
- * WEPSeed[0..2] is transmitted as WEP IV
- */
- WEPSeed[0] = Hi8(IV16);
- WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
- WEPSeed[2] = Lo8(IV16);
- WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *)&TK[0])) >> 1);
-
-#ifdef __BIG_ENDIAN
- {
- int i;
-
- for (i = 0; i < 6; i++)
- PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
- }
-#endif
-}
-
-static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
- int len;
- u8 *pos;
- struct ieee80211_hdr *hdr;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- int ret = 0;
- u8 rc4key[16], *icv;
- u32 crc;
-
- if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
- skb->len < hdr_len)
- return -1;
-
- hdr = (struct ieee80211_hdr *)skb->data;
-
- if (!tcb_desc->hw_sec) {
- if (!tkey->tx_phase1_done) {
- tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
- tkey->tx_iv32);
- tkey->tx_phase1_done = 1;
- }
- tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak,
- tkey->tx_iv16);
- } else {
- tkey->tx_phase1_done = 1;
- }
-
- len = skb->len - hdr_len;
- pos = skb_push(skb, 8);
- memmove(pos, pos + 8, hdr_len);
- pos += hdr_len;
-
- if (tcb_desc->hw_sec) {
- *pos++ = Hi8(tkey->tx_iv16);
- *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F;
- *pos++ = Lo8(tkey->tx_iv16);
- } else {
- *pos++ = rc4key[0];
- *pos++ = rc4key[1];
- *pos++ = rc4key[2];
- }
-
- *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */;
- *pos++ = tkey->tx_iv32 & 0xff;
- *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
- *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
- *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
-
- if (!tcb_desc->hw_sec) {
- icv = skb_put(skb, 4);
- crc = ~crc32_le(~0, pos, len);
- icv[0] = crc;
- icv[1] = crc >> 8;
- icv[2] = crc >> 16;
- icv[3] = crc >> 24;
-
- arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16);
- arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4);
- }
-
- tkey->tx_iv16++;
- if (tkey->tx_iv16 == 0) {
- tkey->tx_phase1_done = 0;
- tkey->tx_iv32++;
- }
-
- if (!tcb_desc->hw_sec)
- return ret;
- return 0;
-}
-
-static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
- u8 keyidx, *pos;
- u32 iv32;
- u16 iv16;
- struct ieee80211_hdr *hdr;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u8 rc4key[16];
- u8 icv[4];
- u32 crc;
- int plen;
-
- if (skb->len < hdr_len + 8 + 4)
- return -1;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- pos = skb->data + hdr_len;
- keyidx = pos[3];
- if (!(keyidx & (1 << 5))) {
- if (net_ratelimit()) {
- netdev_dbg(skb->dev,
- "Received packet without ExtIV flag from %pM\n",
- hdr->addr2);
- }
- return -2;
- }
- keyidx >>= 6;
- if (tkey->key_idx != keyidx) {
- netdev_dbg(skb->dev,
- "RX tkey->key_idx=%d frame keyidx=%d priv=%p\n",
- tkey->key_idx, keyidx, priv);
- return -6;
- }
- if (!tkey->key_set) {
- if (net_ratelimit()) {
- netdev_dbg(skb->dev,
- "Received packet from %pM with keyid=%d that does not have a configured key\n",
- hdr->addr2, keyidx);
- }
- return -3;
- }
- iv16 = (pos[0] << 8) | pos[2];
- iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
- pos += 8;
-
- if (!tcb_desc->hw_sec || (skb->cb[0] == 1)) {
- if ((iv32 < tkey->rx_iv32 ||
- (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) &&
- tkey->initialized) {
- if (net_ratelimit()) {
- netdev_dbg(skb->dev,
- "Replay detected: STA= %pM previous TSC %08x%04x received TSC %08x%04x\n",
- hdr->addr2, tkey->rx_iv32,
- tkey->rx_iv16, iv32, iv16);
- }
- tkey->dot11RSNAStatsTKIPReplays++;
- return -4;
- }
- tkey->initialized = true;
-
- if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
- tkip_mixing_phase1(tkey->rx_ttak, tkey->key,
- hdr->addr2, iv32);
- tkey->rx_phase1_done = 1;
- }
- tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
-
- plen = skb->len - hdr_len - 12;
-
- arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16);
- arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4);
-
- crc = ~crc32_le(~0, pos, plen);
- icv[0] = crc;
- icv[1] = crc >> 8;
- icv[2] = crc >> 16;
- icv[3] = crc >> 24;
-
- if (memcmp(icv, pos + plen, 4) != 0) {
- if (iv32 != tkey->rx_iv32) {
- /* Previously cached Phase1 result was already
- * lost, so it needs to be recalculated for the
- * next packet.
- */
- tkey->rx_phase1_done = 0;
- }
- if (net_ratelimit()) {
- netdev_dbg(skb->dev,
- "ICV error detected: STA= %pM\n",
- hdr->addr2);
- }
- tkey->dot11RSNAStatsTKIPICVErrors++;
- return -5;
- }
- }
-
- /* Update real counters only after Michael MIC verification has
- * completed
- */
- tkey->rx_iv32_new = iv32;
- tkey->rx_iv16_new = iv16;
-
- /* Remove IV and ICV */
- memmove(skb->data + 8, skb->data, hdr_len);
- skb_pull(skb, 8);
- skb_trim(skb, skb->len - 4);
-
- return keyidx;
-}
-
-static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
- u8 *data, size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm_michael);
- int err;
-
- desc->tfm = tfm_michael;
-
- if (crypto_shash_setkey(tfm_michael, key, 8))
- return -1;
-
- err = crypto_shash_init(desc);
- if (err)
- goto out;
- err = crypto_shash_update(desc, hdr, 16);
- if (err)
- goto out;
- err = crypto_shash_update(desc, data, data_len);
- if (err)
- goto out;
- err = crypto_shash_final(desc, mic);
-
-out:
- shash_desc_zero(desc);
- return err;
-}
-
-static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
-{
- struct ieee80211_hdr *hdr11;
-
- hdr11 = (struct ieee80211_hdr *)skb->data;
- switch (le16_to_cpu(hdr11->frame_control) &
- (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_TODS:
- ether_addr_copy(hdr, hdr11->addr3); /* DA */
- ether_addr_copy(hdr + ETH_ALEN, hdr11->addr2); /* SA */
- break;
- case IEEE80211_FCTL_FROMDS:
- ether_addr_copy(hdr, hdr11->addr1); /* DA */
- ether_addr_copy(hdr + ETH_ALEN, hdr11->addr3); /* SA */
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- ether_addr_copy(hdr, hdr11->addr3); /* DA */
- ether_addr_copy(hdr + ETH_ALEN, hdr11->addr4); /* SA */
- break;
- case 0:
- ether_addr_copy(hdr, hdr11->addr1); /* DA */
- ether_addr_copy(hdr + ETH_ALEN, hdr11->addr2); /* SA */
- break;
- }
-
- /* priority */
- hdr[12] = 0;
-
- /* reserved */
- hdr[13] = 0;
- hdr[14] = 0;
- hdr[15] = 0;
-}
-
-static int rtllib_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
- u8 *pos;
- struct ieee80211_hdr *hdr;
-
- hdr = (struct ieee80211_hdr *)skb->data;
-
- if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
- netdev_dbg(skb->dev,
- "Invalid packet for Michael MIC add (tailroom=%d hdr_len=%d skb->len=%d)\n",
- skb_tailroom(skb), hdr_len, skb->len);
- return -1;
- }
-
- michael_mic_hdr(skb, tkey->tx_hdr);
-
- if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_control)))
- tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
- pos = skb_put(skb, 8);
- if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
- return -1;
-
- return 0;
-}
-
-static void rtllib_michael_mic_failure(struct net_device *dev,
- struct ieee80211_hdr *hdr,
- int keyidx)
-{
- union iwreq_data wrqu;
- struct iw_michaelmicfailure ev;
-
- /* TODO: needed parameters: count, keyid, key type, TSC */
- memset(&ev, 0, sizeof(ev));
- ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
- if (hdr->addr1[0] & 0x01)
- ev.flags |= IW_MICFAILURE_GROUP;
- else
- ev.flags |= IW_MICFAILURE_PAIRWISE;
- ev.src_addr.sa_family = ARPHRD_ETHER;
- ether_addr_copy(ev.src_addr.sa_data, hdr->addr2);
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = sizeof(ev);
- wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
-}
-
-static int rtllib_michael_mic_verify(struct sk_buff *skb, int keyidx,
- int hdr_len, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
- u8 mic[8];
- struct ieee80211_hdr *hdr;
-
- hdr = (struct ieee80211_hdr *)skb->data;
-
- if (!tkey->key_set)
- return -1;
-
- michael_mic_hdr(skb, tkey->rx_hdr);
- if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_control)))
- tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
-
- if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
- return -1;
-
- if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
- struct ieee80211_hdr *hdr;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- netdev_dbg(skb->dev,
- "Michael MIC verification failed for MSDU from %pM keyidx=%d\n",
- hdr->addr2, keyidx);
- netdev_dbg(skb->dev, "%d\n",
- memcmp(mic, skb->data + skb->len - 8, 8) != 0);
- if (skb->dev) {
- pr_info("skb->dev != NULL\n");
- rtllib_michael_mic_failure(skb->dev, hdr, keyidx);
- }
- tkey->dot11RSNAStatsTKIPLocalMICFailures++;
- return -1;
- }
-
- /* Update TSC counters for RX now that the packet verification has
- * completed.
- */
- tkey->rx_iv32 = tkey->rx_iv32_new;
- tkey->rx_iv16 = tkey->rx_iv16_new;
-
- skb_trim(skb, skb->len - 8);
-
- return 0;
-}
-
-static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
- int keyidx;
- struct crypto_shash *tfm = tkey->tx_tfm_michael;
- struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
-
- keyidx = tkey->key_idx;
- memset(tkey, 0, sizeof(*tkey));
- tkey->key_idx = keyidx;
- tkey->tx_tfm_michael = tfm;
- tkey->rx_tfm_michael = tfm3;
-
- if (len == TKIP_KEY_LEN) {
- memcpy(tkey->key, key, TKIP_KEY_LEN);
- tkey->key_set = 1;
- tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
- if (seq) {
- tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
- (seq[3] << 8) | seq[2];
- tkey->rx_iv16 = (seq[1] << 8) | seq[0];
- }
- } else if (len == 0) {
- tkey->key_set = 0;
- } else {
- return -1;
- }
-
- return 0;
-}
-
-static int rtllib_tkip_get_key(void *key, int len, u8 *seq, void *priv)
-{
- struct rtllib_tkip_data *tkey = priv;
-
- if (len < TKIP_KEY_LEN)
- return -1;
-
- if (!tkey->key_set)
- return 0;
- memcpy(key, tkey->key, TKIP_KEY_LEN);
-
- if (seq) {
- /* Return the sequence number of the last transmitted frame. */
- seq[0] = tkey->tx_iv16;
- seq[1] = tkey->tx_iv16 >> 8;
- seq[2] = tkey->tx_iv32;
- seq[3] = tkey->tx_iv32 >> 8;
- seq[4] = tkey->tx_iv32 >> 16;
- seq[5] = tkey->tx_iv32 >> 24;
- }
-
- return TKIP_KEY_LEN;
-}
-
-static void rtllib_tkip_print_stats(struct seq_file *m, void *priv)
-{
- struct rtllib_tkip_data *tkip = priv;
-
- seq_printf(m,
- "key[%d] alg=TKIP key_set=%d tx_pn=%02x%02x%02x%02x%02x%02x rx_pn=%02x%02x%02x%02x%02x%02x replays=%d icv_errors=%d local_mic_failures=%d\n",
- tkip->key_idx, tkip->key_set,
- (tkip->tx_iv32 >> 24) & 0xff,
- (tkip->tx_iv32 >> 16) & 0xff,
- (tkip->tx_iv32 >> 8) & 0xff,
- tkip->tx_iv32 & 0xff,
- (tkip->tx_iv16 >> 8) & 0xff,
- tkip->tx_iv16 & 0xff,
- (tkip->rx_iv32 >> 24) & 0xff,
- (tkip->rx_iv32 >> 16) & 0xff,
- (tkip->rx_iv32 >> 8) & 0xff,
- tkip->rx_iv32 & 0xff,
- (tkip->rx_iv16 >> 8) & 0xff,
- tkip->rx_iv16 & 0xff,
- tkip->dot11RSNAStatsTKIPReplays,
- tkip->dot11RSNAStatsTKIPICVErrors,
- tkip->dot11RSNAStatsTKIPLocalMICFailures);
-}
-
-static const struct lib80211_crypto_ops rtllib_crypt_tkip = {
- .name = "R-TKIP",
- .init = rtllib_tkip_init,
- .deinit = rtllib_tkip_deinit,
- .encrypt_mpdu = rtllib_tkip_encrypt,
- .decrypt_mpdu = rtllib_tkip_decrypt,
- .encrypt_msdu = rtllib_michael_mic_add,
- .decrypt_msdu = rtllib_michael_mic_verify,
- .set_key = rtllib_tkip_set_key,
- .get_key = rtllib_tkip_get_key,
- .print_stats = rtllib_tkip_print_stats,
- .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
- .extra_mpdu_postfix_len = 4, /* ICV */
- .extra_msdu_postfix_len = 8, /* MIC */
- .owner = THIS_MODULE,
-};
-
-static int __init rtllib_crypto_tkip_init(void)
-{
- return lib80211_register_crypto_ops(&rtllib_crypt_tkip);
-}
-
-static void __exit rtllib_crypto_tkip_exit(void)
-{
- lib80211_unregister_crypto_ops(&rtllib_crypt_tkip);
-}
-
-module_init(rtllib_crypto_tkip_init);
-module_exit(rtllib_crypto_tkip_exit);
-
-MODULE_DESCRIPTION("Support module for rtllib TKIP crypto");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c
deleted file mode 100644
index aa18c060d727..000000000000
--- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c
+++ /dev/null
@@ -1,242 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Host AP crypt: host-based WEP encryption implementation for Host AP driver
- *
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- */
-
-#include <crypto/arc4.h>
-#include <linux/fips.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/skbuff.h>
-#include <linux/string.h>
-#include "rtllib.h"
-
-#include <linux/crc32.h>
-
-struct prism2_wep_data {
- u32 iv;
-#define WEP_KEY_LEN 13
- u8 key[WEP_KEY_LEN + 1];
- u8 key_len;
- u8 key_idx;
- struct arc4_ctx rx_ctx_arc4;
- struct arc4_ctx tx_ctx_arc4;
-};
-
-static void *prism2_wep_init(int keyidx)
-{
- struct prism2_wep_data *priv;
-
- if (fips_enabled)
- return NULL;
-
- priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
- if (!priv)
- return NULL;
- priv->key_idx = keyidx;
-
- /* start WEP IV from a random value */
- get_random_bytes(&priv->iv, 4);
-
- return priv;
-}
-
-static void prism2_wep_deinit(void *priv)
-{
- kfree_sensitive(priv);
-}
-
-/* Perform WEP encryption on given skb that has at least 4 bytes of headroom
- * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted,
- * so the payload length increases with 8 bytes.
- *
- * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
- */
-static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct prism2_wep_data *wep = priv;
- u32 klen, len;
- u8 key[WEP_KEY_LEN + 3];
- u8 *pos;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u32 crc;
- u8 *icv;
-
- if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 ||
- skb->len < hdr_len){
- pr_err("Error!!! headroom=%d tailroom=%d skblen=%d hdr_len=%d\n",
- skb_headroom(skb), skb_tailroom(skb), skb->len, hdr_len);
- return -1;
- }
- len = skb->len - hdr_len;
- pos = skb_push(skb, 4);
- memmove(pos, pos + 4, hdr_len);
- pos += hdr_len;
-
- klen = 3 + wep->key_len;
-
- wep->iv++;
-
- /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key
- * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N)
- * can be used to speedup attacks, so avoid using them.
- */
- if ((wep->iv & 0xff00) == 0xff00) {
- u8 B = (wep->iv >> 16) & 0xff;
-
- if (B >= 3 && B < klen)
- wep->iv += 0x0100;
- }
-
- /* Prepend 24-bit IV to RC4 key and TX frame */
- *pos++ = key[0] = (wep->iv >> 16) & 0xff;
- *pos++ = key[1] = (wep->iv >> 8) & 0xff;
- *pos++ = key[2] = wep->iv & 0xff;
- *pos++ = wep->key_idx << 6;
-
- /* Copy rest of the WEP key (the secret part) */
- memcpy(key + 3, wep->key, wep->key_len);
-
- if (!tcb_desc->hw_sec) {
- /* Append little-endian CRC32 and encrypt it to produce ICV */
- crc = ~crc32_le(~0, pos, len);
- icv = skb_put(skb, 4);
- icv[0] = crc;
- icv[1] = crc >> 8;
- icv[2] = crc >> 16;
- icv[3] = crc >> 24;
-
- arc4_setkey(&wep->tx_ctx_arc4, key, klen);
- arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4);
- }
-
- return 0;
-}
-
-/* Perform WEP decryption on given struct buffer. Buffer includes whole WEP
- * part of the frame: IV (4 bytes), encrypted payload (including SNAP header),
- * ICV (4 bytes). len includes both IV and ICV.
- *
- * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
- * failure. If frame is OK, IV and ICV will be removed.
- */
-static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
-{
- struct prism2_wep_data *wep = priv;
- u32 klen, plen;
- u8 key[WEP_KEY_LEN + 3];
- u8 keyidx, *pos;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb +
- MAX_DEV_ADDR_SIZE);
- u32 crc;
- u8 icv[4];
-
- if (skb->len < hdr_len + 8)
- return -1;
-
- pos = skb->data + hdr_len;
- key[0] = *pos++;
- key[1] = *pos++;
- key[2] = *pos++;
- keyidx = *pos++ >> 6;
- if (keyidx != wep->key_idx)
- return -1;
-
- klen = 3 + wep->key_len;
-
- /* Copy rest of the WEP key (the secret part) */
- memcpy(key + 3, wep->key, wep->key_len);
-
- /* Apply RC4 to data and compute CRC32 over decrypted data */
- plen = skb->len - hdr_len - 8;
-
- if (!tcb_desc->hw_sec) {
- arc4_setkey(&wep->rx_ctx_arc4, key, klen);
- arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4);
-
- crc = ~crc32_le(~0, pos, plen);
- icv[0] = crc;
- icv[1] = crc >> 8;
- icv[2] = crc >> 16;
- icv[3] = crc >> 24;
- if (memcmp(icv, pos + plen, 4) != 0) {
- /* ICV mismatch - drop frame */
- return -2;
- }
- }
- /* Remove IV and ICV */
- memmove(skb->data + 4, skb->data, hdr_len);
- skb_pull(skb, 4);
- skb_trim(skb, skb->len - 4);
-
- return 0;
-}
-
-static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
-{
- struct prism2_wep_data *wep = priv;
-
- if (len < 0 || len > WEP_KEY_LEN)
- return -1;
-
- memcpy(wep->key, key, len);
- wep->key_len = len;
-
- return 0;
-}
-
-static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
-{
- struct prism2_wep_data *wep = priv;
-
- if (len < wep->key_len)
- return -1;
-
- memcpy(key, wep->key, wep->key_len);
-
- return wep->key_len;
-}
-
-static void prism2_wep_print_stats(struct seq_file *m, void *priv)
-{
- struct prism2_wep_data *wep = priv;
-
- seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len);
-}
-
-static const struct lib80211_crypto_ops rtllib_crypt_wep = {
- .name = "R-WEP",
- .init = prism2_wep_init,
- .deinit = prism2_wep_deinit,
- .encrypt_mpdu = prism2_wep_encrypt,
- .decrypt_mpdu = prism2_wep_decrypt,
- .encrypt_msdu = NULL,
- .decrypt_msdu = NULL,
- .set_key = prism2_wep_set_key,
- .get_key = prism2_wep_get_key,
- .print_stats = prism2_wep_print_stats,
- .extra_mpdu_prefix_len = 4, /* IV */
- .extra_mpdu_postfix_len = 4, /* ICV */
- .owner = THIS_MODULE,
-};
-
-static int __init rtllib_crypto_wep_init(void)
-{
- return lib80211_register_crypto_ops(&rtllib_crypt_wep);
-}
-
-static void __exit rtllib_crypto_wep_exit(void)
-{
- lib80211_unregister_crypto_ops(&rtllib_crypt_wep);
-}
-
-module_init(rtllib_crypto_wep_init);
-module_exit(rtllib_crypto_wep_exit);
-
-MODULE_DESCRIPTION("Support module for rtllib WEP crypto");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
deleted file mode 100644
index 469a69726c16..000000000000
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2004 Intel Corporation. All rights reserved.
- *
- * Portions of this file are based on the WEP enablement code provided by the
- * Host AP project hostap-drivers v0.1.3
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- */
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <net/arp.h>
-#include "rtllib.h"
-
-static inline int rtllib_networks_allocate(struct rtllib_device *ieee)
-{
- if (ieee->networks)
- return 0;
-
- ieee->networks = kcalloc(MAX_NETWORK_COUNT,
- sizeof(struct rtllib_network), GFP_KERNEL);
- if (!ieee->networks)
- return -ENOMEM;
-
- return 0;
-}
-
-static inline void rtllib_networks_free(struct rtllib_device *ieee)
-{
- if (!ieee->networks)
- return;
- kfree(ieee->networks);
- ieee->networks = NULL;
-}
-
-static inline void rtllib_networks_initialize(struct rtllib_device *ieee)
-{
- int i;
-
- INIT_LIST_HEAD(&ieee->network_free_list);
- INIT_LIST_HEAD(&ieee->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- list_add_tail(&ieee->networks[i].list,
- &ieee->network_free_list);
-}
-
-struct net_device *alloc_rtllib(int sizeof_priv)
-{
- struct rtllib_device *ieee = NULL;
- struct net_device *dev;
- int i, err;
-
- pr_debug("rtllib: Initializing...\n");
-
- dev = alloc_etherdev(sizeof(struct rtllib_device) + sizeof_priv);
- if (!dev) {
- pr_err("Unable to allocate net_device.\n");
- return NULL;
- }
- ieee = (struct rtllib_device *)netdev_priv_rsl(dev);
- ieee->dev = dev;
-
- err = rtllib_networks_allocate(ieee);
- if (err) {
- pr_err("Unable to allocate beacon storage: %d\n", err);
- goto free_netdev;
- }
- rtllib_networks_initialize(ieee);
-
- /* Default fragmentation threshold is maximum payload size */
- ieee->fts = DEFAULT_FTS;
- ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
- ieee->open_wep = 1;
-
- ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
-
- ieee->rtllib_ap_sec_type = rtllib_ap_sec_type;
-
- spin_lock_init(&ieee->lock);
- spin_lock_init(&ieee->wpax_suitlist_lock);
- spin_lock_init(&ieee->reorder_spinlock);
- atomic_set(&ieee->atm_swbw, 0);
-
- /* SAM FIXME */
- lib80211_crypt_info_init(&ieee->crypt_info, "RTLLIB", &ieee->lock);
-
- ieee->wpa_enabled = 0;
- ieee->tkip_countermeasures = 0;
- ieee->drop_unencrypted = 0;
- ieee->privacy_invoked = 0;
- ieee->ieee802_1x = 1;
- ieee->hwsec_active = 0;
-
- memset(ieee->swcamtable, 0, sizeof(struct sw_cam_table) * 32);
- err = rtllib_softmac_init(ieee);
- if (err)
- goto free_crypt_info;
-
- ieee->ht_info = kzalloc(sizeof(struct rt_hi_throughput), GFP_KERNEL);
- if (!ieee->ht_info)
- goto free_softmac;
-
- ht_update_default_setting(ieee);
- ht_initialize_ht_info(ieee);
- rtllib_ts_init(ieee);
- for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
-
- for (i = 0; i < 17; i++) {
- ieee->last_rxseq_num[i] = -1;
- ieee->last_rxfrag_num[i] = -1;
- ieee->last_packet_time[i] = 0;
- }
-
- return dev;
-
-free_softmac:
- rtllib_softmac_free(ieee);
-free_crypt_info:
- lib80211_crypt_info_free(&ieee->crypt_info);
- rtllib_networks_free(ieee);
-free_netdev:
- free_netdev(dev);
-
- return NULL;
-}
-EXPORT_SYMBOL(alloc_rtllib);
-
-void free_rtllib(struct net_device *dev)
-{
- struct rtllib_device *ieee = (struct rtllib_device *)
- netdev_priv_rsl(dev);
-
- kfree(ieee->ht_info);
- rtllib_softmac_free(ieee);
-
- lib80211_crypt_info_free(&ieee->crypt_info);
-
- rtllib_networks_free(ieee);
- free_netdev(dev);
-}
-EXPORT_SYMBOL(free_rtllib);
-
-static int __init rtllib_init(void)
-{
- return 0;
-}
-
-static void __exit rtllib_exit(void)
-{
-}
-
-module_init(rtllib_init);
-module_exit(rtllib_exit);
-
-MODULE_DESCRIPTION("Support module for rtllib wireless devices");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
deleted file mode 100644
index 8fe224a83dd6..000000000000
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ /dev/null
@@ -1,2564 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Original code based 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
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- * Copyright (c) 2004, Intel Corporation
- *
- * Few modifications for Realtek's Wi-Fi drivers by
- * Andrea Merello <andrea.merello@gmail.com>
- *
- * A special thanks goes to Realtek for their support !
- */
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <linux/ctype.h>
-
-#include "rtllib.h"
-
-static void rtllib_rx_mgt(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *stats);
-
-static inline void rtllib_monitor_rx(struct rtllib_device *ieee,
- struct sk_buff *skb,
- struct rtllib_rx_stats *rx_status,
- size_t hdr_length)
-{
- skb->dev = ieee->dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, hdr_length);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_80211_RAW);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct rtllib_frag_entry *
-rtllib_frag_cache_find(struct rtllib_device *ieee, unsigned int seq,
- unsigned int frag, u8 tid, u8 *src, u8 *dst)
-{
- struct rtllib_frag_entry *entry;
- int i;
-
- for (i = 0; i < RTLLIB_FRAG_CACHE_LEN; i++) {
- entry = &ieee->frag_cache[tid][i];
- if (entry->skb &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- netdev_dbg(ieee->dev,
- "expiring fragment cache entry seq=%u last_frag=%u\n",
- entry->seq, entry->last_frag);
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb && 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 *
-rtllib_frag_cache_get(struct rtllib_device *ieee,
- struct ieee80211_hdr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 fc = le16_to_cpu(hdr->frame_control);
- u16 sc = le16_to_cpu(hdr->seq_ctrl);
- unsigned int frag = WLAN_GET_SEQ_FRAG(sc);
- unsigned int seq = WLAN_GET_SEQ_SEQ(sc);
- struct rtllib_frag_entry *entry;
- struct ieee80211_qos_hdr *hdr_3addrqos;
- struct ieee80211_qos_hdr_4addr *hdr_4addrqos;
- u8 tid;
-
- if (ieee80211_has_a4(hdr->frame_control) &&
- RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)hdr;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else if (RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_3addrqos = (struct ieee80211_qos_hdr *)hdr;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else {
- tid = 0;
- }
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(ieee->dev->mtu +
- sizeof(struct ieee80211_hdr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ +
- ETH_ALEN /* WDS */ +
- /* QOS Control */
- (RTLLIB_QOS_HAS_SEQ(fc) ? 2 : 0));
- if (!skb)
- return NULL;
-
- entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]];
- ieee->frag_next_idx[tid]++;
- if (ieee->frag_next_idx[tid] >= RTLLIB_FRAG_CACHE_LEN)
- ieee->frag_next_idx[tid] = 0;
-
- if (entry->skb)
- dev_kfree_skb_any(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- ether_addr_copy(entry->src_addr, hdr->addr2);
- ether_addr_copy(entry->dst_addr, hdr->addr1);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received
- */
- entry = rtllib_frag_cache_find(ieee, seq, frag, tid, hdr->addr2,
- hdr->addr1);
- if (entry) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static int rtllib_frag_cache_invalidate(struct rtllib_device *ieee,
- struct ieee80211_hdr *hdr)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
- u16 sc = le16_to_cpu(hdr->seq_ctrl);
- unsigned int seq = WLAN_GET_SEQ_SEQ(sc);
- struct rtllib_frag_entry *entry;
- struct ieee80211_qos_hdr *hdr_3addrqos;
- struct ieee80211_qos_hdr_4addr *hdr_4addrqos;
- u8 tid;
-
- if (ieee80211_has_a4(hdr->frame_control) &&
- RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)hdr;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else if (RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_3addrqos = (struct ieee80211_qos_hdr *)hdr;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else {
- tid = 0;
- }
-
- entry = rtllib_frag_cache_find(ieee, seq, -1, tid, hdr->addr2,
- hdr->addr1);
-
- if (!entry) {
- netdev_dbg(ieee->dev,
- "Couldn't invalidate fragment cache entry (seq=%u)\n",
- seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-/* rtllib_rx_frame_mgtmt
- *
- * Responsible for handling management control frames
- *
- * Called by rtllib_rx
- */
-static inline int
-rtllib_rx_frame_mgmt(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats, u16 type, u16 stype)
-{
- /* On the struct stats definition there is written that
- * this is not mandatory.... but seems that the probe
- * response parser uses it
- */
- struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)skb->data;
-
- rx_stats->len = skb->len;
- rtllib_rx_mgt(ieee, skb, rx_stats);
- if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN))) {
- dev_kfree_skb_any(skb);
- return 0;
- }
- rtllib_rx_frame_softmac(ieee, skb, rx_stats, type, stype);
-
- dev_kfree_skb_any(skb);
-
- return 0;
-}
-
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-/* Called by rtllib_rx_frame_decrypt */
-static int rtllib_is_eapol_frame(struct rtllib_device *ieee,
- struct sk_buff *skb, size_t hdrlen)
-{
- struct net_device *dev = ieee->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 &&
- memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 &&
- memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
- /* 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 + hdrlen;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-/* Called only as a tasklet (software IRQ), by rtllib_rx */
-static inline int
-rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (!crypt || !crypt->ops->decrypt_mpdu)
- return 0;
-
- if (ieee->hwsec_active) {
- struct cb_desc *tcb_desc = (struct cb_desc *)
- (skb->cb + MAX_DEV_ADDR_SIZE);
-
- tcb_desc->hw_sec = 1;
-
- if (ieee->need_sw_enc)
- tcb_desc->hw_sec = 0;
- }
-
- hdr = (struct ieee80211_hdr *)skb->data;
- hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- netdev_dbg(ieee->dev, "decryption failed (SA= %pM) res=%d\n",
- hdr->addr2, res);
- if (res == -2)
- netdev_dbg(ieee->dev,
- "Decryption failed ICV mismatch (key %d)\n",
- skb->data[hdrlen + 3] >> 6);
- return -1;
- }
-
- return res;
-}
-
-/* Called only as a tasklet (software IRQ), by rtllib_rx */
-static inline int
-rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb,
- int keyidx, struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (!crypt || !crypt->ops->decrypt_msdu)
- return 0;
- if (ieee->hwsec_active) {
- struct cb_desc *tcb_desc = (struct cb_desc *)
- (skb->cb + MAX_DEV_ADDR_SIZE);
-
- tcb_desc->hw_sec = 1;
-
- if (ieee->need_sw_enc)
- tcb_desc->hw_sec = 0;
- }
-
- hdr = (struct ieee80211_hdr *)skb->data;
- hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- netdev_dbg(ieee->dev,
- "MSDU decryption/MIC verification failed (SA= %pM keyidx=%d)\n",
- hdr->addr2, keyidx);
- return -1;
- }
-
- return 0;
-}
-
-/* this function is stolen from ipw2200 driver*/
-#define IEEE_PACKET_RETRY_TIME (5 * HZ)
-static int is_duplicate_packet(struct rtllib_device *ieee,
- struct ieee80211_hdr *header)
-{
- u16 fc = le16_to_cpu(header->frame_control);
- u16 sc = le16_to_cpu(header->seq_ctrl);
- u16 seq = WLAN_GET_SEQ_SEQ(sc);
- u16 frag = WLAN_GET_SEQ_FRAG(sc);
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
- struct ieee80211_qos_hdr *hdr_3addrqos;
- struct ieee80211_qos_hdr_4addr *hdr_4addrqos;
- u8 tid;
-
- if (ieee80211_has_a4(header->frame_control) &&
- RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)header;
- tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else if (RTLLIB_QOS_HAS_SEQ(fc)) {
- hdr_3addrqos = (struct ieee80211_qos_hdr *)header;
- tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID;
- tid = UP2AC(tid);
- tid++;
- } else {
- tid = 0;
- }
-
- switch (ieee->iw_mode) {
- case IW_MODE_INFRA:
- last_seq = &ieee->last_rxseq_num[tid];
- last_frag = &ieee->last_rxfrag_num[tid];
- last_time = &ieee->last_packet_time[tid];
- break;
- default:
- return 0;
- }
-
- if ((*last_seq == seq) &&
- time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else {
- *last_seq = seq;
- }
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
-drop:
-
- return 1;
-}
-
-static bool add_reorder_entry(struct rx_ts_record *ts,
- struct rx_reorder_entry *reorder_entry)
-{
- struct list_head *list = &ts->rx_pending_pkt_list;
-
- while (list->next != &ts->rx_pending_pkt_list) {
- if (SN_LESS(reorder_entry->seq_num, ((struct rx_reorder_entry *)
- list_entry(list->next, struct rx_reorder_entry,
- list))->seq_num))
- list = list->next;
- else if (SN_EQUAL(reorder_entry->seq_num,
- ((struct rx_reorder_entry *)list_entry(list->next,
- struct rx_reorder_entry, list))->seq_num))
- return false;
- else
- break;
- }
- reorder_entry->list.next = list->next;
- reorder_entry->list.next->prev = &reorder_entry->list;
- reorder_entry->list.prev = list;
- list->next = &reorder_entry->list;
-
- return true;
-}
-
-void rtllib_indicate_packets(struct rtllib_device *ieee,
- struct rtllib_rxb **prxb_indicate_array, u8 index)
-{
- struct net_device_stats *stats = &ieee->stats;
- u8 i = 0, j = 0;
- u16 ethertype;
-
- for (j = 0; j < index; j++) {
- struct rtllib_rxb *prxb = prxb_indicate_array[j];
-
- for (i = 0; i < prxb->nr_subframes; i++) {
- struct sk_buff *sub_skb = prxb->subframes[i];
-
- /* convert hdr + possible LLC headers into Ethernet header */
- ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7];
- if (sub_skb->len >= 8 &&
- ((memcmp(sub_skb->data, rfc1042_header,
- SNAP_SIZE) == 0 &&
- ethertype != ETH_P_AARP &&
- ethertype != ETH_P_IPX) ||
- memcmp(sub_skb->data, bridge_tunnel_header,
- SNAP_SIZE) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation
- * and replace EtherType
- */
- skb_pull(sub_skb, SNAP_SIZE);
- memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN);
- memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN);
- } else {
- u16 len;
- /* Leave Ethernet header part of hdr and full payload */
- len = sub_skb->len;
- memcpy(skb_push(sub_skb, 2), &len, 2);
- memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN);
- memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN);
- }
-
- /* Indicate the packets to upper layer */
- if (sub_skb) {
- stats->rx_packets++;
- stats->rx_bytes += sub_skb->len;
-
- memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
- sub_skb->protocol = eth_type_trans(sub_skb,
- ieee->dev);
- sub_skb->dev = ieee->dev;
- sub_skb->dev->stats.rx_packets++;
- sub_skb->dev->stats.rx_bytes += sub_skb->len;
- /* 802.11 crc not sufficient */
- sub_skb->ip_summed = CHECKSUM_NONE;
- ieee->last_rx_ps_time = jiffies;
- netif_rx(sub_skb);
- }
- }
- kfree(prxb);
- prxb = NULL;
- }
-}
-
-void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee,
- struct rx_ts_record *ts)
-{
- struct rx_reorder_entry *pRxReorderEntry;
- u8 rfd_cnt = 0;
-
- del_timer_sync(&ts->rx_pkt_pending_timer);
- while (!list_empty(&ts->rx_pending_pkt_list)) {
- if (rfd_cnt >= REORDER_WIN_SIZE) {
- netdev_info(ieee->dev,
- "-------------->%s() error! rfd_cnt >= REORDER_WIN_SIZE\n",
- __func__);
- break;
- }
-
- pRxReorderEntry = (struct rx_reorder_entry *)
- list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, list);
- netdev_dbg(ieee->dev, "%s(): Indicate seq_num %d!\n", __func__,
- pRxReorderEntry->seq_num);
- list_del_init(&pRxReorderEntry->list);
-
- ieee->rfd_array[rfd_cnt] = pRxReorderEntry->prxb;
-
- rfd_cnt = rfd_cnt + 1;
- list_add_tail(&pRxReorderEntry->list,
- &ieee->RxReorder_Unused_List);
- }
- rtllib_indicate_packets(ieee, ieee->rfd_array, rfd_cnt);
-
- ts->rx_indicate_seq = 0xffff;
-}
-
-static void rx_reorder_indicate_packet(struct rtllib_device *ieee,
- struct rtllib_rxb *prxb,
- struct rx_ts_record *ts, u16 seq_num)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct rx_reorder_entry *reorder_entry = NULL;
- u8 win_size = ht_info->rx_reorder_win_size;
- u16 win_end = 0;
- u8 index = 0;
- bool match_win_start = false, pkt_in_buf = false;
- unsigned long flags;
-
- netdev_dbg(ieee->dev,
- "%s(): Seq is %d, ts->rx_indicate_seq is %d, win_size is %d\n",
- __func__, seq_num, ts->rx_indicate_seq, win_size);
-
- spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
-
- win_end = (ts->rx_indicate_seq + win_size - 1) % 4096;
- /* Rx Reorder initialize condition.*/
- if (ts->rx_indicate_seq == 0xffff)
- ts->rx_indicate_seq = seq_num;
-
- /* Drop out the packet which seq_num is smaller than WinStart */
- if (SN_LESS(seq_num, ts->rx_indicate_seq)) {
- netdev_dbg(ieee->dev,
- "Packet Drop! IndicateSeq: %d, NewSeq: %d\n",
- ts->rx_indicate_seq, seq_num);
- ht_info->rx_reorder_drop_counter++;
- {
- int i;
-
- for (i = 0; i < prxb->nr_subframes; i++)
- dev_kfree_skb(prxb->subframes[i]);
- kfree(prxb);
- prxb = NULL;
- }
- spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
- return;
- }
-
- /* Sliding window manipulation. Conditions includes:
- * 1. Incoming seq_num is equal to WinStart =>Window shift 1
- * 2. Incoming seq_num is larger than the win_end => Window shift N
- */
- if (SN_EQUAL(seq_num, ts->rx_indicate_seq)) {
- ts->rx_indicate_seq = (ts->rx_indicate_seq + 1) % 4096;
- match_win_start = true;
- } else if (SN_LESS(win_end, seq_num)) {
- if (seq_num >= (win_size - 1))
- ts->rx_indicate_seq = seq_num + 1 - win_size;
- else
- ts->rx_indicate_seq = 4095 -
- (win_size - (seq_num + 1)) + 1;
- netdev_dbg(ieee->dev,
- "Window Shift! IndicateSeq: %d, NewSeq: %d\n",
- ts->rx_indicate_seq, seq_num);
- }
-
- /* Indication process.
- * After Packet dropping and Sliding Window shifting as above, we can
- * now just indicate the packets with the seq_num smaller than latest
- * WinStart and struct buffer other packets.
- *
- * For Rx Reorder condition:
- * 1. All packets with seq_num smaller than WinStart => Indicate
- * 2. All packets with seq_num larger than or equal to
- * WinStart => Buffer it.
- */
- if (match_win_start) {
- /* Current packet is going to be indicated.*/
- netdev_dbg(ieee->dev,
- "Packets indication! IndicateSeq: %d, NewSeq: %d\n",
- ts->rx_indicate_seq, seq_num);
- ieee->prxb_indicate_array[0] = prxb;
- index = 1;
- } else {
- /* Current packet is going to be inserted into pending list.*/
- if (!list_empty(&ieee->RxReorder_Unused_List)) {
- reorder_entry = (struct rx_reorder_entry *)
- list_entry(ieee->RxReorder_Unused_List.next,
- struct rx_reorder_entry, list);
- list_del_init(&reorder_entry->list);
-
- /* Make a reorder entry and insert
- * into a the packet list.
- */
- reorder_entry->seq_num = seq_num;
- reorder_entry->prxb = prxb;
-
- if (!add_reorder_entry(ts, reorder_entry)) {
- int i;
-
- netdev_dbg(ieee->dev,
- "%s(): Duplicate packet is dropped. IndicateSeq: %d, NewSeq: %d\n",
- __func__, ts->rx_indicate_seq,
- seq_num);
- list_add_tail(&reorder_entry->list,
- &ieee->RxReorder_Unused_List);
-
- for (i = 0; i < prxb->nr_subframes; i++)
- dev_kfree_skb(prxb->subframes[i]);
- kfree(prxb);
- prxb = NULL;
- } else {
- netdev_dbg(ieee->dev,
- "Pkt insert into struct buffer. IndicateSeq: %d, NewSeq: %d\n",
- ts->rx_indicate_seq, seq_num);
- }
- } else {
- /* Packets are dropped if there are not enough reorder
- * entries. This part should be modified!! We can just
- * indicate all the packets in struct buffer and get
- * reorder entries.
- */
- netdev_err(ieee->dev,
- "%s(): There is no reorder entry! Packet is dropped!\n",
- __func__);
- {
- int i;
-
- for (i = 0; i < prxb->nr_subframes; i++)
- dev_kfree_skb(prxb->subframes[i]);
- kfree(prxb);
- prxb = NULL;
- }
- }
- }
-
- /* Check if there is any packet need indicate.*/
- while (!list_empty(&ts->rx_pending_pkt_list)) {
- netdev_dbg(ieee->dev, "%s(): start RREORDER indicate\n",
- __func__);
-
- reorder_entry = (struct rx_reorder_entry *)
- list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry,
- list);
- if (SN_LESS(reorder_entry->seq_num, ts->rx_indicate_seq) ||
- SN_EQUAL(reorder_entry->seq_num, ts->rx_indicate_seq)) {
- /* This protect struct buffer from overflow. */
- if (index >= REORDER_WIN_SIZE) {
- netdev_err(ieee->dev,
- "%s(): Buffer overflow!\n",
- __func__);
- pkt_in_buf = true;
- break;
- }
-
- list_del_init(&reorder_entry->list);
-
- if (SN_EQUAL(reorder_entry->seq_num, ts->rx_indicate_seq))
- ts->rx_indicate_seq = (ts->rx_indicate_seq + 1) %
- 4096;
-
- ieee->prxb_indicate_array[index] = reorder_entry->prxb;
- netdev_dbg(ieee->dev, "%s(): Indicate seq_num %d!\n",
- __func__, reorder_entry->seq_num);
- index++;
-
- list_add_tail(&reorder_entry->list,
- &ieee->RxReorder_Unused_List);
- } else {
- pkt_in_buf = true;
- break;
- }
- }
-
- /* Handling pending timer. Set this timer to prevent from long time
- * Rx buffering.
- */
- if (index > 0) {
- spin_unlock_irqrestore(&ieee->reorder_spinlock, flags);
- if (timer_pending(&ts->rx_pkt_pending_timer))
- del_timer_sync(&ts->rx_pkt_pending_timer);
- spin_lock_irqsave(&ieee->reorder_spinlock, flags);
- ts->rx_timeout_indicate_seq = 0xffff;
-
- if (index > REORDER_WIN_SIZE) {
- netdev_err(ieee->dev,
- "%s(): Rx Reorder struct buffer full!\n",
- __func__);
- spin_unlock_irqrestore(&(ieee->reorder_spinlock),
- flags);
- return;
- }
- rtllib_indicate_packets(ieee, ieee->prxb_indicate_array, index);
- pkt_in_buf = false;
- }
-
- if (pkt_in_buf && ts->rx_timeout_indicate_seq == 0xffff) {
- netdev_dbg(ieee->dev, "%s(): SET rx timeout timer\n", __func__);
- ts->rx_timeout_indicate_seq = ts->rx_indicate_seq;
- spin_unlock_irqrestore(&ieee->reorder_spinlock, flags);
- mod_timer(&ts->rx_pkt_pending_timer, jiffies +
- msecs_to_jiffies(ht_info->rx_reorder_pending_time));
- spin_lock_irqsave(&ieee->reorder_spinlock, flags);
- }
- spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
-}
-
-static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats,
- struct rtllib_rxb *rxb, u8 *src, u8 *dst)
-{
- struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- u16 llc_offset = sizeof(struct ieee80211_hdr_3addr);
- bool is_aggregate_frame = false;
- u16 subframe_len;
- u8 pad_len = 0;
- u16 seq_num = 0;
- struct sk_buff *sub_skb;
- /* just for debug purpose */
- seq_num = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl));
- if ((RTLLIB_QOS_HAS_SEQ(fc)) &&
- (((union frameqos *)(skb->data + RTLLIB_3ADDR_LEN))->field.reserved))
- is_aggregate_frame = true;
-
- if (RTLLIB_QOS_HAS_SEQ(fc))
- llc_offset += 2;
- if (rx_stats->contain_htc)
- llc_offset += sHTCLng;
-
- if (skb->len <= llc_offset)
- return 0;
-
- skb_pull(skb, llc_offset);
- ieee->is_aggregate_frame = is_aggregate_frame;
- if (!is_aggregate_frame) {
- rxb->nr_subframes = 1;
-
- /* altered by clark 3/30/2010
- * The struct buffer size of the skb indicated to upper layer
- * must be less than 5000, or the defraged IP datagram
- * in the IP layer will exceed "ipfrag_high_tresh" and be
- * discarded. so there must not use the function
- * "skb_copy" and "skb_clone" for "skb".
- */
-
- /* Allocate new skb for releasing to upper layer */
- sub_skb = dev_alloc_skb(RTLLIB_SKBBUFFER_SIZE);
- if (!sub_skb)
- return 0;
- skb_reserve(sub_skb, 12);
- skb_put_data(sub_skb, skb->data, skb->len);
- sub_skb->dev = ieee->dev;
-
- rxb->subframes[0] = sub_skb;
-
- memcpy(rxb->src, src, ETH_ALEN);
- memcpy(rxb->dst, dst, ETH_ALEN);
- rxb->subframes[0]->dev = ieee->dev;
- return 1;
- }
-
- rxb->nr_subframes = 0;
- memcpy(rxb->src, src, ETH_ALEN);
- memcpy(rxb->dst, dst, ETH_ALEN);
- while (skb->len > ETHERNET_HEADER_SIZE) {
- /* Offset 12 denote 2 mac address */
- subframe_len = *((u16 *)(skb->data + 12));
- subframe_len = (subframe_len >> 8) +
- (subframe_len << 8);
-
- if (skb->len < (ETHERNET_HEADER_SIZE + subframe_len)) {
- netdev_info(ieee->dev,
- "%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",
- __func__, rxb->nr_subframes);
- netdev_info(ieee->dev,
- "%s: A-MSDU parse error!! Subframe Length: %d\n",
- __func__, subframe_len);
- netdev_info(ieee->dev,
- "nRemain_Length is %d and subframe_len is : %d\n",
- skb->len, subframe_len);
- netdev_info(ieee->dev,
- "The Packet seq_num is %d\n",
- seq_num);
- return 0;
- }
-
- /* move the data point to data content */
- skb_pull(skb, ETHERNET_HEADER_SIZE);
-
- /* altered by clark 3/30/2010
- * The struct buffer size of the skb indicated to upper layer
- * must be less than 5000, or the defraged IP datagram
- * in the IP layer will exceed "ipfrag_high_tresh" and be
- * discarded. so there must not use the function
- * "skb_copy" and "skb_clone" for "skb".
- */
-
- /* Allocate new skb for releasing to upper layer */
- sub_skb = dev_alloc_skb(subframe_len + 12);
- if (!sub_skb)
- return 0;
- skb_reserve(sub_skb, 12);
- skb_put_data(sub_skb, skb->data, subframe_len);
-
- sub_skb->dev = ieee->dev;
- rxb->subframes[rxb->nr_subframes++] = sub_skb;
- if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) {
- netdev_dbg(ieee->dev,
- "ParseSubframe(): Too many Subframes! Packets dropped!\n");
- break;
- }
- skb_pull(skb, subframe_len);
-
- if (skb->len != 0) {
- pad_len = 4 - ((subframe_len +
- ETHERNET_HEADER_SIZE) % 4);
- if (pad_len == 4)
- pad_len = 0;
-
- if (skb->len < pad_len)
- return 0;
-
- skb_pull(skb, pad_len);
- }
- }
-
- return rxb->nr_subframes;
-}
-
-static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee,
- struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
- size_t hdrlen;
-
- hdrlen = rtllib_get_hdrlen(fc);
- if (ht_c_check(ieee, skb->data)) {
- if (net_ratelimit())
- netdev_info(ieee->dev, "%s: find HTCControl!\n",
- __func__);
- hdrlen += 4;
- rx_stats->contain_htc = true;
- }
-
- return hdrlen;
-}
-
-static int rtllib_rx_check_duplicate(struct rtllib_device *ieee,
- struct sk_buff *skb, u8 multicast)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc, sc;
- u8 frag;
-
- fc = le16_to_cpu(hdr->frame_control);
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = WLAN_GET_SEQ_FRAG(sc);
-
- if (!ieee->ht_info->cur_rx_reorder_enable ||
- !ieee->current_network.qos_data.active ||
- !is_data_frame(skb->data) ||
- is_legacy_data_frame(skb->data)) {
- if (!ieee80211_is_beacon(hdr->frame_control)) {
- if (is_duplicate_packet(ieee, hdr))
- return -1;
- }
- } else {
- struct rx_ts_record *ts = NULL;
-
- if (rtllib_get_ts(ieee, (struct ts_common_info **)&ts, hdr->addr2,
- (u8)frame_qos_tid((u8 *)(skb->data)), RX_DIR, true)) {
- if ((fc & (1 << 11)) && (frag == ts->rx_last_frag_num) &&
- (WLAN_GET_SEQ_SEQ(sc) == ts->rx_last_seq_num))
- return -1;
- ts->rx_last_frag_num = frag;
- ts->rx_last_seq_num = WLAN_GET_SEQ_SEQ(sc);
- } else {
- netdev_warn(ieee->dev, "%s(): No TS! Skip the check!\n",
- __func__);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void rtllib_rx_extract_addr(struct rtllib_device *ieee,
- struct ieee80211_hdr *hdr, u8 *dst,
- u8 *src, u8 *bssid)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- ether_addr_copy(dst, hdr->addr1);
- ether_addr_copy(src, hdr->addr3);
- ether_addr_copy(bssid, hdr->addr2);
- break;
- case IEEE80211_FCTL_TODS:
- ether_addr_copy(dst, hdr->addr3);
- ether_addr_copy(src, hdr->addr2);
- ether_addr_copy(bssid, hdr->addr1);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- ether_addr_copy(dst, hdr->addr3);
- ether_addr_copy(src, hdr->addr4);
- ether_addr_copy(bssid, ieee->current_network.bssid);
- break;
- default:
- ether_addr_copy(dst, hdr->addr1);
- ether_addr_copy(src, hdr->addr2);
- ether_addr_copy(bssid, hdr->addr3);
- break;
- }
-}
-
-static int rtllib_rx_data_filter(struct rtllib_device *ieee, struct ieee80211_hdr *hdr,
- u8 *dst, u8 *src, u8 *bssid, u8 *addr2)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
- u8 type = WLAN_FC_GET_TYPE(fc);
- u8 stype = WLAN_FC_GET_STYPE(fc);
-
- /* Filter frames from different BSS */
- if (ieee80211_has_a4(hdr->frame_control) &&
- !ether_addr_equal(ieee->current_network.bssid, bssid) &&
- !is_zero_ether_addr(ieee->current_network.bssid)) {
- return -1;
- }
-
- /* 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 &&
- stype != IEEE80211_STYPE_QOS_DATA) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- netdev_dbg(ieee->dev,
- "RX: dropped data frame with no data (type=0x%02x, subtype=0x%02x)\n",
- type, stype);
- return -1;
- }
-
- /* packets from our adapter are dropped (echo) */
- if (!memcmp(src, ieee->dev->dev_addr, ETH_ALEN))
- return -1;
-
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(dst)) {
- if (memcmp(bssid, ieee->current_network.bssid,
- ETH_ALEN))
- return -1;
- }
- return 0;
-}
-
-static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data **crypt, size_t hdrlen)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
- int idx = 0;
-
- if (skb->len >= hdrlen + 3)
- idx = skb->data[hdrlen + 3] >> 6;
-
- *crypt = ieee->crypt_info.crypt[idx];
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption
- */
- if (*crypt && (!(*crypt)->ops || !(*crypt)->ops->decrypt_mpdu))
- *crypt = NULL;
-
- if (!*crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
- /* 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.
- */
- netdev_dbg(ieee->dev,
- "Decryption failed (not set) (SA= %pM)\n",
- hdr->addr2);
- return -1;
- }
-
- return 0;
-}
-
-static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats,
- struct lib80211_crypt_data *crypt, size_t hdrlen)
-{
- struct ieee80211_hdr *hdr;
- int keyidx = 0;
- u16 fc, sc;
- u8 frag;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = WLAN_GET_SEQ_FRAG(sc);
-
- if ((!rx_stats->decrypted))
- ieee->need_sw_enc = 1;
- else
- ieee->need_sw_enc = 0;
-
- keyidx = rtllib_rx_frame_decrypt(ieee, skb, crypt);
- if ((fc & IEEE80211_FCTL_PROTECTED) && (keyidx < 0)) {
- netdev_info(ieee->dev, "%s: decrypt frame error\n", __func__);
- return -1;
- }
-
- hdr = (struct ieee80211_hdr *)skb->data;
- if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
- int flen;
- struct sk_buff *frag_skb = rtllib_frag_cache_get(ieee, hdr);
-
- netdev_dbg(ieee->dev, "Rx Fragment received (%u)\n", frag);
-
- if (!frag_skb) {
- netdev_dbg(ieee->dev,
- "Rx cannot get skb from fragment cache (morefrag=%d seq=%u frag=%u)\n",
- (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- WLAN_GET_SEQ_SEQ(sc), frag);
- return -1;
- }
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- netdev_warn(ieee->dev,
- "%s: host decrypted and reassembled frame did not fit skb\n",
- __func__);
- rtllib_frag_cache_invalidate(ieee, hdr);
- return -1;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb
- */
- skb_put_data(frag_skb, skb->data, flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb
- */
- skb_put_data(frag_skb, skb->data + hdrlen, flen);
- }
- dev_kfree_skb_any(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
- */
- return -2;
- }
-
- /* 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;
- rtllib_frag_cache_invalidate(ieee, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated
- */
- if ((fc & IEEE80211_FCTL_PROTECTED) &&
- rtllib_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) {
- netdev_info(ieee->dev, "%s: ==>decrypt msdu error\n", __func__);
- return -1;
- }
-
- hdr = (struct ieee80211_hdr *)skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
- if (/*ieee->ieee802_1x &&*/
- rtllib_is_eapol_frame(ieee, skb, hdrlen)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured
- */
- struct eapol *eap = (struct eapol *)(skb->data +
- 24);
- netdev_dbg(ieee->dev,
- "RX: IEEE 802.1X EAPOL frame: %s\n",
- eap_get_type(eap->type));
- } else {
- netdev_dbg(ieee->dev,
- "encryption configured, but RX frame not encrypted (SA= %pM)\n",
- hdr->addr2);
- return -1;
- }
- }
-
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) &&
- rtllib_is_eapol_frame(ieee, skb, hdrlen)) {
- struct eapol *eap = (struct eapol *)(skb->data + 24);
-
- netdev_dbg(ieee->dev, "RX: IEEE 802.1X EAPOL frame: %s\n",
- eap_get_type(eap->type));
- }
-
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
- !rtllib_is_eapol_frame(ieee, skb, hdrlen)) {
- netdev_dbg(ieee->dev,
- "dropped unencrypted RX data frame from %pM (drop_unencrypted=1)\n",
- hdr->addr2);
- return -1;
- }
-
- return 0;
-}
-
-static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast,
- u8 nr_subframes)
-{
- if (unicast) {
- if (ieee->link_state == MAC80211_LINKED) {
- if (((ieee->link_detect_info.num_rx_unicast_ok_in_period +
- ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
- (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2)) {
- ieee->leisure_ps_leave(ieee->dev);
- }
- }
- }
- ieee->last_rx_ps_time = jiffies;
-}
-
-static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee,
- struct rtllib_rx_stats *rx_stats,
- struct rtllib_rxb *rxb,
- u8 *dst,
- u8 *src)
-{
- struct net_device *dev = ieee->dev;
- u16 ethertype;
- int i = 0;
-
- if (!rxb) {
- netdev_info(dev, "%s: rxb is NULL!!\n", __func__);
- return;
- }
-
- for (i = 0; i < rxb->nr_subframes; i++) {
- struct sk_buff *sub_skb = rxb->subframes[i];
-
- if (sub_skb) {
- /* convert hdr + possible LLC headers
- * into Ethernet header
- */
- ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7];
- if (sub_skb->len >= 8 &&
- ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation
- * and replace EtherType
- */
- skb_pull(sub_skb, SNAP_SIZE);
- ether_addr_copy(skb_push(sub_skb, ETH_ALEN),
- src);
- ether_addr_copy(skb_push(sub_skb, ETH_ALEN),
- dst);
- } else {
- u16 len;
- /* Leave Ethernet header part of hdr
- * and full payload
- */
- len = sub_skb->len;
- memcpy(skb_push(sub_skb, 2), &len, 2);
- ether_addr_copy(skb_push(sub_skb, ETH_ALEN),
- src);
- ether_addr_copy(skb_push(sub_skb, ETH_ALEN),
- dst);
- }
-
- ieee->stats.rx_packets++;
- ieee->stats.rx_bytes += sub_skb->len;
-
- if (is_multicast_ether_addr(dst))
- ieee->stats.multicast++;
-
- /* Indicate the packets to upper layer */
- memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
- sub_skb->protocol = eth_type_trans(sub_skb, dev);
- sub_skb->dev = dev;
- sub_skb->dev->stats.rx_packets++;
- sub_skb->dev->stats.rx_bytes += sub_skb->len;
- /* 802.11 crc not sufficient */
- sub_skb->ip_summed = CHECKSUM_NONE;
- netif_rx(sub_skb);
- }
- }
- kfree(rxb);
-}
-
-static int rtllib_rx_infra_adhoc(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- struct net_device *dev = ieee->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct lib80211_crypt_data *crypt = NULL;
- struct rtllib_rxb *rxb = NULL;
- struct rx_ts_record *ts = NULL;
- u16 fc, sc, seq_num = 0;
- u8 type, stype, multicast = 0, unicast = 0, nr_subframes = 0, TID = 0;
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- u8 bssid[ETH_ALEN] = {0};
-
- size_t hdrlen = 0;
- int ret = 0, i = 0;
-
- fc = le16_to_cpu(hdr->frame_control);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
- sc = le16_to_cpu(hdr->seq_ctrl);
-
- /*Filter pkt not to me*/
- multicast = is_multicast_ether_addr(hdr->addr1);
- unicast = !multicast;
- if (unicast && !ether_addr_equal(dev->dev_addr, hdr->addr1))
- goto rx_dropped;
-
- /*Filter pkt has too small length */
- hdrlen = rtllib_rx_get_hdrlen(ieee, skb, rx_stats);
- if (skb->len < hdrlen) {
- netdev_info(dev,
- "%s():ERR!!! skb->len is smaller than hdrlen\n",
- __func__);
- goto rx_dropped;
- }
-
- /* Filter Duplicate pkt */
- ret = rtllib_rx_check_duplicate(ieee, skb, multicast);
- if (ret < 0)
- goto rx_dropped;
-
- /* Filter CTRL Frame */
- if (type == RTLLIB_FTYPE_CTL)
- goto rx_dropped;
-
- /* Filter MGNT Frame */
- if (type == RTLLIB_FTYPE_MGMT) {
- if (rtllib_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-
- /* Filter WAPI DATA Frame */
-
- /* Update statstics for AP roaming */
- ieee->link_detect_info.num_recv_data_in_period++;
- ieee->link_detect_info.num_rx_ok_in_period++;
-
- /* Data frame - extract src/dst addresses */
- rtllib_rx_extract_addr(ieee, hdr, dst, src, bssid);
-
- /* Filter Data frames */
- ret = rtllib_rx_data_filter(ieee, hdr, dst, src, bssid, hdr->addr2);
- if (ret < 0)
- goto rx_dropped;
-
- if (skb->len == hdrlen)
- goto rx_dropped;
-
- /* Send pspoll based on moredata */
- if ((ieee->iw_mode == IW_MODE_INFRA) &&
- (ieee->sta_sleep == LPS_IS_SLEEP) &&
- (ieee->polling)) {
- if (WLAN_FC_MORE_DATA(fc)) {
- /* more data bit is set, let's request a new frame
- * from the AP
- */
- rtllib_sta_ps_send_pspoll_frame(ieee);
- } else {
- ieee->polling = false;
- }
- }
-
- /* Get crypt if encrypted */
- ret = rtllib_rx_get_crypt(ieee, skb, &crypt, hdrlen);
- if (ret == -1)
- goto rx_dropped;
-
- /* Decrypt data frame (including reassemble) */
- ret = rtllib_rx_decrypt(ieee, skb, rx_stats, crypt, hdrlen);
- if (ret == -1)
- goto rx_dropped;
- else if (ret == -2)
- goto rx_exit;
-
- /* Get TS for Rx Reorder */
- hdr = (struct ieee80211_hdr *)skb->data;
- if (ieee->current_network.qos_data.active && is_qos_data_frame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1)) {
- TID = frame_qos_tid(skb->data);
- seq_num = WLAN_GET_SEQ_SEQ(sc);
- rtllib_get_ts(ieee, (struct ts_common_info **)&ts, hdr->addr2, TID,
- RX_DIR, true);
- if (TID != 0 && TID != 3)
- ieee->bis_any_nonbepkts = true;
- }
-
- /* Parse rx data frame (For AMSDU) */
- /* skb: hdr + (possible reassembled) full plaintext payload */
- rxb = kmalloc(sizeof(struct rtllib_rxb), GFP_ATOMIC);
- if (!rxb)
- goto rx_dropped;
-
- /* to parse amsdu packets */
- /* qos data packets & reserved bit is 1 */
- if (parse_subframe(ieee, skb, rx_stats, rxb, src, dst) == 0) {
- /* only to free rxb, and not submit the packets
- * to upper layer
- */
- for (i = 0; i < rxb->nr_subframes; i++)
- dev_kfree_skb(rxb->subframes[i]);
- kfree(rxb);
- rxb = NULL;
- goto rx_dropped;
- }
-
- /* Update WAPI PN */
-
- /* Check if leave LPS */
- if (ieee->is_aggregate_frame)
- nr_subframes = rxb->nr_subframes;
- else
- nr_subframes = 1;
- if (unicast)
- ieee->link_detect_info.num_rx_unicast_ok_in_period += nr_subframes;
- rtllib_rx_check_leave_lps(ieee, unicast, nr_subframes);
-
- /* Indicate packets to upper layer or Rx Reorder */
- if (!ieee->ht_info->cur_rx_reorder_enable || !ts)
- rtllib_rx_indicate_pkt_legacy(ieee, rx_stats, rxb, dst, src);
- else
- rx_reorder_indicate_packet(ieee, rxb, ts, seq_num);
-
- dev_kfree_skb(skb);
-
- rx_exit:
- return 1;
-
- rx_dropped:
- ieee->stats.rx_dropped++;
-
- /* Returning 0 indicates to caller that we have not handled the SKB--
- * so it is still allocated and can be used again by underlying
- * hardware as a DMA target
- */
- return 0;
-}
-
-static int rtllib_rx_monitor(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
- size_t hdrlen = rtllib_get_hdrlen(fc);
-
- if (skb->len < hdrlen) {
- netdev_info(ieee->dev,
- "%s():ERR!!! skb->len is smaller than hdrlen\n",
- __func__);
- return 0;
- }
-
- if (ht_c_check(ieee, skb->data)) {
- if (net_ratelimit())
- netdev_info(ieee->dev, "%s: Find HTCControl!\n",
- __func__);
- hdrlen += 4;
- }
-
- ieee->stats.rx_packets++;
- ieee->stats.rx_bytes += skb->len;
- rtllib_monitor_rx(ieee, skb, rx_stats, hdrlen);
-
- return 1;
-}
-
-/* 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).
- */
-int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- int ret = 0;
-
- if (!ieee || !skb || !rx_stats) {
- pr_info("%s: Input parameters NULL!\n", __func__);
- goto rx_dropped;
- }
- if (skb->len < 10) {
- netdev_info(ieee->dev, "%s: SKB length < 10\n", __func__);
- goto rx_dropped;
- }
-
- switch (ieee->iw_mode) {
- case IW_MODE_INFRA:
- ret = rtllib_rx_infra_adhoc(ieee, skb, rx_stats);
- break;
- case IW_MODE_MONITOR:
- ret = rtllib_rx_monitor(ieee, skb, rx_stats);
- break;
- default:
- netdev_info(ieee->dev, "%s: ERR iw mode!!!\n", __func__);
- break;
- }
-
- return ret;
-
- rx_dropped:
- if (ieee)
- ieee->stats.rx_dropped++;
- return 0;
-}
-EXPORT_SYMBOL(rtllib_rx);
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-/* Make ther structure we read from the beacon packet has the right values */
-static int rtllib_verify_qos_info(struct rtllib_qos_information_element
- *info_element, int sub_type)
-{
- if (info_element->element_id != QOS_ELEMENT_ID)
- return -1;
- if (info_element->qui_subtype != sub_type)
- return -1;
- if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
- return -1;
- if (info_element->qui_type != QOS_OUI_TYPE)
- return -1;
- if (info_element->version != QOS_VERSION_1)
- return -1;
-
- return 0;
-}
-
-/* Parse a QoS parameter element */
-static int rtllib_read_qos_param_element(
- struct rtllib_qos_parameter_info *element_param,
- struct rtllib_info_element *info_element)
-{
- size_t size = sizeof(*element_param);
-
- if (!element_param || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_param, info_element, size);
- return rtllib_verify_qos_info(&element_param->info_element,
- QOS_OUI_PARAM_SUB_TYPE);
-}
-
-/* Parse a QoS information element */
-static int rtllib_read_qos_info_element(
- struct rtllib_qos_information_element *element_info,
- struct rtllib_info_element *info_element)
-{
- size_t size = sizeof(*element_info);
-
- if (!element_info || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_info, info_element, size);
- return rtllib_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
-}
-
-/* Write QoS parameters from the ac parameters. */
-static int rtllib_qos_convert_ac_to_parameters(struct rtllib_qos_parameter_info *param_elm,
- struct rtllib_qos_data *qos_data)
-{
- struct rtllib_qos_ac_parameter *ac_params;
- struct rtllib_qos_parameters *qos_param = &(qos_data->parameters);
- int i;
- u8 aci;
- u8 acm;
-
- qos_data->wmm_acm = 0;
- for (i = 0; i < QOS_QUEUE_NUM; i++) {
- ac_params = &(param_elm->ac_params_record[i]);
-
- aci = (ac_params->aci_aifsn & 0x60) >> 5;
- acm = (ac_params->aci_aifsn & 0x10) >> 4;
-
- if (aci >= QOS_QUEUE_NUM)
- continue;
- switch (aci) {
- case 1:
- /* BIT(0) | BIT(3) */
- if (acm)
- qos_data->wmm_acm |= (0x01 << 0) | (0x01 << 3);
- break;
- case 2:
- /* BIT(4) | BIT(5) */
- if (acm)
- qos_data->wmm_acm |= (0x01 << 4) | (0x01 << 5);
- break;
- case 3:
- /* BIT(6) | BIT(7) */
- if (acm)
- qos_data->wmm_acm |= (0x01 << 6) | (0x01 << 7);
- break;
- case 0:
- default:
- /* BIT(1) | BIT(2) */
- if (acm)
- qos_data->wmm_acm |= (0x01 << 1) | (0x01 << 2);
- break;
- }
-
- qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f;
-
- /* WMM spec P.11: The minimum value for AIFSN shall be 2 */
- qos_param->aifs[aci] = max_t(u8, qos_param->aifs[aci], 2);
-
- qos_param->cw_min[aci] = cpu_to_le16(ac_params->ecw_min_max &
- 0x0F);
-
- qos_param->cw_max[aci] = cpu_to_le16((ac_params->ecw_min_max &
- 0xF0) >> 4);
-
- qos_param->flag[aci] =
- (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
- qos_param->tx_op_limit[aci] = ac_params->tx_op_limit;
- }
- return 0;
-}
-
-/* we have a generic data element which it may contain QoS information or
- * parameters element. check the information element length to decide
- * which type to read
- */
-static int rtllib_parse_qos_info_param_IE(struct rtllib_device *ieee,
- struct rtllib_info_element
- *info_element,
- struct rtllib_network *network)
-{
- int rc = 0;
- struct rtllib_qos_information_element qos_info_element;
-
- rc = rtllib_read_qos_info_element(&qos_info_element, info_element);
-
- if (rc == 0) {
- network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
- network->flags |= NETWORK_HAS_QOS_INFORMATION;
- } else {
- struct rtllib_qos_parameter_info param_element;
-
- rc = rtllib_read_qos_param_element(&param_element,
- info_element);
- if (rc == 0) {
- rtllib_qos_convert_ac_to_parameters(&param_element,
- &(network->qos_data));
- network->flags |= NETWORK_HAS_QOS_PARAMETERS;
- network->qos_data.param_count =
- param_element.info_element.ac_info & 0x0F;
- }
- }
-
- if (rc == 0) {
- netdev_dbg(ieee->dev, "QoS is supported\n");
- network->qos_data.supported = 1;
- }
- return rc;
-}
-
-static const char *get_info_element_string(u16 id)
-{
- switch (id) {
- case MFIE_TYPE_SSID:
- return "SSID";
- case MFIE_TYPE_RATES:
- return "RATES";
- case MFIE_TYPE_FH_SET:
- return "FH_SET";
- case MFIE_TYPE_DS_SET:
- return "DS_SET";
- case MFIE_TYPE_CF_SET:
- return "CF_SET";
- case MFIE_TYPE_TIM:
- return "TIM";
- case MFIE_TYPE_IBSS_SET:
- return "IBSS_SET";
- case MFIE_TYPE_COUNTRY:
- return "COUNTRY";
- case MFIE_TYPE_HOP_PARAMS:
- return "HOP_PARAMS";
- case MFIE_TYPE_HOP_TABLE:
- return "HOP_TABLE";
- case MFIE_TYPE_REQUEST:
- return "REQUEST";
- case MFIE_TYPE_CHALLENGE:
- return "CHALLENGE";
- case MFIE_TYPE_POWER_CONSTRAINT:
- return "POWER_CONSTRAINT";
- case MFIE_TYPE_POWER_CAPABILITY:
- return "POWER_CAPABILITY";
- case MFIE_TYPE_TPC_REQUEST:
- return "TPC_REQUEST";
- case MFIE_TYPE_TPC_REPORT:
- return "TPC_REPORT";
- case MFIE_TYPE_SUPP_CHANNELS:
- return "SUPP_CHANNELS";
- case MFIE_TYPE_CSA:
- return "CSA";
- case MFIE_TYPE_MEASURE_REQUEST:
- return "MEASURE_REQUEST";
- case MFIE_TYPE_MEASURE_REPORT:
- return "MEASURE_REPORT";
- case MFIE_TYPE_QUIET:
- return "QUIET";
- case MFIE_TYPE_IBSS_DFS:
- return "IBSS_DFS";
- case MFIE_TYPE_RSN:
- return "RSN";
- case MFIE_TYPE_RATES_EX:
- return "RATES_EX";
- case MFIE_TYPE_GENERIC:
- return "GENERIC";
- case MFIE_TYPE_QOS_PARAMETER:
- return "QOS_PARAMETER";
- default:
- return "UNKNOWN";
- }
-}
-
-static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
- struct rtllib_info_element *info_element,
- struct rtllib_network *network,
- u16 *tmp_htcap_len,
- u16 *tmp_htinfo_len)
-{
- u16 ht_realtek_agg_len = 0;
- u8 ht_realtek_agg_buf[MAX_IE_LEN];
-
- if (!rtllib_parse_qos_info_param_IE(ieee, info_element, network))
- return;
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x01) {
- network->wpa_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->wpa_ie, info_element, network->wpa_ie_len);
- return;
- }
- if (info_element->len == 7 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0xe0 &&
- info_element->data[2] == 0x4c &&
- info_element->data[3] == 0x01 &&
- info_element->data[4] == 0x02)
- network->turbo_enable = 1;
-
- if (*tmp_htcap_len == 0) {
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x90 &&
- info_element->data[2] == 0x4c &&
- info_element->data[3] == 0x033) {
- *tmp_htcap_len = min_t(u8, info_element->len,
- MAX_IE_LEN);
- if (*tmp_htcap_len != 0) {
- network->bssht.bd_ht_spec_ver = HT_SPEC_VER_EWC;
- network->bssht.bd_ht_cap_len = min_t(u16, *tmp_htcap_len,
- sizeof(network->bssht.bd_ht_cap_buf));
- memcpy(network->bssht.bd_ht_cap_buf,
- info_element->data,
- network->bssht.bd_ht_cap_len);
- }
- }
- if (*tmp_htcap_len != 0) {
- network->bssht.bd_support_ht = true;
- network->bssht.bd_ht_1r = ((((struct ht_capab_ele *)(network->bssht.bd_ht_cap_buf))->MCS[1]) == 0);
- } else {
- network->bssht.bd_support_ht = false;
- network->bssht.bd_ht_1r = false;
- }
- }
-
- if (*tmp_htinfo_len == 0) {
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x90 &&
- info_element->data[2] == 0x4c &&
- info_element->data[3] == 0x034) {
- *tmp_htinfo_len = min_t(u8, info_element->len,
- MAX_IE_LEN);
- if (*tmp_htinfo_len != 0) {
- network->bssht.bd_ht_spec_ver = HT_SPEC_VER_EWC;
- network->bssht.bd_ht_info_len = min_t(u16, *tmp_htinfo_len,
- sizeof(network->bssht.bd_ht_info_buf));
- memcpy(network->bssht.bd_ht_info_buf,
- info_element->data,
- network->bssht.bd_ht_info_len);
- }
- }
- }
-
- if (network->bssht.bd_support_ht) {
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0xe0 &&
- info_element->data[2] == 0x4c &&
- info_element->data[3] == 0x02) {
- ht_realtek_agg_len = min_t(u8, info_element->len,
- MAX_IE_LEN);
- memcpy(ht_realtek_agg_buf, info_element->data,
- info_element->len);
- }
- if (ht_realtek_agg_len >= 5) {
- network->realtek_cap_exit = true;
- network->bssht.bd_rt2rt_aggregation = true;
-
- if ((ht_realtek_agg_buf[4] == 1) &&
- (ht_realtek_agg_buf[5] & 0x02))
- network->bssht.bd_rt2rt_long_slot_time = true;
-
- if ((ht_realtek_agg_buf[4] == 1) &&
- (ht_realtek_agg_buf[5] & RT_HT_CAP_USE_92SE))
- network->bssht.rt2rt_ht_mode |= RT_HT_CAP_USE_92SE;
- }
- }
- if (ht_realtek_agg_len >= 5) {
- if ((ht_realtek_agg_buf[5] & RT_HT_CAP_USE_SOFTAP))
- network->bssht.rt2rt_ht_mode |= RT_HT_CAP_USE_SOFTAP;
- }
-
- if ((info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x05 &&
- info_element->data[2] == 0xb5) ||
- (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x0a &&
- info_element->data[2] == 0xf7) ||
- (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x10 &&
- info_element->data[2] == 0x18)) {
- network->broadcom_cap_exist = true;
- }
- if (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x0c &&
- info_element->data[2] == 0x43)
- network->ralink_cap_exist = true;
- if ((info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x03 &&
- info_element->data[2] == 0x7f) ||
- (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x13 &&
- info_element->data[2] == 0x74))
- network->atheros_cap_exist = true;
-
- if ((info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0x43))
- network->marvell_cap_exist = true;
- if (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x40 &&
- info_element->data[2] == 0x96)
- network->cisco_cap_exist = true;
-
- if (info_element->len >= 3 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x0a &&
- info_element->data[2] == 0xf5)
- network->airgo_cap_exist = true;
-
- if (info_element->len > 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x40 &&
- info_element->data[2] == 0x96 &&
- info_element->data[3] == 0x01) {
- if (info_element->len == 6) {
- memcpy(network->ccx_rm_state, &info_element->data[4], 2);
- if (network->ccx_rm_state[0] != 0)
- network->ccx_rm_enable = true;
- else
- network->ccx_rm_enable = false;
- network->mb_ssid_mask = network->ccx_rm_state[1] & 0x07;
- if (network->mb_ssid_mask != 0) {
- network->mb_ssid_valid = true;
- network->mb_ssid_mask = 0xff <<
- (network->mb_ssid_mask);
- ether_addr_copy(network->mb_ssid,
- network->bssid);
- network->mb_ssid[5] &= network->mb_ssid_mask;
- } else {
- network->mb_ssid_valid = false;
- }
- } else {
- network->ccx_rm_enable = false;
- }
- }
- if (info_element->len > 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x40 &&
- info_element->data[2] == 0x96 &&
- info_element->data[3] == 0x03) {
- if (info_element->len == 5) {
- network->with_ccx_ver_num = true;
- network->bss_ccx_ver_number = info_element->data[4];
- } else {
- network->with_ccx_ver_num = false;
- network->bss_ccx_ver_number = 0;
- }
- }
- if (info_element->len > 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x04) {
- netdev_dbg(ieee->dev, "MFIE_TYPE_WZC: %d bytes\n",
- info_element->len);
- network->wzc_ie_len = min(info_element->len + 2, MAX_WZC_IE_LEN);
- memcpy(network->wzc_ie, info_element, network->wzc_ie_len);
- }
-}
-
-static void rtllib_parse_mfie_ht_cap(struct rtllib_info_element *info_element,
- struct rtllib_network *network,
- u16 *tmp_htcap_len)
-{
- struct bss_ht *ht = &network->bssht;
-
- *tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN);
- if (*tmp_htcap_len != 0) {
- ht->bd_ht_spec_ver = HT_SPEC_VER_EWC;
- ht->bd_ht_cap_len = min_t(u16, *tmp_htcap_len,
- sizeof(ht->bd_ht_cap_buf));
- memcpy(ht->bd_ht_cap_buf, info_element->data, ht->bd_ht_cap_len);
-
- ht->bd_support_ht = true;
- ht->bd_ht_1r = ((((struct ht_capab_ele *)
- ht->bd_ht_cap_buf))->MCS[1]) == 0;
-
- ht->bd_bandwidth = (enum ht_channel_width)
- (((struct ht_capab_ele *)
- (ht->bd_ht_cap_buf))->chl_width);
- } else {
- ht->bd_support_ht = false;
- ht->bd_ht_1r = false;
- ht->bd_bandwidth = HT_CHANNEL_WIDTH_20;
- }
-}
-
-int rtllib_parse_info_param(struct rtllib_device *ieee,
- struct rtllib_info_element *info_element,
- u16 length,
- struct rtllib_network *network,
- struct rtllib_rx_stats *stats)
-{
- u8 i;
- short offset;
- u16 tmp_htcap_len = 0;
- u16 tmp_htinfo_len = 0;
- char rates_str[64];
- char *p;
-
- while (length >= sizeof(*info_element)) {
- if (sizeof(*info_element) + info_element->len > length) {
- netdev_dbg(ieee->dev,
- "Info elem: parse failed: info_element->len + 2 > left : info_element->len+2=%zd left=%d, id=%d.\n",
- info_element->len + sizeof(*info_element),
- length, info_element->id);
- /* We stop processing but don't return an error here
- * because some misbehaviour APs break this rule. ie.
- * Orinoco AP1000.
- */
- break;
- }
-
- switch (info_element->id) {
- case MFIE_TYPE_SSID:
- if (rtllib_is_empty_essid(info_element->data,
- info_element->len)) {
- network->flags |= NETWORK_EMPTY_ESSID;
- break;
- }
-
- network->ssid_len = min(info_element->len,
- (u8)IW_ESSID_MAX_SIZE);
- memcpy(network->ssid, info_element->data,
- network->ssid_len);
- if (network->ssid_len < IW_ESSID_MAX_SIZE)
- memset(network->ssid + network->ssid_len, 0,
- IW_ESSID_MAX_SIZE - network->ssid_len);
-
- netdev_dbg(ieee->dev, "MFIE_TYPE_SSID: '%s' len=%d.\n",
- network->ssid, network->ssid_len);
- break;
-
- case MFIE_TYPE_RATES:
- p = rates_str;
- network->rates_len = min(info_element->len,
- MAX_RATES_LENGTH);
- for (i = 0; i < network->rates_len; i++) {
- network->rates[i] = info_element->data[i];
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates[i]);
- if (rtllib_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- RTLLIB_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
-
- if (rtllib_is_cck_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_CCK;
- }
- }
-
- netdev_dbg(ieee->dev, "MFIE_TYPE_RATES: '%s' (%d)\n",
- rates_str, network->rates_len);
- break;
-
- case MFIE_TYPE_RATES_EX:
- p = rates_str;
- network->rates_ex_len = min(info_element->len,
- MAX_RATES_EX_LENGTH);
- for (i = 0; i < network->rates_ex_len; i++) {
- network->rates_ex[i] = info_element->data[i];
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates_ex[i]);
- if (rtllib_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- RTLLIB_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- netdev_dbg(ieee->dev, "MFIE_TYPE_RATES_EX: '%s' (%d)\n",
- rates_str, network->rates_ex_len);
- break;
-
- case MFIE_TYPE_DS_SET:
- netdev_dbg(ieee->dev, "MFIE_TYPE_DS_SET: %d\n",
- info_element->data[0]);
- network->channel = info_element->data[0];
- break;
-
- case MFIE_TYPE_FH_SET:
- netdev_dbg(ieee->dev, "MFIE_TYPE_FH_SET: ignored\n");
- break;
-
- case MFIE_TYPE_CF_SET:
- netdev_dbg(ieee->dev, "MFIE_TYPE_CF_SET: ignored\n");
- break;
-
- case MFIE_TYPE_TIM:
- if (info_element->len < 4)
- break;
-
- network->tim.tim_count = info_element->data[0];
- network->tim.tim_period = info_element->data[1];
-
- network->dtim_period = info_element->data[1];
- if (ieee->link_state != MAC80211_LINKED)
- break;
- network->last_dtim_sta_time = jiffies;
-
- network->dtim_data = RTLLIB_DTIM_VALID;
-
- if (info_element->data[2] & 1)
- network->dtim_data |= RTLLIB_DTIM_MBCAST;
-
- offset = (info_element->data[2] >> 1) * 2;
-
- if (ieee->assoc_id < 8 * offset ||
- ieee->assoc_id > 8 * (offset + info_element->len - 3))
- break;
-
- offset = (ieee->assoc_id / 8) - offset;
- if (info_element->data[3 + offset] &
- (1 << (ieee->assoc_id % 8)))
- network->dtim_data |= RTLLIB_DTIM_UCAST;
-
- network->listen_interval = network->dtim_period;
- break;
-
- case MFIE_TYPE_ERP:
- network->erp_value = info_element->data[0];
- network->flags |= NETWORK_HAS_ERP_VALUE;
- netdev_dbg(ieee->dev, "MFIE_TYPE_ERP_SET: %d\n",
- network->erp_value);
- break;
- case MFIE_TYPE_IBSS_SET:
- network->atim_window = info_element->data[0];
- netdev_dbg(ieee->dev, "MFIE_TYPE_IBSS_SET: %d\n",
- network->atim_window);
- break;
-
- case MFIE_TYPE_CHALLENGE:
- netdev_dbg(ieee->dev, "MFIE_TYPE_CHALLENGE: ignored\n");
- break;
-
- case MFIE_TYPE_GENERIC:
- netdev_dbg(ieee->dev, "MFIE_TYPE_GENERIC: %d bytes\n",
- info_element->len);
-
- rtllib_parse_mife_generic(ieee, info_element, network,
- &tmp_htcap_len,
- &tmp_htinfo_len);
- break;
-
- case MFIE_TYPE_RSN:
- netdev_dbg(ieee->dev, "MFIE_TYPE_RSN: %d bytes\n",
- info_element->len);
- network->rsn_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->rsn_ie, info_element,
- network->rsn_ie_len);
- break;
-
- case MFIE_TYPE_HT_CAP:
- netdev_dbg(ieee->dev, "MFIE_TYPE_HT_CAP: %d bytes\n",
- info_element->len);
-
- rtllib_parse_mfie_ht_cap(info_element, network,
- &tmp_htcap_len);
- break;
-
- case MFIE_TYPE_HT_INFO:
- netdev_dbg(ieee->dev, "MFIE_TYPE_HT_INFO: %d bytes\n",
- info_element->len);
- tmp_htinfo_len = min_t(u8, info_element->len,
- MAX_IE_LEN);
- if (tmp_htinfo_len) {
- network->bssht.bd_ht_spec_ver = HT_SPEC_VER_IEEE;
- network->bssht.bd_ht_info_len = tmp_htinfo_len >
- sizeof(network->bssht.bd_ht_info_buf) ?
- sizeof(network->bssht.bd_ht_info_buf) :
- tmp_htinfo_len;
- memcpy(network->bssht.bd_ht_info_buf,
- info_element->data,
- network->bssht.bd_ht_info_len);
- }
- break;
-
- case MFIE_TYPE_AIRONET:
- netdev_dbg(ieee->dev, "MFIE_TYPE_AIRONET: %d bytes\n",
- info_element->len);
- if (info_element->len > IE_CISCO_FLAG_POSITION) {
- network->with_aironet_ie = true;
-
- if ((info_element->data[IE_CISCO_FLAG_POSITION]
- & SUPPORT_CKIP_MIC) ||
- (info_element->data[IE_CISCO_FLAG_POSITION]
- & SUPPORT_CKIP_PK))
- network->ckip_supported = true;
- else
- network->ckip_supported = false;
- } else {
- network->with_aironet_ie = false;
- network->ckip_supported = false;
- }
- break;
- case MFIE_TYPE_QOS_PARAMETER:
- netdev_err(ieee->dev,
- "QoS Error need to parse QOS_PARAMETER IE\n");
- break;
-
- case MFIE_TYPE_COUNTRY:
- netdev_dbg(ieee->dev, "MFIE_TYPE_COUNTRY: %d bytes\n",
- info_element->len);
- break;
-/* TODO */
- default:
- netdev_dbg(ieee->dev,
- "Unsupported info element: %s (%d)\n",
- get_info_element_string(info_element->id),
- info_element->id);
- break;
- }
-
- length -= sizeof(*info_element) + info_element->len;
- info_element =
- (struct rtllib_info_element *)&info_element->data[info_element->len];
- }
-
- if (!network->atheros_cap_exist && !network->broadcom_cap_exist &&
- !network->cisco_cap_exist && !network->ralink_cap_exist &&
- !network->bssht.bd_rt2rt_aggregation)
- network->unknown_cap_exist = true;
- else
- network->unknown_cap_exist = false;
- return 0;
-}
-
-static long rtllib_translate_todbm(u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
-
- return signal_power;
-}
-
-static inline int rtllib_network_init(
- struct rtllib_device *ieee,
- struct rtllib_probe_response *beacon,
- struct rtllib_network *network,
- struct rtllib_rx_stats *stats)
-{
- memset(&network->qos_data, 0, sizeof(struct rtllib_qos_data));
-
- /* Pull out fixed field data */
- ether_addr_copy(network->bssid, beacon->header.addr3);
- network->capability = le16_to_cpu(beacon->capability);
- network->last_scanned = jiffies;
- network->time_stamp[0] = beacon->time_stamp[0];
- network->time_stamp[1] = beacon->time_stamp[1];
- network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
- /* Where to pull this? beacon->listen_interval;*/
- network->listen_interval = 0x0A;
- network->rates_len = network->rates_ex_len = 0;
- network->ssid_len = 0;
- network->hidden_ssid_len = 0;
- memset(network->hidden_ssid, 0, sizeof(network->hidden_ssid));
- network->flags = 0;
- network->atim_window = 0;
- network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
- 0x3 : 0x0;
- network->berp_info_valid = false;
- network->broadcom_cap_exist = false;
- network->ralink_cap_exist = false;
- network->atheros_cap_exist = false;
- network->cisco_cap_exist = false;
- network->unknown_cap_exist = false;
- network->realtek_cap_exit = false;
- network->marvell_cap_exist = false;
- network->airgo_cap_exist = false;
- network->turbo_enable = 0;
- network->signal_strength = stats->signal_strength;
- network->RSSI = stats->signal_strength;
- network->country_ie_len = 0;
- memset(network->country_ie_buf, 0, MAX_IE_LEN);
- ht_initialize_bss_desc(&network->bssht);
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
- network->wzc_ie_len = 0;
-
- if (rtllib_parse_info_param(ieee,
- beacon->info_element,
- (stats->len - sizeof(*beacon)),
- network,
- stats))
- return 1;
-
- network->mode = 0;
-
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= WIRELESS_MODE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= WIRELESS_MODE_B;
-
- if (network->mode == 0) {
- netdev_dbg(ieee->dev, "Filtered out '%s (%pM)' network.\n",
- escape_essid(network->ssid, network->ssid_len),
- network->bssid);
- return 1;
- }
-
- if (network->bssht.bd_support_ht) {
- if (network->mode & (WIRELESS_MODE_G | WIRELESS_MODE_B))
- network->mode = WIRELESS_MODE_N_24G;
- }
- if (rtllib_is_empty_essid(network->ssid, network->ssid_len))
- network->flags |= NETWORK_EMPTY_ESSID;
- stats->signal = 30 + (stats->signal_strength * 70) / 100;
- stats->noise = rtllib_translate_todbm((u8)(100 - stats->signal)) - 25;
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- return 0;
-}
-
-static inline int is_same_network(struct rtllib_network *src,
- struct rtllib_network *dst, u8 ssidbroad)
-{
- /* A network is only a duplicate if the channel, BSSID, ESSID
- * and the capability field (in particular IBSS and BSS) all match.
- * We treat all <hidden> with the same BSSID and channel
- * as one network
- */
- return (((src->ssid_len == dst->ssid_len) || (!ssidbroad)) &&
- (src->channel == dst->channel) &&
- !memcmp(src->bssid, dst->bssid, ETH_ALEN) &&
- (!memcmp(src->ssid, dst->ssid, src->ssid_len) ||
- (!ssidbroad)) &&
- ((src->capability & WLAN_CAPABILITY_IBSS) ==
- (dst->capability & WLAN_CAPABILITY_IBSS)) &&
- ((src->capability & WLAN_CAPABILITY_ESS) ==
- (dst->capability & WLAN_CAPABILITY_ESS)));
-}
-
-static inline void update_network(struct rtllib_device *ieee,
- struct rtllib_network *dst,
- struct rtllib_network *src)
-{
- int qos_active;
- u8 old_param;
-
- memcpy(&dst->stats, &src->stats, sizeof(struct rtllib_rx_stats));
- dst->capability = src->capability;
- memcpy(dst->rates, src->rates, src->rates_len);
- dst->rates_len = src->rates_len;
- memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
- dst->rates_ex_len = src->rates_ex_len;
- if (src->ssid_len > 0) {
- if (dst->ssid_len == 0) {
- memset(dst->hidden_ssid, 0, sizeof(dst->hidden_ssid));
- dst->hidden_ssid_len = src->ssid_len;
- memcpy(dst->hidden_ssid, src->ssid, src->ssid_len);
- } else {
- memset(dst->ssid, 0, dst->ssid_len);
- dst->ssid_len = src->ssid_len;
- memcpy(dst->ssid, src->ssid, src->ssid_len);
- }
- }
- dst->mode = src->mode;
- dst->flags = src->flags;
- dst->time_stamp[0] = src->time_stamp[0];
- dst->time_stamp[1] = src->time_stamp[1];
- if (src->flags & NETWORK_HAS_ERP_VALUE) {
- dst->erp_value = src->erp_value;
- dst->berp_info_valid = src->berp_info_valid = true;
- }
- dst->beacon_interval = src->beacon_interval;
- dst->listen_interval = src->listen_interval;
- dst->atim_window = src->atim_window;
- dst->dtim_period = src->dtim_period;
- dst->dtim_data = src->dtim_data;
- dst->last_dtim_sta_time = src->last_dtim_sta_time;
- memcpy(&dst->tim, &src->tim, sizeof(struct rtllib_tim_parameters));
-
- dst->bssht.bd_support_ht = src->bssht.bd_support_ht;
- dst->bssht.bd_rt2rt_aggregation = src->bssht.bd_rt2rt_aggregation;
- dst->bssht.bd_ht_cap_len = src->bssht.bd_ht_cap_len;
- memcpy(dst->bssht.bd_ht_cap_buf, src->bssht.bd_ht_cap_buf,
- src->bssht.bd_ht_cap_len);
- dst->bssht.bd_ht_info_len = src->bssht.bd_ht_info_len;
- memcpy(dst->bssht.bd_ht_info_buf, src->bssht.bd_ht_info_buf,
- src->bssht.bd_ht_info_len);
- dst->bssht.bd_ht_spec_ver = src->bssht.bd_ht_spec_ver;
- dst->bssht.bd_rt2rt_long_slot_time = src->bssht.bd_rt2rt_long_slot_time;
- dst->broadcom_cap_exist = src->broadcom_cap_exist;
- dst->ralink_cap_exist = src->ralink_cap_exist;
- dst->atheros_cap_exist = src->atheros_cap_exist;
- dst->realtek_cap_exit = src->realtek_cap_exit;
- dst->marvell_cap_exist = src->marvell_cap_exist;
- dst->cisco_cap_exist = src->cisco_cap_exist;
- dst->airgo_cap_exist = src->airgo_cap_exist;
- dst->unknown_cap_exist = src->unknown_cap_exist;
- memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
- dst->wpa_ie_len = src->wpa_ie_len;
- memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
- dst->rsn_ie_len = src->rsn_ie_len;
- memcpy(dst->wzc_ie, src->wzc_ie, src->wzc_ie_len);
- dst->wzc_ie_len = src->wzc_ie_len;
-
- dst->last_scanned = jiffies;
- /* qos related parameters */
- qos_active = dst->qos_data.active;
- old_param = dst->qos_data.param_count;
- dst->qos_data.supported = src->qos_data.supported;
- if (dst->flags & NETWORK_HAS_QOS_PARAMETERS)
- memcpy(&dst->qos_data, &src->qos_data,
- sizeof(struct rtllib_qos_data));
- if (dst->qos_data.supported == 1) {
- if (dst->ssid_len)
- netdev_dbg(ieee->dev,
- "QoS the network %s is QoS supported\n",
- dst->ssid);
- else
- netdev_dbg(ieee->dev,
- "QoS the network is QoS supported\n");
- }
- dst->qos_data.active = qos_active;
- dst->qos_data.old_param_count = old_param;
-
- dst->wmm_info = src->wmm_info;
- if (src->wmm_param[0].ac_aci_acm_aifsn ||
- src->wmm_param[1].ac_aci_acm_aifsn ||
- src->wmm_param[2].ac_aci_acm_aifsn ||
- src->wmm_param[3].ac_aci_acm_aifsn)
- memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
-
- dst->signal_strength = src->signal_strength;
- dst->RSSI = src->RSSI;
- dst->turbo_enable = src->turbo_enable;
-
- dst->country_ie_len = src->country_ie_len;
- memcpy(dst->country_ie_buf, src->country_ie_buf, src->country_ie_len);
-
- dst->with_aironet_ie = src->with_aironet_ie;
- dst->ckip_supported = src->ckip_supported;
- memcpy(dst->ccx_rm_state, src->ccx_rm_state, 2);
- dst->ccx_rm_enable = src->ccx_rm_enable;
- dst->mb_ssid_mask = src->mb_ssid_mask;
- dst->mb_ssid_valid = src->mb_ssid_valid;
- memcpy(dst->mb_ssid, src->mb_ssid, 6);
- dst->with_ccx_ver_num = src->with_ccx_ver_num;
- dst->bss_ccx_ver_number = src->bss_ccx_ver_number;
-}
-
-static int is_passive_channel(struct rtllib_device *rtllib, u8 channel)
-{
- if (channel > MAX_CHANNEL_NUMBER) {
- netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__);
- return 0;
- }
-
- if (rtllib->active_channel_map[channel] == 2)
- return 1;
-
- return 0;
-}
-
-int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel)
-{
- if (channel > MAX_CHANNEL_NUMBER) {
- netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__);
- return 0;
- }
- if (rtllib->active_channel_map[channel] > 0)
- return 1;
-
- return 0;
-}
-EXPORT_SYMBOL(rtllib_legal_channel);
-
-static inline void rtllib_process_probe_response(
- struct rtllib_device *ieee,
- struct rtllib_probe_response *beacon,
- struct rtllib_rx_stats *stats)
-{
- struct rtllib_network *target;
- struct rtllib_network *oldest = NULL;
- struct rtllib_info_element *info_element = &beacon->info_element[0];
- unsigned long flags;
- short renew;
- struct rtllib_network *network = kzalloc(sizeof(struct rtllib_network),
- GFP_ATOMIC);
- __le16 frame_ctl = beacon->header.frame_control;
-
- if (!network)
- return;
-
- netdev_dbg(ieee->dev,
- "'%s' ( %pM ): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
- escape_essid(info_element->data, info_element->len),
- beacon->header.addr3,
- (le16_to_cpu(beacon->capability) & (1 << 0xf)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0xe)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0xd)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0xc)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0xb)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0xa)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x9)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x8)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x7)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x6)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x5)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x4)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x3)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x2)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x1)) ? '1' : '0',
- (le16_to_cpu(beacon->capability) & (1 << 0x0)) ? '1' : '0');
-
- if (rtllib_network_init(ieee, beacon, network, stats)) {
- netdev_dbg(ieee->dev, "Dropped '%s' ( %pM) via %s.\n",
- escape_essid(info_element->data, info_element->len),
- beacon->header.addr3,
- ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE");
- goto free_network;
- }
-
- if (!rtllib_legal_channel(ieee, network->channel))
- goto free_network;
-
- if (ieee80211_is_probe_resp(frame_ctl)) {
- if (is_passive_channel(ieee, network->channel)) {
- netdev_info(ieee->dev,
- "GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n",
- network->channel);
- goto free_network;
- }
- }
-
- /* The network parsed correctly -- so now we scan our known networks
- * to see if we can find it in our list.
- *
- * NOTE: This search is definitely not optimized. Once its doing
- * the "right thing" we'll optimize it for efficiency if
- * necessary
- */
-
- /* Search for this entry in the list and update it if it is
- * already there.
- */
-
- spin_lock_irqsave(&ieee->lock, flags);
- if (is_same_network(&ieee->current_network, network,
- (network->ssid_len ? 1 : 0))) {
- update_network(ieee, &ieee->current_network, network);
- if ((ieee->current_network.mode == WIRELESS_MODE_N_24G ||
- ieee->current_network.mode == WIRELESS_MODE_G) &&
- ieee->current_network.berp_info_valid) {
- if (ieee->current_network.erp_value & ERP_UseProtection)
- ieee->current_network.buseprotection = true;
- else
- ieee->current_network.buseprotection = false;
- }
- if (ieee80211_is_beacon(frame_ctl)) {
- if (ieee->link_state >= MAC80211_LINKED)
- ieee->link_detect_info.num_recv_bcn_in_period++;
- }
- }
- list_for_each_entry(target, &ieee->network_list, list) {
- if (is_same_network(target, network,
- (target->ssid_len ? 1 : 0)))
- break;
- if (!oldest || (target->last_scanned < oldest->last_scanned))
- oldest = target;
- }
-
- /* If we didn't find a match, then get a new network slot to initialize
- * with this beacon's information
- */
- if (&target->list == &ieee->network_list) {
- if (list_empty(&ieee->network_free_list)) {
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- netdev_dbg(ieee->dev,
- "Expired '%s' ( %pM) from network list.\n",
- escape_essid(target->ssid, target->ssid_len),
- target->bssid);
- } else {
- /* Otherwise just pull from the free list */
- target = list_entry(ieee->network_free_list.next,
- struct rtllib_network, list);
- list_del(ieee->network_free_list.next);
- }
-
- netdev_dbg(ieee->dev, "Adding '%s' ( %pM) via %s.\n",
- escape_essid(network->ssid, network->ssid_len),
- network->bssid,
- ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE");
-
- memcpy(target, network, sizeof(*target));
- list_add_tail(&target->list, &ieee->network_list);
- if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)
- rtllib_softmac_new_net(ieee, network);
- } else {
- netdev_dbg(ieee->dev, "Updating '%s' ( %pM) via %s.\n",
- escape_essid(target->ssid, target->ssid_len),
- target->bssid,
- ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE");
-
- /* we have an entry and we are going to update it. But this
- * entry may be already expired. In this case we do the same
- * as we found a new net and call the new_net handler
- */
- renew = !time_after(target->last_scanned + ieee->scan_age,
- jiffies);
- if ((!target->ssid_len) &&
- (((network->ssid_len > 0) && (target->hidden_ssid_len == 0))
- || ((ieee->current_network.ssid_len == network->ssid_len) &&
- (strncmp(ieee->current_network.ssid, network->ssid,
- network->ssid_len) == 0) &&
- (ieee->link_state == MAC80211_NOLINK))))
- renew = 1;
- update_network(ieee, target, network);
- if (renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE))
- rtllib_softmac_new_net(ieee, network);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
- if (ieee80211_is_beacon(frame_ctl) &&
- is_same_network(&ieee->current_network, network,
- (network->ssid_len ? 1 : 0)) &&
- (ieee->link_state == MAC80211_LINKED)) {
- ieee->handle_beacon(ieee->dev, beacon, &ieee->current_network);
- }
-free_network:
- kfree(network);
-}
-
-static void rtllib_rx_mgt(struct rtllib_device *ieee,
- struct sk_buff *skb,
- struct rtllib_rx_stats *stats)
-{
- struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->data;
-
- if (!ieee80211_is_probe_resp(header->frame_control) &&
- (!ieee80211_is_beacon(header->frame_control)))
- ieee->last_rx_ps_time = jiffies;
-
- if (ieee80211_is_beacon(header->frame_control)) {
- netdev_dbg(ieee->dev, "received BEACON\n");
- rtllib_process_probe_response(
- ieee, (struct rtllib_probe_response *)header,
- stats);
-
- if (ieee->sta_sleep || (ieee->ps != RTLLIB_PS_DISABLED &&
- ieee->iw_mode == IW_MODE_INFRA &&
- ieee->link_state == MAC80211_LINKED))
- schedule_work(&ieee->ps_task);
- } else if (ieee80211_is_probe_resp(header->frame_control)) {
- netdev_dbg(ieee->dev, "received PROBE RESPONSE\n");
- rtllib_process_probe_response(ieee, (struct rtllib_probe_response *)header,
- stats);
- }
-}
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
deleted file mode 100644
index 0fc97c868f81..000000000000
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ /dev/null
@@ -1,2309 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
- *
- * Mostly extracted from the rtl8180-sa2400 driver for the
- * in-kernel generic ieee802.11 stack.
- *
- * Few lines might be stolen from other part of the rtllib
- * stack. Copyright who own it's copyright
- *
- * WPA code stolen from the ipw2200 driver.
- * Copyright who own it's copyright.
- */
-#include "rtllib.h"
-
-#include <linux/random.h>
-#include <linux/delay.h>
-#include <linux/uaccess.h>
-#include <linux/etherdevice.h>
-#include <linux/ieee80211.h>
-
-static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl);
-
-static short rtllib_is_54g(struct rtllib_network *net)
-{
- return (net->rates_ex_len > 0) || (net->rates_len > 4);
-}
-
-/* returns the total length needed for placing the RATE MFIE
- * tag and the EXTENDED RATE MFIE tag if needed.
- * It encludes two bytes per tag for the tag itself and its len
- */
-static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee)
-{
- unsigned int rate_len = 0;
-
- rate_len = RTLLIB_CCK_RATE_LEN + 2;
- rate_len += RTLLIB_OFDM_RATE_LEN + 2;
-
- return rate_len;
-}
-
-/* place the MFIE rate, tag to the memory (double) pointed.
- * Then it updates the pointer so that
- * it points after the new MFIE tag added.
- */
-static void rtllib_mfie_brate(struct rtllib_device *ieee, u8 **tag_p)
-{
- u8 *tag = *tag_p;
-
- *tag++ = MFIE_TYPE_RATES;
- *tag++ = 4;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB;
-
- /* We may add an option for custom rates that specific HW
- * might support
- */
- *tag_p = tag;
-}
-
-static void rtllib_mfie_grate(struct rtllib_device *ieee, u8 **tag_p)
-{
- u8 *tag = *tag_p;
-
- *tag++ = MFIE_TYPE_RATES_EX;
- *tag++ = 8;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_6MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_9MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_12MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_18MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_24MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_36MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_48MB;
- *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_54MB;
-
- /* We may add an option for custom rates that specific HW might
- * support
- */
- *tag_p = tag;
-}
-
-static void rtllib_wmm_info(struct rtllib_device *ieee, u8 **tag_p)
-{
- u8 *tag = *tag_p;
-
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = 7;
- *tag++ = 0x00;
- *tag++ = 0x50;
- *tag++ = 0xf2;
- *tag++ = 0x02;
- *tag++ = 0x00;
- *tag++ = 0x01;
- *tag++ = MAX_SP_Len;
- *tag_p = tag;
-}
-
-static void rtllib_turbo_info(struct rtllib_device *ieee, u8 **tag_p)
-{
- u8 *tag = *tag_p;
-
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = 7;
- *tag++ = 0x00;
- *tag++ = 0xe0;
- *tag++ = 0x4c;
- *tag++ = 0x01;
- *tag++ = 0x02;
- *tag++ = 0x11;
- *tag++ = 0x00;
-
- *tag_p = tag;
- netdev_alert(ieee->dev, "This is enable turbo mode IE process\n");
-}
-
-static void enqueue_mgmt(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- int nh;
-
- nh = (ieee->mgmt_queue_head + 1) % MGMT_QUEUE_NUM;
-
-/* if the queue is full but we have newer frames then
- * just overwrites the oldest.
- *
- * if (nh == ieee->mgmt_queue_tail)
- * return -1;
- */
- ieee->mgmt_queue_head = nh;
- ieee->mgmt_queue_ring[nh] = skb;
-}
-
-static void init_mgmt_queue(struct rtllib_device *ieee)
-{
- ieee->mgmt_queue_tail = 0;
- ieee->mgmt_queue_head = 0;
-}
-
-u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee)
-{
- u16 i;
- u8 query_rate = 0;
- u8 basic_rate;
-
- for (i = 0; i < ieee->current_network.rates_len; i++) {
- basic_rate = ieee->current_network.rates[i] & 0x7F;
- if (!rtllib_is_cck_rate(basic_rate)) {
- if (query_rate == 0) {
- query_rate = basic_rate;
- } else {
- if (basic_rate < query_rate)
- query_rate = basic_rate;
- }
- }
- }
-
- if (query_rate == 0) {
- query_rate = 12;
- netdev_info(ieee->dev, "No basic_rate found!!\n");
- }
- return query_rate;
-}
-
-static u8 mgnt_query_mgnt_frame_tx_rate(struct rtllib_device *ieee)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- u8 rate;
-
- if (ht_info->iot_action & HT_IOT_ACT_MGNT_USE_CCK_6M)
- rate = 0x0c;
- else
- rate = ieee->basic_rate & 0x7f;
-
- if (rate == 0)
- rate = 0x02;
-
- return rate;
-}
-
-inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee)
-{
- unsigned long flags;
- short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
- struct ieee80211_hdr_3addr *header =
- (struct ieee80211_hdr_3addr *)skb->data;
-
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8);
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* called with 2nd param 0, no mgmt lock required */
- rtllib_sta_wakeup(ieee, 0);
-
- if (ieee80211_is_beacon(header->frame_control))
- tcb_desc->queue_index = BEACON_QUEUE;
- else
- tcb_desc->queue_index = MGNT_QUEUE;
-
- if (ieee->disable_mgnt_queue)
- tcb_desc->queue_index = HIGH_QUEUE;
-
- tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee);
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_dis_rate_fallback = 1;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- if (single) {
- if (ieee->queue_stop) {
- enqueue_mgmt(ieee, skb);
- } else {
- header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
-
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
-
- /* avoid watchdog triggers */
- ieee->softmac_data_hard_start_xmit(skb, ieee->dev,
- ieee->basic_rate);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
- } else {
- spin_unlock_irqrestore(&ieee->lock, flags);
- spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
-
- header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
-
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
-
- /* check whether the managed packet queued greater than 5 */
- if (!ieee->check_nic_enough_desc(ieee->dev,
- tcb_desc->queue_index) ||
- skb_queue_len(&ieee->skb_waitq[tcb_desc->queue_index]) ||
- ieee->queue_stop) {
- /* insert the skb packet to the management queue
- *
- * as for the completion function, it does not need
- * to check it any more.
- */
- netdev_info(ieee->dev,
- "%s():insert to waitqueue, queue_index:%d!\n",
- __func__, tcb_desc->queue_index);
- skb_queue_tail(&ieee->skb_waitq[tcb_desc->queue_index],
- skb);
- } else {
- ieee->softmac_hard_start_xmit(skb, ieee->dev);
- }
- spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags);
- }
-}
-
-static inline void
-softmac_ps_mgmt_xmit(struct sk_buff *skb,
- struct rtllib_device *ieee)
-{
- short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
- struct ieee80211_hdr_3addr *header =
- (struct ieee80211_hdr_3addr *)skb->data;
- u16 fc, type, stype;
- struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8);
-
- fc = le16_to_cpu(header->frame_control);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
-
- if (stype != IEEE80211_STYPE_PSPOLL)
- tcb_desc->queue_index = MGNT_QUEUE;
- else
- tcb_desc->queue_index = HIGH_QUEUE;
-
- if (ieee->disable_mgnt_queue)
- tcb_desc->queue_index = HIGH_QUEUE;
-
- tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee);
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_dis_rate_fallback = 1;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- if (single) {
- if (type != RTLLIB_FTYPE_CTL) {
- header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
-
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
- }
- /* avoid watchdog triggers */
- ieee->softmac_data_hard_start_xmit(skb, ieee->dev,
- ieee->basic_rate);
-
- } else {
- if (type != RTLLIB_FTYPE_CTL) {
- header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
-
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
- }
- ieee->softmac_hard_start_xmit(skb, ieee->dev);
- }
-}
-
-static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee)
-{
- unsigned int len, rate_len;
- u8 *tag;
- struct sk_buff *skb;
- struct rtllib_probe_request *req;
-
- len = ieee->current_network.ssid_len;
-
- rate_len = rtllib_MFIE_rate_len(ieee);
-
- skb = dev_alloc_skb(sizeof(struct rtllib_probe_request) +
- 2 + len + rate_len + ieee->tx_headroom);
-
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- req = skb_put(skb, sizeof(struct rtllib_probe_request));
- req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
- req->header.duration_id = 0;
-
- eth_broadcast_addr(req->header.addr1);
- ether_addr_copy(req->header.addr2, ieee->dev->dev_addr);
- eth_broadcast_addr(req->header.addr3);
-
- tag = skb_put(skb, len + 2 + rate_len);
-
- *tag++ = MFIE_TYPE_SSID;
- *tag++ = len;
- memcpy(tag, ieee->current_network.ssid, len);
- tag += len;
-
- rtllib_mfie_brate(ieee, &tag);
- rtllib_mfie_grate(ieee, &tag);
-
- return skb;
-}
-
-/* Enables network monitor mode, all rx packets will be received. */
-void rtllib_enable_net_monitor_mode(struct net_device *dev,
- bool init_state)
-{
- struct rtllib_device *ieee = netdev_priv_rsl(dev);
-
- netdev_info(dev, "========>Enter Monitor Mode\n");
-
- ieee->allow_all_dest_addr_handler(dev, true, !init_state);
-}
-
-/* Disables network monitor mode. Only packets destinated to
- * us will be received.
- */
-void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state)
-{
- struct rtllib_device *ieee = netdev_priv_rsl(dev);
-
- netdev_info(dev, "========>Exit Monitor Mode\n");
-
- ieee->allow_all_dest_addr_handler(dev, false, !init_state);
-}
-
-static void rtllib_send_probe(struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
-
- skb = rtllib_probe_req(ieee);
- if (skb) {
- softmac_mgmt_xmit(skb, ieee);
- ieee->softmac_stats.tx_probe_rq++;
- }
-}
-
-static void rtllib_send_probe_requests(struct rtllib_device *ieee)
-{
- if (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ) {
- rtllib_send_probe(ieee);
- rtllib_send_probe(ieee);
- }
-}
-
-/* this performs syncro scan blocking the caller until all channels
- * in the allowed channel map has been checked.
- */
-static void rtllib_softmac_scan_syncro(struct rtllib_device *ieee)
-{
- union iwreq_data wrqu;
- short ch = 0;
-
- ieee->be_scan_inprogress = true;
-
- mutex_lock(&ieee->scan_mutex);
-
- while (1) {
- do {
- ch++;
- if (ch > MAX_CHANNEL_NUMBER)
- goto out; /* scan completed */
- } while (!ieee->active_channel_map[ch]);
-
- /* this function can be called in two situations
- * 1- We have switched to ad-hoc mode and we are
- * performing a complete syncro scan before conclude
- * there are no interesting cell and to create a
- * new one. In this case the link state is
- * MAC80211_NOLINK until we found an interesting cell.
- * If so the ieee8021_new_net, called by the RX path
- * will set the state to MAC80211_LINKED, so we stop
- * scanning
- * 2- We are linked and the root uses run iwlist scan.
- * So we switch to MAC80211_LINKED_SCANNING to remember
- * that we are still logically linked (not interested in
- * new network events, despite for updating the net list,
- * but we are temporarily 'unlinked' as the driver shall
- * not filter RX frames and the channel is changing.
- * So the only situation in which are interested is to check
- * if the state become LINKED because of the #1 situation
- */
-
- if (ieee->link_state == MAC80211_LINKED)
- goto out;
- if (ieee->sync_scan_hurryup) {
- netdev_info(ieee->dev,
- "============>sync_scan_hurryup out\n");
- goto out;
- }
-
- ieee->set_chan(ieee->dev, ch);
- if (ieee->active_channel_map[ch] == 1)
- rtllib_send_probe_requests(ieee);
-
- /* this prevent excessive time wait when we
- * need to wait for a syncro scan to end..
- */
- msleep_interruptible_rsl(RTLLIB_SOFTMAC_SCAN_TIME);
- }
-out:
- ieee->actscanning = false;
- ieee->sync_scan_hurryup = 0;
-
- mutex_unlock(&ieee->scan_mutex);
-
- ieee->be_scan_inprogress = false;
-
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(ieee->dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void rtllib_softmac_scan_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device, softmac_scan_wq);
- u8 last_channel = ieee->current_network.channel;
-
- if (!ieee->ieee_up)
- return;
- if (rtllib_act_scanning(ieee, true))
- return;
-
- mutex_lock(&ieee->scan_mutex);
-
- if (ieee->rf_power_state == rf_off) {
- netdev_info(ieee->dev,
- "======>%s():rf state is rf_off, return\n",
- __func__);
- goto out1;
- }
-
- do {
- ieee->current_network.channel =
- (ieee->current_network.channel + 1) %
- MAX_CHANNEL_NUMBER;
- if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER) {
- if (!ieee->active_channel_map[ieee->current_network.channel])
- ieee->current_network.channel = 6;
- goto out; /* no good chans */
- }
- } while (!ieee->active_channel_map[ieee->current_network.channel]);
-
- if (ieee->scanning_continue == 0)
- goto out;
-
- ieee->set_chan(ieee->dev, ieee->current_network.channel);
-
- if (ieee->active_channel_map[ieee->current_network.channel] == 1)
- rtllib_send_probe_requests(ieee);
-
- schedule_delayed_work(&ieee->softmac_scan_wq,
- msecs_to_jiffies(RTLLIB_SOFTMAC_SCAN_TIME));
-
- mutex_unlock(&ieee->scan_mutex);
- return;
-
-out:
- ieee->current_network.channel = last_channel;
-
-out1:
- ieee->actscanning = false;
- ieee->scan_watch_dog = 0;
- ieee->scanning_continue = 0;
- mutex_unlock(&ieee->scan_mutex);
-}
-
-static void rtllib_softmac_stop_scan(struct rtllib_device *ieee)
-{
- mutex_lock(&ieee->scan_mutex);
- ieee->scan_watch_dog = 0;
- if (ieee->scanning_continue == 1) {
- ieee->scanning_continue = 0;
- ieee->actscanning = false;
- mutex_unlock(&ieee->scan_mutex);
- cancel_delayed_work_sync(&ieee->softmac_scan_wq);
- } else {
- mutex_unlock(&ieee->scan_mutex);
- }
-}
-
-void rtllib_stop_scan(struct rtllib_device *ieee)
-{
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
- rtllib_softmac_stop_scan(ieee);
-}
-EXPORT_SYMBOL(rtllib_stop_scan);
-
-void rtllib_stop_scan_syncro(struct rtllib_device *ieee)
-{
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
- ieee->sync_scan_hurryup = 1;
-}
-EXPORT_SYMBOL(rtllib_stop_scan_syncro);
-
-bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan)
-{
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) {
- if (sync_scan)
- return ieee->be_scan_inprogress;
- else
- return ieee->actscanning || ieee->be_scan_inprogress;
- } else {
- return test_bit(STATUS_SCANNING, &ieee->status);
- }
-}
-EXPORT_SYMBOL(rtllib_act_scanning);
-
-/* called with ieee->lock held */
-static void rtllib_start_scan(struct rtllib_device *ieee)
-{
- ieee->rtllib_ips_leave_wq(ieee->dev);
-
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) {
- if (ieee->scanning_continue == 0) {
- ieee->actscanning = true;
- ieee->scanning_continue = 1;
- schedule_delayed_work(&ieee->softmac_scan_wq, 0);
- }
- }
-}
-
-/* called with wx_mutex held */
-void rtllib_start_scan_syncro(struct rtllib_device *ieee)
-{
- ieee->sync_scan_hurryup = 0;
- if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
- rtllib_softmac_scan_syncro(ieee);
-}
-EXPORT_SYMBOL(rtllib_start_scan_syncro);
-
-static inline struct sk_buff *
-rtllib_authentication_req(struct rtllib_network *beacon,
- struct rtllib_device *ieee,
- int challengelen, u8 *daddr)
-{
- struct sk_buff *skb;
- struct rtllib_authentication *auth;
- int len;
-
- len = sizeof(struct rtllib_authentication) + challengelen +
- ieee->tx_headroom + 4;
- skb = dev_alloc_skb(len);
-
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- auth = skb_put(skb, sizeof(struct rtllib_authentication));
-
- auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
- if (challengelen)
- auth->header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-
- auth->header.duration_id = cpu_to_le16(0x013a);
- ether_addr_copy(auth->header.addr1, beacon->bssid);
- ether_addr_copy(auth->header.addr2, ieee->dev->dev_addr);
- ether_addr_copy(auth->header.addr3, beacon->bssid);
- if (ieee->auth_mode == 0)
- auth->algorithm = WLAN_AUTH_OPEN;
- else if (ieee->auth_mode == 1)
- auth->algorithm = cpu_to_le16(WLAN_AUTH_SHARED_KEY);
- else if (ieee->auth_mode == 2)
- auth->algorithm = WLAN_AUTH_OPEN;
- auth->transaction = cpu_to_le16(ieee->associate_seq);
- ieee->associate_seq++;
-
- auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS);
-
- return skb;
-}
-
-static struct sk_buff *rtllib_null_func(struct rtllib_device *ieee, short pwr)
-{
- struct sk_buff *skb;
- struct ieee80211_hdr_3addr *hdr;
-
- skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr) + ieee->tx_headroom);
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- hdr = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
-
- ether_addr_copy(hdr->addr1, ieee->current_network.bssid);
- ether_addr_copy(hdr->addr2, ieee->dev->dev_addr);
- ether_addr_copy(hdr->addr3, ieee->current_network.bssid);
-
- hdr->frame_control = cpu_to_le16(RTLLIB_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
- (pwr ? IEEE80211_FCTL_PM : 0));
-
- return skb;
-}
-
-static struct sk_buff *rtllib_pspoll_func(struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
- struct ieee80211_pspoll *hdr;
-
- skb = dev_alloc_skb(sizeof(struct ieee80211_pspoll) + ieee->tx_headroom);
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- hdr = skb_put(skb, sizeof(struct ieee80211_pspoll));
-
- ether_addr_copy(hdr->bssid, ieee->current_network.bssid);
- ether_addr_copy(hdr->ta, ieee->dev->dev_addr);
-
- hdr->aid = cpu_to_le16(ieee->assoc_id | 0xc000);
- hdr->frame_control = cpu_to_le16(RTLLIB_FTYPE_CTL | IEEE80211_STYPE_PSPOLL |
- IEEE80211_FCTL_PM);
-
- return skb;
-}
-
-static inline int sec_is_in_pmkid_list(struct rtllib_device *ieee, u8 *bssid)
-{
- int i = 0;
-
- do {
- if ((ieee->pmkid_list[i].used) &&
- (memcmp(ieee->pmkid_list[i].bssid, bssid, ETH_ALEN) == 0))
- break;
- i++;
- } while (i < NUM_PMKID_CACHE);
-
- if (i == NUM_PMKID_CACHE)
- i = -1;
- return i;
-}
-
-static inline struct sk_buff *
-rtllib_association_req(struct rtllib_network *beacon,
- struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
- struct rtllib_assoc_request_frame *hdr;
- u8 *tag, *ies;
- int i;
- u8 *ht_cap_buf = NULL;
- u8 ht_cap_len = 0;
- u8 *realtek_ie_buf = NULL;
- u8 realtek_ie_len = 0;
- int wpa_ie_len = ieee->wpa_ie_len;
- int wps_ie_len = ieee->wps_ie_len;
- unsigned int ckip_ie_len = 0;
- unsigned int ccxrm_ie_len = 0;
- unsigned int cxvernum_ie_len = 0;
- struct lib80211_crypt_data *crypt;
- int encrypt;
- int pmk_cache_idx;
-
- unsigned int rate_len = (beacon->rates_len ?
- (beacon->rates_len + 2) : 0) +
- (beacon->rates_ex_len ? (beacon->rates_ex_len) +
- 2 : 0);
-
- unsigned int wmm_info_len = beacon->qos_data.supported ? 9 : 0;
- unsigned int turbo_info_len = beacon->turbo_enable ? 9 : 0;
-
- int len = 0;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- if (crypt)
- encrypt = crypt && crypt->ops &&
- ((strcmp(crypt->ops->name, "R-WEP") == 0 ||
- wpa_ie_len));
- else
- encrypt = 0;
-
- if ((ieee->rtllib_ap_sec_type &&
- (ieee->rtllib_ap_sec_type(ieee) & SEC_ALG_TKIP)) ||
- ieee->forced_bg_mode) {
- ieee->ht_info->enable_ht = 0;
- ieee->mode = WIRELESS_MODE_G;
- }
-
- if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- ht_cap_buf = (u8 *)&ieee->ht_info->self_ht_cap;
- ht_cap_len = sizeof(ieee->ht_info->self_ht_cap);
- ht_construct_capability_element(ieee, ht_cap_buf, &ht_cap_len,
- encrypt, true);
- if (ieee->ht_info->current_rt2rt_aggregation) {
- realtek_ie_buf = ieee->ht_info->sz_rt2rt_agg_buf;
- realtek_ie_len =
- sizeof(ieee->ht_info->sz_rt2rt_agg_buf);
- ht_construct_rt2rt_agg_element(ieee, realtek_ie_buf,
- &realtek_ie_len);
- }
- }
-
- if (beacon->ckip_supported)
- ckip_ie_len = 30 + 2;
- if (beacon->ccx_rm_enable)
- ccxrm_ie_len = 6 + 2;
- if (beacon->bss_ccx_ver_number >= 2)
- cxvernum_ie_len = 5 + 2;
-
- pmk_cache_idx = sec_is_in_pmkid_list(ieee, ieee->current_network.bssid);
- if (pmk_cache_idx >= 0) {
- wpa_ie_len += 18;
- netdev_info(ieee->dev, "[PMK cache]: WPA2 IE length: %x\n",
- wpa_ie_len);
- }
- len = sizeof(struct rtllib_assoc_request_frame) + 2
- + beacon->ssid_len
- + rate_len
- + wpa_ie_len
- + wps_ie_len
- + wmm_info_len
- + turbo_info_len
- + ht_cap_len
- + realtek_ie_len
- + ckip_ie_len
- + ccxrm_ie_len
- + cxvernum_ie_len
- + ieee->tx_headroom;
-
- skb = dev_alloc_skb(len);
-
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- hdr = skb_put(skb, sizeof(struct rtllib_assoc_request_frame) + 2);
-
- hdr->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ);
- hdr->header.duration_id = cpu_to_le16(37);
- ether_addr_copy(hdr->header.addr1, beacon->bssid);
- ether_addr_copy(hdr->header.addr2, ieee->dev->dev_addr);
- ether_addr_copy(hdr->header.addr3, beacon->bssid);
-
- ether_addr_copy(ieee->ap_mac_addr, beacon->bssid);
-
- hdr->capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
- if (beacon->capability & WLAN_CAPABILITY_PRIVACY)
- hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
-
- if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
-
- if (beacon->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
- hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- hdr->listen_interval = cpu_to_le16(beacon->listen_interval);
-
- hdr->info_element[0].id = MFIE_TYPE_SSID;
-
- hdr->info_element[0].len = beacon->ssid_len;
- skb_put_data(skb, beacon->ssid, beacon->ssid_len);
-
- tag = skb_put(skb, rate_len);
-
- if (beacon->rates_len) {
- *tag++ = MFIE_TYPE_RATES;
- *tag++ = beacon->rates_len;
- for (i = 0; i < beacon->rates_len; i++)
- *tag++ = beacon->rates[i];
- }
-
- if (beacon->rates_ex_len) {
- *tag++ = MFIE_TYPE_RATES_EX;
- *tag++ = beacon->rates_ex_len;
- for (i = 0; i < beacon->rates_ex_len; i++)
- *tag++ = beacon->rates_ex[i];
- }
-
- if (beacon->ckip_supported) {
- static const u8 aironet_ie_oui[] = {0x00, 0x01, 0x66};
- u8 ccx_aironet_buf[30];
- struct octet_string os_ccx_aironet_ie;
-
- memset(ccx_aironet_buf, 0, 30);
- os_ccx_aironet_ie.octet = ccx_aironet_buf;
- os_ccx_aironet_ie.Length = sizeof(ccx_aironet_buf);
- memcpy(os_ccx_aironet_ie.octet, aironet_ie_oui,
- sizeof(aironet_ie_oui));
-
- os_ccx_aironet_ie.octet[IE_CISCO_FLAG_POSITION] |=
- (SUPPORT_CKIP_PK | SUPPORT_CKIP_MIC);
- tag = skb_put(skb, ckip_ie_len);
- *tag++ = MFIE_TYPE_AIRONET;
- *tag++ = os_ccx_aironet_ie.Length;
- memcpy(tag, os_ccx_aironet_ie.octet, os_ccx_aironet_ie.Length);
- tag += os_ccx_aironet_ie.Length;
- }
-
- if (beacon->ccx_rm_enable) {
- static const u8 ccx_rm_cap_buf[] = {0x00, 0x40, 0x96, 0x01, 0x01,
- 0x00};
- struct octet_string os_ccx_rm_cap;
-
- os_ccx_rm_cap.octet = (u8 *)ccx_rm_cap_buf;
- os_ccx_rm_cap.Length = sizeof(ccx_rm_cap_buf);
- tag = skb_put(skb, ccxrm_ie_len);
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = os_ccx_rm_cap.Length;
- memcpy(tag, os_ccx_rm_cap.octet, os_ccx_rm_cap.Length);
- tag += os_ccx_rm_cap.Length;
- }
-
- if (beacon->bss_ccx_ver_number >= 2) {
- u8 ccx_ver_num_buf[] = {0x00, 0x40, 0x96, 0x03, 0x00};
- struct octet_string os_ccx_ver_num;
-
- ccx_ver_num_buf[4] = beacon->bss_ccx_ver_number;
- os_ccx_ver_num.octet = ccx_ver_num_buf;
- os_ccx_ver_num.Length = sizeof(ccx_ver_num_buf);
- tag = skb_put(skb, cxvernum_ie_len);
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = os_ccx_ver_num.Length;
- memcpy(tag, os_ccx_ver_num.octet, os_ccx_ver_num.Length);
- tag += os_ccx_ver_num.Length;
- }
- if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- if (ieee->ht_info->peer_ht_spec_ver != HT_SPEC_VER_EWC) {
- tag = skb_put(skb, ht_cap_len);
- *tag++ = MFIE_TYPE_HT_CAP;
- *tag++ = ht_cap_len - 2;
- memcpy(tag, ht_cap_buf, ht_cap_len - 2);
- tag += ht_cap_len - 2;
- }
- }
-
- if (wpa_ie_len) {
- skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len);
-
- if (pmk_cache_idx >= 0) {
- tag = skb_put(skb, 18);
- *tag = 1;
- *(tag + 1) = 0;
- memcpy((tag + 2), &ieee->pmkid_list[pmk_cache_idx].PMKID,
- 16);
- }
- }
- if (wmm_info_len) {
- tag = skb_put(skb, wmm_info_len);
- rtllib_wmm_info(ieee, &tag);
- }
-
- if (wps_ie_len && ieee->wps_ie)
- skb_put_data(skb, ieee->wps_ie, wps_ie_len);
-
- if (turbo_info_len) {
- tag = skb_put(skb, turbo_info_len);
- rtllib_turbo_info(ieee, &tag);
- }
-
- if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- if (ieee->ht_info->peer_ht_spec_ver == HT_SPEC_VER_EWC) {
- tag = skb_put(skb, ht_cap_len);
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = ht_cap_len - 2;
- memcpy(tag, ht_cap_buf, ht_cap_len - 2);
- tag += ht_cap_len - 2;
- }
-
- if (ieee->ht_info->current_rt2rt_aggregation) {
- tag = skb_put(skb, realtek_ie_len);
- *tag++ = MFIE_TYPE_GENERIC;
- *tag++ = realtek_ie_len - 2;
- memcpy(tag, realtek_ie_buf, realtek_ie_len - 2);
- }
- }
-
- kfree(ieee->assocreq_ies);
- ieee->assocreq_ies = NULL;
- ies = &hdr->info_element[0].id;
- ieee->assocreq_ies_len = (skb->data + skb->len) - ies;
- ieee->assocreq_ies = kmemdup(ies, ieee->assocreq_ies_len, GFP_ATOMIC);
- if (!ieee->assocreq_ies)
- ieee->assocreq_ies_len = 0;
-
- return skb;
-}
-
-static void rtllib_associate_abort(struct rtllib_device *ieee)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- ieee->associate_seq++;
-
- /* don't scan, and avoid to have the RX path possibly
- * try again to associate. Even do not react to AUTH or
- * ASSOC response. Just wait for the retry wq to be scheduled.
- * Here we will check if there are good nets to associate
- * with, so we retry or just get back to NO_LINK and scanning
- */
- if (ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATING) {
- netdev_dbg(ieee->dev, "Authentication failed\n");
- ieee->softmac_stats.no_auth_rs++;
- } else {
- netdev_dbg(ieee->dev, "Association failed\n");
- ieee->softmac_stats.no_ass_rs++;
- }
-
- ieee->link_state = RTLLIB_ASSOCIATING_RETRY;
-
- schedule_delayed_work(&ieee->associate_retry_wq,
- RTLLIB_SOFTMAC_ASSOC_RETRY_TIME);
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-static void rtllib_associate_abort_cb(struct timer_list *t)
-{
- struct rtllib_device *dev = from_timer(dev, t, associate_timer);
-
- rtllib_associate_abort(dev);
-}
-
-static void rtllib_associate_step1(struct rtllib_device *ieee, u8 *daddr)
-{
- struct rtllib_network *beacon = &ieee->current_network;
- struct sk_buff *skb;
-
- netdev_dbg(ieee->dev, "Stopping scan\n");
-
- ieee->softmac_stats.tx_auth_rq++;
-
- skb = rtllib_authentication_req(beacon, ieee, 0, daddr);
-
- if (!skb) {
- rtllib_associate_abort(ieee);
- } else {
- ieee->link_state = RTLLIB_ASSOCIATING_AUTHENTICATING;
- netdev_dbg(ieee->dev, "Sending authentication request\n");
- softmac_mgmt_xmit(skb, ieee);
- if (!timer_pending(&ieee->associate_timer)) {
- ieee->associate_timer.expires = jiffies + (HZ / 2);
- add_timer(&ieee->associate_timer);
- }
- }
-}
-
-static void rtllib_auth_challenge(struct rtllib_device *ieee, u8 *challenge,
- int chlen)
-{
- u8 *c;
- struct sk_buff *skb;
- struct rtllib_network *beacon = &ieee->current_network;
-
- ieee->associate_seq++;
- ieee->softmac_stats.tx_auth_rq++;
-
- skb = rtllib_authentication_req(beacon, ieee, chlen + 2, beacon->bssid);
-
- if (!skb) {
- rtllib_associate_abort(ieee);
- } else {
- c = skb_put(skb, chlen + 2);
- *(c++) = MFIE_TYPE_CHALLENGE;
- *(c++) = chlen;
- memcpy(c, challenge, chlen);
-
- netdev_dbg(ieee->dev,
- "Sending authentication challenge response\n");
-
- rtllib_encrypt_fragment(ieee, skb,
- sizeof(struct ieee80211_hdr_3addr));
-
- softmac_mgmt_xmit(skb, ieee);
- mod_timer(&ieee->associate_timer, jiffies + (HZ / 2));
- }
- kfree(challenge);
-}
-
-static void rtllib_associate_step2(struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
- struct rtllib_network *beacon = &ieee->current_network;
-
- del_timer_sync(&ieee->associate_timer);
-
- netdev_dbg(ieee->dev, "Sending association request\n");
-
- ieee->softmac_stats.tx_ass_rq++;
- skb = rtllib_association_req(beacon, ieee);
- if (!skb) {
- rtllib_associate_abort(ieee);
- } else {
- softmac_mgmt_xmit(skb, ieee);
- mod_timer(&ieee->associate_timer, jiffies + (HZ / 2));
- }
-}
-
-static void rtllib_associate_complete_wq(void *data)
-{
- struct rtllib_device *ieee = (struct rtllib_device *)
- container_of(data,
- struct rtllib_device,
- associate_complete_wq);
- struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl;
-
- netdev_info(ieee->dev, "Associated successfully with %pM\n",
- ieee->current_network.bssid);
- netdev_info(ieee->dev, "normal associate\n");
- notify_wx_assoc_event(ieee);
-
- netif_carrier_on(ieee->dev);
- ieee->is_roaming = false;
- if (rtllib_is_54g(&ieee->current_network)) {
- ieee->rate = 108;
- netdev_info(ieee->dev, "Using G rates:%d\n", ieee->rate);
- } else {
- ieee->rate = 22;
- ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_B);
- netdev_info(ieee->dev, "Using B rates:%d\n", ieee->rate);
- }
- if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- netdev_info(ieee->dev, "Successfully associated, ht enabled\n");
- ht_on_assoc_rsp(ieee);
- } else {
- netdev_info(ieee->dev,
- "Successfully associated, ht not enabled(%d, %d)\n",
- ieee->ht_info->current_ht_support,
- ieee->ht_info->enable_ht);
- memset(ieee->dot11ht_oper_rate_set, 0, 16);
- }
- ieee->link_detect_info.slot_num = 2 * (1 +
- ieee->current_network.beacon_interval /
- 500);
- if (ieee->link_detect_info.num_recv_bcn_in_period == 0 ||
- ieee->link_detect_info.num_recv_data_in_period == 0) {
- ieee->link_detect_info.num_recv_bcn_in_period = 1;
- ieee->link_detect_info.num_recv_data_in_period = 1;
- }
- psc->lps_idle_count = 0;
- ieee->link_change(ieee->dev);
-}
-
-static void rtllib_sta_send_associnfo(struct rtllib_device *ieee)
-{
-}
-
-static void rtllib_associate_complete(struct rtllib_device *ieee)
-{
- del_timer_sync(&ieee->associate_timer);
-
- ieee->link_state = MAC80211_LINKED;
- rtllib_sta_send_associnfo(ieee);
-
- schedule_work(&ieee->associate_complete_wq);
-}
-
-static void rtllib_associate_procedure_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device,
- associate_procedure_wq);
- rtllib_stop_scan_syncro(ieee);
- ieee->rtllib_ips_leave(ieee->dev);
- mutex_lock(&ieee->wx_mutex);
-
- rtllib_stop_scan(ieee);
- ht_set_connect_bw_mode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
- if (ieee->rf_power_state == rf_off) {
- ieee->rtllib_ips_leave_wq(ieee->dev);
- mutex_unlock(&ieee->wx_mutex);
- return;
- }
- ieee->associate_seq = 1;
-
- rtllib_associate_step1(ieee, ieee->current_network.bssid);
-
- mutex_unlock(&ieee->wx_mutex);
-}
-
-inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
- struct rtllib_network *net)
-{
- u8 tmp_ssid[IW_ESSID_MAX_SIZE + 1];
- int tmp_ssid_len = 0;
-
- short apset, ssidset, ssidbroad, apmatch, ssidmatch;
-
- /* we are interested in new only if we are not associated
- * and we are not associating / authenticating
- */
- if (ieee->link_state != MAC80211_NOLINK)
- return;
-
- if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability &
- WLAN_CAPABILITY_ESS))
- return;
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- /* if the user specified the AP MAC, we need also the essid
- * This could be obtained by beacons or, if the network does not
- * broadcast it, it can be put manually.
- */
- apset = ieee->wap_set;
- ssidset = ieee->ssid_set;
- ssidbroad = !(net->ssid_len == 0 || net->ssid[0] == '\0');
- apmatch = (memcmp(ieee->current_network.bssid, net->bssid,
- ETH_ALEN) == 0);
- if (!ssidbroad) {
- ssidmatch = (ieee->current_network.ssid_len ==
- net->hidden_ssid_len) &&
- (!strncmp(ieee->current_network.ssid,
- net->hidden_ssid, net->hidden_ssid_len));
- if (net->hidden_ssid_len > 0) {
- strncpy(net->ssid, net->hidden_ssid,
- net->hidden_ssid_len);
- net->ssid_len = net->hidden_ssid_len;
- ssidbroad = 1;
- }
- } else {
- ssidmatch =
- (ieee->current_network.ssid_len == net->ssid_len) &&
- (!strncmp(ieee->current_network.ssid, net->ssid,
- net->ssid_len));
- }
-
- /* if the user set the AP check if match.
- * if the network does not broadcast essid we check the
- * user supplied ANY essid
- * if the network does broadcast and the user does not set
- * essid it is OK
- * if the network does broadcast and the user did set essid
- * check if essid match
- * if the ap is not set, check that the user set the bssid
- * and the network does broadcast and that those two bssid match
- */
- if ((apset && apmatch &&
- ((ssidset && ssidbroad && ssidmatch) ||
- (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) ||
- (!apset && ssidset && ssidbroad && ssidmatch) ||
- (ieee->is_roaming && ssidset && ssidbroad && ssidmatch)) {
- /* Save the essid so that if it is hidden, it is
- * replaced with the essid provided by the user.
- */
- if (!ssidbroad) {
- memcpy(tmp_ssid, ieee->current_network.ssid,
- ieee->current_network.ssid_len);
- tmp_ssid_len = ieee->current_network.ssid_len;
- }
- memcpy(&ieee->current_network, net,
- sizeof(ieee->current_network));
- if (!ssidbroad) {
- memcpy(ieee->current_network.ssid, tmp_ssid,
- tmp_ssid_len);
- ieee->current_network.ssid_len = tmp_ssid_len;
- }
- netdev_info(ieee->dev,
- "Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x cur_net.flags:0x%x\n",
- ieee->current_network.ssid,
- ieee->current_network.channel,
- ieee->current_network.qos_data.supported,
- ieee->ht_info->enable_ht,
- ieee->current_network.bssht.bd_support_ht,
- ieee->current_network.mode,
- ieee->current_network.flags);
-
- if ((rtllib_act_scanning(ieee, false)) &&
- !(ieee->softmac_features & IEEE_SOFTMAC_SCAN))
- rtllib_stop_scan_syncro(ieee);
-
- ht_reset_iot_setting(ieee->ht_info);
- ieee->wmm_acm = 0;
- if (ieee->iw_mode == IW_MODE_INFRA) {
- /* Join the network for the first time */
- ieee->asoc_retry_count = 0;
- if ((ieee->current_network.qos_data.supported == 1) &&
- ieee->current_network.bssht.bd_support_ht)
- ht_reset_self_and_save_peer_setting(ieee,
- &ieee->current_network);
- else
- ieee->ht_info->current_ht_support = false;
-
- ieee->link_state = RTLLIB_ASSOCIATING;
- schedule_delayed_work(&ieee->associate_procedure_wq, 0);
- } else {
- if (rtllib_is_54g(&ieee->current_network)) {
- ieee->rate = 108;
- ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_G);
- netdev_info(ieee->dev,
- "Using G rates\n");
- } else {
- ieee->rate = 22;
- ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_B);
- netdev_info(ieee->dev,
- "Using B rates\n");
- }
- memset(ieee->dot11ht_oper_rate_set, 0, 16);
- ieee->link_state = MAC80211_LINKED;
- }
- }
- }
-}
-
-static void rtllib_softmac_check_all_nets(struct rtllib_device *ieee)
-{
- unsigned long flags;
- struct rtllib_network *target;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(target, &ieee->network_list, list) {
- /* if the state become different that NOLINK means
- * we had found what we are searching for
- */
-
- if (ieee->link_state != MAC80211_NOLINK)
- break;
-
- if (ieee->scan_age == 0 || time_after(target->last_scanned +
- ieee->scan_age, jiffies))
- rtllib_softmac_new_net(ieee, target);
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-static inline int auth_parse(struct net_device *dev, struct sk_buff *skb,
- u8 **challenge, int *chlen)
-{
- struct rtllib_authentication *a;
- u8 *t;
-
- if (skb->len < (sizeof(struct rtllib_authentication) -
- sizeof(struct rtllib_info_element))) {
- netdev_dbg(dev, "invalid len in auth resp: %d\n", skb->len);
- return -EINVAL;
- }
- *challenge = NULL;
- a = (struct rtllib_authentication *)skb->data;
- if (skb->len > (sizeof(struct rtllib_authentication) + 3)) {
- t = skb->data + sizeof(struct rtllib_authentication);
-
- if (*(t++) == MFIE_TYPE_CHALLENGE) {
- *chlen = *(t++);
- *challenge = kmemdup(t, *chlen, GFP_ATOMIC);
- if (!*challenge)
- return -ENOMEM;
- }
- }
-
- if (a->status) {
- netdev_dbg(dev, "auth_parse() failed\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static inline u16 assoc_parse(struct rtllib_device *ieee, struct sk_buff *skb,
- int *aid)
-{
- struct rtllib_assoc_response_frame *response_head;
- u16 status_code;
-
- if (skb->len < sizeof(struct rtllib_assoc_response_frame)) {
- netdev_dbg(ieee->dev, "Invalid len in auth resp: %d\n",
- skb->len);
- return 0xcafe;
- }
-
- response_head = (struct rtllib_assoc_response_frame *)skb->data;
- *aid = le16_to_cpu(response_head->aid) & 0x3fff;
-
- status_code = le16_to_cpu(response_head->status);
- if ((status_code == WLAN_STATUS_ASSOC_DENIED_RATES ||
- status_code == WLAN_STATUS_CAPS_UNSUPPORTED) &&
- ((ieee->mode == WIRELESS_MODE_G) &&
- (ieee->current_network.mode == WIRELESS_MODE_N_24G) &&
- (ieee->asoc_retry_count++ < (RT_ASOC_RETRY_LIMIT - 1)))) {
- ieee->ht_info->iot_action |= HT_IOT_ACT_PURE_N_MODE;
- } else {
- ieee->asoc_retry_count = 0;
- }
-
- return le16_to_cpu(response_head->status);
-}
-
-void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr)
-{
- struct sk_buff *buf = rtllib_null_func(ieee, pwr);
-
- if (buf)
- softmac_ps_mgmt_xmit(buf, ieee);
-}
-EXPORT_SYMBOL(rtllib_sta_ps_send_null_frame);
-
-void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee)
-{
- struct sk_buff *buf = rtllib_pspoll_func(ieee);
-
- if (buf)
- softmac_ps_mgmt_xmit(buf, ieee);
-}
-
-static short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u64 *time)
-{
- int timeout;
- u8 dtim;
- struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl;
-
- if (ieee->lps_delay_cnt) {
- ieee->lps_delay_cnt--;
- return 0;
- }
-
- dtim = ieee->current_network.dtim_data;
- if (!(dtim & RTLLIB_DTIM_VALID))
- return 0;
- timeout = ieee->current_network.beacon_interval;
- ieee->current_network.dtim_data = RTLLIB_DTIM_INVALID;
- /* there's no need to notify AP that I find you buffered
- * with broadcast packet
- */
- if (dtim & (RTLLIB_DTIM_UCAST & ieee->ps))
- return 2;
-
- if (!time_after(jiffies,
- dev_trans_start(ieee->dev) + msecs_to_jiffies(timeout)))
- return 0;
- if (!time_after(jiffies,
- ieee->last_rx_ps_time + msecs_to_jiffies(timeout)))
- return 0;
- if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) &&
- (ieee->mgmt_queue_tail != ieee->mgmt_queue_head))
- return 0;
-
- if (time) {
- if (ieee->awake_pkt_sent) {
- psc->lps_awake_intvl = 1;
- } else {
- u8 max_period = 5;
-
- if (psc->lps_awake_intvl == 0)
- psc->lps_awake_intvl = 1;
- psc->lps_awake_intvl = (psc->lps_awake_intvl >=
- max_period) ? max_period :
- (psc->lps_awake_intvl + 1);
- }
- {
- u8 lps_awake_intvl_tmp = 0;
- u8 period = ieee->current_network.dtim_period;
- u8 count = ieee->current_network.tim.tim_count;
-
- if (count == 0) {
- if (psc->lps_awake_intvl > period)
- lps_awake_intvl_tmp = period +
- (psc->lps_awake_intvl -
- period) -
- ((psc->lps_awake_intvl - period) %
- period);
- else
- lps_awake_intvl_tmp = psc->lps_awake_intvl;
-
- } else {
- if (psc->lps_awake_intvl >
- ieee->current_network.tim.tim_count)
- lps_awake_intvl_tmp = count +
- (psc->lps_awake_intvl - count) -
- ((psc->lps_awake_intvl - count) % period);
- else
- lps_awake_intvl_tmp = psc->lps_awake_intvl;
- }
-
- *time = ieee->current_network.last_dtim_sta_time
- + msecs_to_jiffies(ieee->current_network.beacon_interval *
- lps_awake_intvl_tmp);
- }
- }
-
- return 1;
-}
-
-static inline void rtllib_sta_ps(struct work_struct *work)
-{
- struct rtllib_device *ieee;
- u64 time;
- short sleep;
- unsigned long flags, flags2;
-
- ieee = container_of(work, struct rtllib_device, ps_task);
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- if ((ieee->ps == RTLLIB_PS_DISABLED ||
- ieee->iw_mode != IW_MODE_INFRA ||
- ieee->link_state != MAC80211_LINKED)) {
- spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
- rtllib_sta_wakeup(ieee, 1);
-
- spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
- }
- sleep = rtllib_sta_ps_sleep(ieee, &time);
- /* 2 wake, 1 sleep, 0 do nothing */
- if (sleep == 0)
- goto out;
- if (sleep == 1) {
- if (ieee->sta_sleep == LPS_IS_SLEEP) {
- ieee->enter_sleep_state(ieee->dev, time);
- } else if (ieee->sta_sleep == LPS_IS_WAKE) {
- spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
-
- if (ieee->ps_is_queue_empty(ieee->dev)) {
- ieee->sta_sleep = LPS_WAIT_NULL_DATA_SEND;
- ieee->ack_tx_to_ieee = 1;
- rtllib_sta_ps_send_null_frame(ieee, 1);
- ieee->ps_time = time;
- }
- spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
- }
-
- ieee->awake_pkt_sent = false;
-
- } else if (sleep == 2) {
- spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
-
- rtllib_sta_wakeup(ieee, 1);
-
- spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
- }
-
-out:
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl)
-{
- if (ieee->sta_sleep == LPS_IS_WAKE) {
- if (nl) {
- if (ieee->ht_info->iot_action &
- HT_IOT_ACT_NULL_DATA_POWER_SAVING) {
- ieee->ack_tx_to_ieee = 1;
- rtllib_sta_ps_send_null_frame(ieee, 0);
- } else {
- ieee->ack_tx_to_ieee = 1;
- rtllib_sta_ps_send_pspoll_frame(ieee);
- }
- }
- return;
- }
-
- if (ieee->sta_sleep == LPS_IS_SLEEP)
- ieee->sta_wake_up(ieee->dev);
- if (nl) {
- if (ieee->ht_info->iot_action &
- HT_IOT_ACT_NULL_DATA_POWER_SAVING) {
- ieee->ack_tx_to_ieee = 1;
- rtllib_sta_ps_send_null_frame(ieee, 0);
- } else {
- ieee->ack_tx_to_ieee = 1;
- ieee->polling = true;
- rtllib_sta_ps_send_pspoll_frame(ieee);
- }
-
- } else {
- ieee->sta_sleep = LPS_IS_WAKE;
- ieee->polling = false;
- }
-}
-
-void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success)
-{
- unsigned long flags, flags2;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (ieee->sta_sleep == LPS_WAIT_NULL_DATA_SEND) {
- /* Null frame with PS bit set */
- if (success) {
- ieee->sta_sleep = LPS_IS_SLEEP;
- ieee->enter_sleep_state(ieee->dev, ieee->ps_time);
- }
- /* if the card report not success we can't be sure the AP
- * has not RXed so we can't assume the AP believe us awake
- */
- } else {/* 21112005 - tx again null without PS bit if lost */
-
- if ((ieee->sta_sleep == LPS_IS_WAKE) && !success) {
- spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
- if (ieee->ht_info->iot_action &
- HT_IOT_ACT_NULL_DATA_POWER_SAVING)
- rtllib_sta_ps_send_null_frame(ieee, 0);
- else
- rtllib_sta_ps_send_pspoll_frame(ieee);
- spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
- }
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-EXPORT_SYMBOL(rtllib_ps_tx_ack);
-
-static void rtllib_process_action(struct rtllib_device *ieee,
- struct sk_buff *skb)
-{
- u8 *act = skb->data + RTLLIB_3ADDR_LEN;
- u8 category = 0;
-
- category = *act;
- act++;
- switch (category) {
- case ACT_CAT_BA:
- switch (*act) {
- case ACT_ADDBAREQ:
- rtllib_rx_add_ba_req(ieee, skb);
- break;
- case ACT_ADDBARSP:
- rtllib_rx_add_ba_rsp(ieee, skb);
- break;
- case ACT_DELBA:
- rtllib_rx_DELBA(ieee, skb);
- break;
- }
- break;
- default:
- break;
- }
-}
-
-static inline int
-rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- u16 errcode;
- int aid;
- u8 *ies;
- struct rtllib_assoc_response_frame *assoc_resp;
- struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data;
- u16 frame_ctl = le16_to_cpu(header->frame_control);
-
- netdev_dbg(ieee->dev, "received [RE]ASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(frame_ctl));
-
- if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
- ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATED &&
- (ieee->iw_mode == IW_MODE_INFRA)) {
- errcode = assoc_parse(ieee, skb, &aid);
- if (!errcode) {
- struct rtllib_network *network =
- kzalloc(sizeof(struct rtllib_network),
- GFP_ATOMIC);
-
- if (!network)
- return 1;
- ieee->link_state = MAC80211_LINKED;
- ieee->assoc_id = aid;
- ieee->softmac_stats.rx_ass_ok++;
- /* station support qos */
- /* Let the register setting default with Legacy station */
- assoc_resp = (struct rtllib_assoc_response_frame *)skb->data;
- if (ieee->current_network.qos_data.supported == 1) {
- if (rtllib_parse_info_param(ieee, assoc_resp->info_element,
- rx_stats->len - sizeof(*assoc_resp),
- network, rx_stats)) {
- kfree(network);
- return 1;
- }
- memcpy(ieee->ht_info->peer_ht_cap_buf,
- network->bssht.bd_ht_cap_buf,
- network->bssht.bd_ht_cap_len);
- memcpy(ieee->ht_info->peer_ht_info_buf,
- network->bssht.bd_ht_info_buf,
- network->bssht.bd_ht_info_len);
- ieee->handle_assoc_response(ieee->dev,
- (struct rtllib_assoc_response_frame *)header, network);
- }
- kfree(network);
-
- kfree(ieee->assocresp_ies);
- ieee->assocresp_ies = NULL;
- ies = &assoc_resp->info_element[0].id;
- ieee->assocresp_ies_len = (skb->data + skb->len) - ies;
- ieee->assocresp_ies = kmemdup(ies,
- ieee->assocresp_ies_len,
- GFP_ATOMIC);
- if (!ieee->assocresp_ies)
- ieee->assocresp_ies_len = 0;
-
- rtllib_associate_complete(ieee);
- } else {
- /* aid could not been allocated */
- ieee->softmac_stats.rx_ass_err++;
- netdev_info(ieee->dev,
- "Association response status code 0x%x\n",
- errcode);
- if (ieee->asoc_retry_count < RT_ASOC_RETRY_LIMIT)
- schedule_delayed_work(&ieee->associate_procedure_wq, 0);
- else
- rtllib_associate_abort(ieee);
- }
- }
- return 0;
-}
-
-static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- int errcode;
- u8 *challenge;
- int chlen = 0;
- bool support_nmode = true, half_support_nmode = false;
-
- errcode = auth_parse(ieee->dev, skb, &challenge, &chlen);
-
- if (errcode) {
- ieee->softmac_stats.rx_auth_rs_err++;
- netdev_info(ieee->dev,
- "Authentication response status code %d", errcode);
- rtllib_associate_abort(ieee);
- return;
- }
-
- if (ieee->open_wep || !challenge) {
- ieee->link_state = RTLLIB_ASSOCIATING_AUTHENTICATED;
- ieee->softmac_stats.rx_auth_rs_ok++;
- if (!(ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE)) {
- if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev)) {
- if (is_ht_half_nmode_aps(ieee)) {
- support_nmode = true;
- half_support_nmode = true;
- } else {
- support_nmode = false;
- half_support_nmode = false;
- }
- }
- }
- /* Dummy wirless mode setting to avoid encryption issue */
- if (support_nmode) {
- ieee->set_wireless_mode(ieee->dev,
- ieee->current_network.mode);
- } else {
- /*TODO*/
- ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_G);
- }
-
- if ((ieee->current_network.mode == WIRELESS_MODE_N_24G) &&
- half_support_nmode) {
- netdev_info(ieee->dev, "======>enter half N mode\n");
- ieee->half_wireless_n24g_mode = true;
- } else {
- ieee->half_wireless_n24g_mode = false;
- }
- rtllib_associate_step2(ieee);
- } else {
- rtllib_auth_challenge(ieee, challenge, chlen);
- }
-}
-
-static inline int
-rtllib_rx_auth(struct rtllib_device *ieee, struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats)
-{
- if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) {
- if (ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATING &&
- (ieee->iw_mode == IW_MODE_INFRA)) {
- netdev_dbg(ieee->dev,
- "Received authentication response");
- rtllib_rx_auth_resp(ieee, skb);
- }
- }
- return 0;
-}
-
-static inline int
-rtllib_rx_deauth(struct rtllib_device *ieee, struct sk_buff *skb)
-{
- struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data;
- u16 frame_ctl;
-
- if (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0)
- return 0;
-
- /* FIXME for now repeat all the association procedure
- * both for disassociation and deauthentication
- */
- if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
- ieee->link_state == MAC80211_LINKED &&
- (ieee->iw_mode == IW_MODE_INFRA)) {
- frame_ctl = le16_to_cpu(header->frame_control);
- netdev_info(ieee->dev,
- "==========>received disassoc/deauth(%x) frame, reason code:%x\n",
- WLAN_FC_GET_STYPE(frame_ctl),
- ((struct rtllib_disassoc *)skb->data)->reason);
- ieee->link_state = RTLLIB_ASSOCIATING;
- ieee->softmac_stats.reassoc++;
- ieee->is_roaming = true;
- ieee->link_detect_info.busy_traffic = false;
- rtllib_disassociate(ieee);
- remove_peer_ts(ieee, header->addr2);
- if (!(ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_CCMP | SEC_ALG_TKIP)))
- schedule_delayed_work(&ieee->associate_procedure_wq, 5);
- }
- return 0;
-}
-
-inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee,
- struct sk_buff *skb,
- struct rtllib_rx_stats *rx_stats, u16 type,
- u16 stype)
-{
- struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data;
- u16 frame_ctl;
-
- if (!ieee->proto_started)
- return 0;
-
- frame_ctl = le16_to_cpu(header->frame_control);
- switch (WLAN_FC_GET_STYPE(frame_ctl)) {
- case IEEE80211_STYPE_ASSOC_RESP:
- case IEEE80211_STYPE_REASSOC_RESP:
- if (rtllib_rx_assoc_resp(ieee, skb, rx_stats) == 1)
- return 1;
- break;
- case IEEE80211_STYPE_ASSOC_REQ:
- case IEEE80211_STYPE_REASSOC_REQ:
- break;
- case IEEE80211_STYPE_AUTH:
- rtllib_rx_auth(ieee, skb, rx_stats);
- break;
- case IEEE80211_STYPE_DISASSOC:
- case IEEE80211_STYPE_DEAUTH:
- rtllib_rx_deauth(ieee, skb);
- break;
- case IEEE80211_STYPE_ACTION:
- rtllib_process_action(ieee, skb);
- break;
- default:
- return -1;
- }
- return 0;
-}
-
-/* following are for a simpler TX queue management.
- * Instead of using netif_[stop/wake]_queue the driver
- * will use these two functions (plus a reset one), that
- * will internally use the kernel netif_* and takes
- * care of the ieee802.11 fragmentation.
- * So the driver receives a fragment per time and might
- * call the stop function when it wants to not
- * have enough room to TX an entire packet.
- * This might be useful if each fragment needs it's own
- * descriptor, thus just keep a total free memory > than
- * the max fragmentation threshold is not enough.. If the
- * ieee802.11 stack passed a TXB struct then you need
- * to keep N free descriptors where
- * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
- * In this way you need just one and the 802.11 stack
- * will take care of buffering fragments and pass them to
- * the driver later, when it wakes the queue.
- */
-void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee)
-{
- unsigned int queue_index = txb->queue_index;
- unsigned long flags;
- int i;
- struct cb_desc *tcb_desc = NULL;
- unsigned long queue_len = 0;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* called with 2nd param 0, no tx mgmt lock required */
- rtllib_sta_wakeup(ieee, 0);
-
- /* update the tx status */
- tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb +
- MAX_DEV_ADDR_SIZE);
- if (tcb_desc->multicast)
- ieee->stats.multicast++;
-
- /* if xmit available, just xmit it immediately, else just insert it to
- * the wait queue
- */
- for (i = 0; i < txb->nr_frags; i++) {
- queue_len = skb_queue_len(&ieee->skb_waitq[queue_index]);
- if ((queue_len != 0) ||
- (!ieee->check_nic_enough_desc(ieee->dev, queue_index)) ||
- (ieee->queue_stop)) {
- /* insert the skb packet to the wait queue
- * as for the completion function, it does not need
- * to check it any more.
- */
- if (queue_len < 200)
- skb_queue_tail(&ieee->skb_waitq[queue_index],
- txb->fragments[i]);
- else
- kfree_skb(txb->fragments[i]);
- } else {
- ieee->softmac_data_hard_start_xmit(txb->fragments[i],
- ieee->dev, ieee->rate);
- }
- }
-
- rtllib_txb_free(txb);
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-void rtllib_reset_queue(struct rtllib_device *ieee)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ieee->lock, flags);
- init_mgmt_queue(ieee);
- if (ieee->tx_pending.txb) {
- rtllib_txb_free(ieee->tx_pending.txb);
- ieee->tx_pending.txb = NULL;
- }
- ieee->queue_stop = 0;
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-EXPORT_SYMBOL(rtllib_reset_queue);
-
-void rtllib_stop_all_queues(struct rtllib_device *ieee)
-{
- unsigned int i;
-
- for (i = 0; i < ieee->dev->num_tx_queues; i++)
- txq_trans_cond_update(netdev_get_tx_queue(ieee->dev, i));
-
- netif_tx_stop_all_queues(ieee->dev);
-}
-
-void rtllib_wake_all_queues(struct rtllib_device *ieee)
-{
- netif_tx_wake_all_queues(ieee->dev);
-}
-
-/* this is called only in user context, with wx_mutex held */
-static void rtllib_start_bss(struct rtllib_device *ieee)
-{
- unsigned long flags;
-
- /* check if we have already found the net we
- * are interested in (if any).
- * if not (we are disassociated and we are not
- * in associating / authenticating phase) start the background scanning.
- */
- rtllib_softmac_check_all_nets(ieee);
-
- /* ensure no-one start an associating process (thus setting
- * the ieee->link_state to rtllib_ASSOCIATING) while we
- * have just checked it and we are going to enable scan.
- * The rtllib_new_net function is always called with
- * lock held (from both rtllib_softmac_check_all_nets and
- * the rx path), so we cannot be in the middle of such function
- */
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (ieee->link_state == MAC80211_NOLINK)
- rtllib_start_scan(ieee);
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-
-static void rtllib_link_change_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device, link_change_wq);
- ieee->link_change(ieee->dev);
-}
-
-/* called only in userspace context */
-void rtllib_disassociate(struct rtllib_device *ieee)
-{
- netif_carrier_off(ieee->dev);
- if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)
- rtllib_reset_queue(ieee);
-
- ieee->link_state = MAC80211_NOLINK;
- ieee->is_set_key = false;
- ieee->wap_set = 0;
-
- schedule_delayed_work(&ieee->link_change_wq, 0);
-
- notify_wx_assoc_event(ieee);
-}
-
-static void rtllib_associate_retry_wq(void *data)
-{
- struct rtllib_device *ieee = container_of_dwork_rsl(data,
- struct rtllib_device, associate_retry_wq);
- unsigned long flags;
-
- mutex_lock(&ieee->wx_mutex);
- if (!ieee->proto_started)
- goto exit;
-
- if (ieee->link_state != RTLLIB_ASSOCIATING_RETRY)
- goto exit;
-
- /* until we do not set the state to MAC80211_NOLINK
- * there are no possibility to have someone else trying
- * to start an association procedure (we get here with
- * ieee->link_state = RTLLIB_ASSOCIATING).
- * When we set the state to MAC80211_NOLINK it is possible
- * that the RX path run an attempt to associate, but
- * both rtllib_softmac_check_all_nets and the
- * RX path works with ieee->lock held so there are no
- * problems. If we are still disassociated then start a scan.
- * the lock here is necessary to ensure no one try to start
- * an association procedure when we have just checked the
- * state and we are going to start the scan.
- */
- ieee->beinretry = true;
- ieee->link_state = MAC80211_NOLINK;
-
- rtllib_softmac_check_all_nets(ieee);
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (ieee->link_state == MAC80211_NOLINK)
- rtllib_start_scan(ieee);
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- ieee->beinretry = false;
-exit:
- mutex_unlock(&ieee->wx_mutex);
-}
-
-void rtllib_softmac_stop_protocol(struct rtllib_device *ieee)
-{
- rtllib_stop_scan_syncro(ieee);
- mutex_lock(&ieee->wx_mutex);
- rtllib_stop_protocol(ieee);
- mutex_unlock(&ieee->wx_mutex);
-}
-EXPORT_SYMBOL(rtllib_softmac_stop_protocol);
-
-void rtllib_stop_protocol(struct rtllib_device *ieee)
-{
- if (!ieee->proto_started)
- return;
-
- ieee->proto_started = 0;
- ieee->proto_stoppping = 1;
- ieee->rtllib_ips_leave(ieee->dev);
-
- del_timer_sync(&ieee->associate_timer);
- mutex_unlock(&ieee->wx_mutex);
- cancel_delayed_work_sync(&ieee->associate_retry_wq);
- mutex_lock(&ieee->wx_mutex);
- cancel_delayed_work_sync(&ieee->link_change_wq);
- rtllib_stop_scan(ieee);
-
- if (ieee->link_state <= RTLLIB_ASSOCIATING_AUTHENTICATED)
- ieee->link_state = MAC80211_NOLINK;
-
- if (ieee->link_state == MAC80211_LINKED) {
- if (ieee->iw_mode == IW_MODE_INFRA)
- send_disassociation(ieee, 1, WLAN_REASON_DEAUTH_LEAVING);
- rtllib_disassociate(ieee);
- }
-
- remove_all_ts(ieee);
- ieee->proto_stoppping = 0;
-
- kfree(ieee->assocreq_ies);
- ieee->assocreq_ies = NULL;
- ieee->assocreq_ies_len = 0;
- kfree(ieee->assocresp_ies);
- ieee->assocresp_ies = NULL;
- ieee->assocresp_ies_len = 0;
-}
-
-void rtllib_softmac_start_protocol(struct rtllib_device *ieee)
-{
- mutex_lock(&ieee->wx_mutex);
- rtllib_start_protocol(ieee);
- mutex_unlock(&ieee->wx_mutex);
-}
-EXPORT_SYMBOL(rtllib_softmac_start_protocol);
-
-void rtllib_start_protocol(struct rtllib_device *ieee)
-{
- short ch = 0;
- int i = 0;
-
- if (ieee->proto_started)
- return;
-
- ieee->proto_started = 1;
-
- if (ieee->current_network.channel == 0) {
- do {
- ch++;
- if (ch > MAX_CHANNEL_NUMBER)
- return; /* no channel found */
- } while (!ieee->active_channel_map[ch]);
- ieee->current_network.channel = ch;
- }
-
- if (ieee->current_network.beacon_interval == 0)
- ieee->current_network.beacon_interval = 100;
-
- for (i = 0; i < 17; i++) {
- ieee->last_rxseq_num[i] = -1;
- ieee->last_rxfrag_num[i] = -1;
- ieee->last_packet_time[i] = 0;
- }
-
- ieee->wmm_acm = 0;
- /* if the user set the MAC of the ad-hoc cell and then
- * switch to managed mode, shall we make sure that association
- * attempts does not fail just because the user provide the essid
- * and the nic is still checking for the AP MAC ??
- */
- switch (ieee->iw_mode) {
- case IW_MODE_INFRA:
- rtllib_start_bss(ieee);
- break;
- }
-}
-
-int rtllib_softmac_init(struct rtllib_device *ieee)
-{
- int i;
-
- memset(&ieee->current_network, 0, sizeof(struct rtllib_network));
-
- ieee->link_state = MAC80211_NOLINK;
- for (i = 0; i < 5; i++)
- ieee->seq_ctrl[i] = 0;
-
- ieee->link_detect_info.slot_index = 0;
- ieee->link_detect_info.slot_num = 2;
- ieee->link_detect_info.num_recv_bcn_in_period = 0;
- ieee->link_detect_info.num_recv_data_in_period = 0;
- ieee->link_detect_info.num_tx_ok_in_period = 0;
- ieee->link_detect_info.num_rx_ok_in_period = 0;
- ieee->link_detect_info.num_rx_unicast_ok_in_period = 0;
- ieee->is_aggregate_frame = false;
- ieee->assoc_id = 0;
- ieee->queue_stop = 0;
- ieee->scanning_continue = 0;
- ieee->softmac_features = 0;
- ieee->wap_set = 0;
- ieee->ssid_set = 0;
- ieee->proto_started = 0;
- ieee->proto_stoppping = 0;
- ieee->basic_rate = RTLLIB_DEFAULT_BASIC_RATE;
- ieee->rate = 22;
- ieee->ps = RTLLIB_PS_DISABLED;
- ieee->sta_sleep = LPS_IS_WAKE;
-
- ieee->reg_dot11ht_oper_rate_set[0] = 0xff;
- ieee->reg_dot11ht_oper_rate_set[1] = 0xff;
- ieee->reg_dot11ht_oper_rate_set[4] = 0x01;
-
- ieee->reg_dot11tx_ht_oper_rate_set[0] = 0xff;
- ieee->reg_dot11tx_ht_oper_rate_set[1] = 0xff;
- ieee->reg_dot11tx_ht_oper_rate_set[4] = 0x01;
-
- ieee->first_ie_in_scan = false;
- ieee->actscanning = false;
- ieee->beinretry = false;
- ieee->is_set_key = false;
- init_mgmt_queue(ieee);
-
- ieee->tx_pending.txb = NULL;
-
- timer_setup(&ieee->associate_timer, rtllib_associate_abort_cb, 0);
-
- INIT_DELAYED_WORK(&ieee->link_change_wq, (void *)rtllib_link_change_wq);
- INIT_WORK(&ieee->associate_complete_wq, (void *)rtllib_associate_complete_wq);
- INIT_DELAYED_WORK(&ieee->associate_procedure_wq, (void *)rtllib_associate_procedure_wq);
- INIT_DELAYED_WORK(&ieee->softmac_scan_wq, (void *)rtllib_softmac_scan_wq);
- INIT_DELAYED_WORK(&ieee->associate_retry_wq, (void *)rtllib_associate_retry_wq);
- INIT_WORK(&ieee->wx_sync_scan_wq, (void *)rtllib_wx_sync_scan_wq);
-
- mutex_init(&ieee->wx_mutex);
- mutex_init(&ieee->scan_mutex);
- mutex_init(&ieee->ips_mutex);
-
- spin_lock_init(&ieee->mgmt_tx_lock);
- spin_lock_init(&ieee->beacon_lock);
-
- INIT_WORK(&ieee->ps_task, rtllib_sta_ps);
-
- return 0;
-}
-
-void rtllib_softmac_free(struct rtllib_device *ieee)
-{
- del_timer_sync(&ieee->associate_timer);
-
- cancel_delayed_work_sync(&ieee->associate_retry_wq);
- cancel_delayed_work_sync(&ieee->associate_procedure_wq);
- cancel_delayed_work_sync(&ieee->softmac_scan_wq);
- cancel_delayed_work_sync(&ieee->hw_wakeup_wq);
- cancel_delayed_work_sync(&ieee->hw_sleep_wq);
- cancel_delayed_work_sync(&ieee->link_change_wq);
- cancel_work_sync(&ieee->associate_complete_wq);
- cancel_work_sync(&ieee->ips_leave_wq);
- cancel_work_sync(&ieee->wx_sync_scan_wq);
- cancel_work_sync(&ieee->ps_task);
-}
-
-static inline struct sk_buff *
-rtllib_disauth_skb(struct rtllib_network *beacon,
- struct rtllib_device *ieee, u16 rsn)
-{
- struct sk_buff *skb;
- struct rtllib_disauth *disauth;
- int len = sizeof(struct rtllib_disauth) + ieee->tx_headroom;
-
- skb = dev_alloc_skb(len);
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- disauth = skb_put(skb, sizeof(struct rtllib_disauth));
- disauth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DEAUTH);
- disauth->header.duration_id = 0;
-
- ether_addr_copy(disauth->header.addr1, beacon->bssid);
- ether_addr_copy(disauth->header.addr2, ieee->dev->dev_addr);
- ether_addr_copy(disauth->header.addr3, beacon->bssid);
-
- disauth->reason = cpu_to_le16(rsn);
- return skb;
-}
-
-static inline struct sk_buff *
-rtllib_disassociate_skb(struct rtllib_network *beacon,
- struct rtllib_device *ieee, u16 rsn)
-{
- struct sk_buff *skb;
- struct rtllib_disassoc *disass;
- int len = sizeof(struct rtllib_disassoc) + ieee->tx_headroom;
-
- skb = dev_alloc_skb(len);
-
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- disass = skb_put(skb, sizeof(struct rtllib_disassoc));
- disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
- disass->header.duration_id = 0;
-
- ether_addr_copy(disass->header.addr1, beacon->bssid);
- ether_addr_copy(disass->header.addr2, ieee->dev->dev_addr);
- ether_addr_copy(disass->header.addr3, beacon->bssid);
-
- disass->reason = cpu_to_le16(rsn);
- return skb;
-}
-
-void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn)
-{
- struct rtllib_network *beacon = &ieee->current_network;
- struct sk_buff *skb;
-
- if (deauth)
- skb = rtllib_disauth_skb(beacon, ieee, rsn);
- else
- skb = rtllib_disassociate_skb(beacon, ieee, rsn);
-
- if (skb)
- softmac_mgmt_xmit(skb, ieee);
-}
-
-u8 rtllib_ap_sec_type(struct rtllib_device *ieee)
-{
- static u8 ccmp_ie[4] = {0x00, 0x50, 0xf2, 0x04};
- static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04};
- int wpa_ie_len = ieee->wpa_ie_len;
- struct lib80211_crypt_data *crypt;
- int encrypt;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY)
- || (crypt && crypt->ops && (strcmp(crypt->ops->name, "R-WEP") == 0));
-
- /* simply judge */
- if (encrypt && (wpa_ie_len == 0)) {
- return SEC_ALG_WEP;
- } else if ((wpa_ie_len != 0)) {
- if (((ieee->wpa_ie[0] == 0xdd) &&
- (!memcmp(&ieee->wpa_ie[14], ccmp_ie, 4))) ||
- ((ieee->wpa_ie[0] == 0x30) &&
- (!memcmp(&ieee->wpa_ie[10], ccmp_rsn_ie, 4))))
- return SEC_ALG_CCMP;
- else
- return SEC_ALG_TKIP;
- } else {
- return SEC_ALG_NONE;
- }
-}
-
-static void rtllib_mlme_disassociate_request(struct rtllib_device *rtllib,
- u8 *addr, u8 rsn)
-{
- u8 i;
- u8 op_mode;
-
- remove_peer_ts(rtllib, addr);
-
- if (memcmp(rtllib->current_network.bssid, addr, 6) == 0) {
- rtllib->link_state = MAC80211_NOLINK;
-
- for (i = 0; i < 6; i++)
- rtllib->current_network.bssid[i] = 0x22;
- op_mode = RT_OP_MODE_NO_LINK;
- rtllib->op_mode = RT_OP_MODE_NO_LINK;
- rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_MEDIA_STATUS,
- (u8 *)(&op_mode));
- rtllib_disassociate(rtllib);
-
- rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_BSSID,
- rtllib->current_network.bssid);
- }
-}
-
-static void rtllib_mgnt_disconnect_ap(struct rtllib_device *rtllib, u8 rsn)
-{
- bool filter_out_nonassociated_bssid = false;
-
- filter_out_nonassociated_bssid = false;
- rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_CECHK_BSSID,
- (u8 *)(&filter_out_nonassociated_bssid));
- rtllib_mlme_disassociate_request(rtllib, rtllib->current_network.bssid,
- rsn);
-
- rtllib->link_state = MAC80211_NOLINK;
-}
-
-bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn)
-{
- if (rtllib->ps != RTLLIB_PS_DISABLED)
- rtllib->sta_wake_up(rtllib->dev);
-
- if (rtllib->link_state == MAC80211_LINKED) {
- if (rtllib->iw_mode == IW_MODE_INFRA)
- rtllib_mgnt_disconnect_ap(rtllib, rsn);
- }
-
- return true;
-}
-EXPORT_SYMBOL(rtllib_mgnt_disconnect);
-
-void notify_wx_assoc_event(struct rtllib_device *ieee)
-{
- union iwreq_data wrqu;
-
- if (ieee->cannot_notify)
- return;
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (ieee->link_state == MAC80211_LINKED) {
- memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid,
- ETH_ALEN);
- } else {
- netdev_info(ieee->dev, "%s(): Tell user space disconnected\n",
- __func__);
- eth_zero_addr(wrqu.ap_addr.sa_data);
- }
- wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL);
-}
-EXPORT_SYMBOL(notify_wx_assoc_event);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
deleted file mode 100644
index c59686d68a33..000000000000
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ /dev/null
@@ -1,534 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
- *
- * Mostly extracted from the rtl8180-sa2400 driver for the
- * in-kernel generic ieee802.11 stack.
- *
- * Some pieces of code might be stolen from ipw2100 driver
- * copyright of who own it's copyright ;-)
- *
- * PS wx handler mostly stolen from hostap, copyright who
- * own it's copyright ;-)
- */
-#include <linux/etherdevice.h>
-
-#include "rtllib.h"
-
-int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int ret;
- struct iw_freq *fwrq = &wrqu->freq;
-
- mutex_lock(&ieee->wx_mutex);
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- ret = 0;
- goto out;
- }
-
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- if ((fwrq->m >= (int)2.412e8 &&
- fwrq->m <= (int)2.487e8)) {
- fwrq->m = ieee80211_freq_khz_to_channel(fwrq->m / 100);
- fwrq->e = 0;
- }
- }
-
- if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
- ret = -EOPNOTSUPP;
- goto out;
-
- } else { /* Set the channel */
-
- if (ieee->active_channel_map[fwrq->m] != 1) {
- ret = -EINVAL;
- goto out;
- }
- ieee->current_network.channel = fwrq->m;
- ieee->set_chan(ieee->dev, ieee->current_network.channel);
- }
-
- ret = 0;
-out:
- mutex_unlock(&ieee->wx_mutex);
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_freq);
-
-int rtllib_wx_get_freq(struct rtllib_device *ieee,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- struct iw_freq *fwrq = &wrqu->freq;
-
- if (ieee->current_network.channel == 0)
- return -1;
- fwrq->m = ieee80211_channel_to_freq_khz(ieee->current_network.channel,
- NL80211_BAND_2GHZ) * 100;
- fwrq->e = 1;
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_freq);
-
-int rtllib_wx_get_wap(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- unsigned long flags;
-
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
-
- if (ieee->iw_mode == IW_MODE_MONITOR)
- return -1;
-
- /* We want avoid to give to the user inconsistent infos*/
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (ieee->link_state != MAC80211_LINKED &&
- ieee->link_state != MAC80211_LINKED_SCANNING &&
- ieee->wap_set == 0)
-
- eth_zero_addr(wrqu->ap_addr.sa_data);
- else
- memcpy(wrqu->ap_addr.sa_data,
- ieee->current_network.bssid, ETH_ALEN);
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_wap);
-
-int rtllib_wx_set_wap(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *awrq,
- char *extra)
-{
- int ret = 0;
- unsigned long flags;
-
- short ifup = ieee->proto_started;
- struct sockaddr *temp = (struct sockaddr *)awrq;
-
- rtllib_stop_scan_syncro(ieee);
-
- mutex_lock(&ieee->wx_mutex);
- /* use ifconfig hw ether */
-
- if (temp->sa_family != ARPHRD_ETHER) {
- ret = -EINVAL;
- goto out;
- }
-
- if (is_zero_ether_addr(temp->sa_data)) {
- spin_lock_irqsave(&ieee->lock, flags);
- ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
- ieee->wap_set = 0;
- spin_unlock_irqrestore(&ieee->lock, flags);
- ret = -1;
- goto out;
- }
-
- if (ifup)
- rtllib_stop_protocol(ieee);
-
- /* just to avoid to give inconsistent infos in the
- * get wx method. not really needed otherwise
- */
- spin_lock_irqsave(&ieee->lock, flags);
-
- ieee->cannot_notify = false;
- ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
- ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (ifup)
- rtllib_start_protocol(ieee);
-out:
- mutex_unlock(&ieee->wx_mutex);
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_wap);
-
-int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int len, ret = 0;
- unsigned long flags;
-
- if (ieee->iw_mode == IW_MODE_MONITOR)
- return -1;
-
- /* We want avoid to give to the user inconsistent infos*/
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (ieee->current_network.ssid[0] == '\0' ||
- ieee->current_network.ssid_len == 0) {
- ret = -1;
- goto out;
- }
-
- if (ieee->link_state != MAC80211_LINKED &&
- ieee->link_state != MAC80211_LINKED_SCANNING &&
- ieee->ssid_set == 0) {
- ret = -1;
- goto out;
- }
- len = ieee->current_network.ssid_len;
- wrqu->essid.length = len;
- strncpy(b, ieee->current_network.ssid, len);
- wrqu->essid.flags = 1;
-
-out:
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_get_essid);
-
-int rtllib_wx_set_rate(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u32 target_rate = wrqu->bitrate.value;
-
- ieee->rate = target_rate / 100000;
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_rate);
-
-int rtllib_wx_get_rate(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u32 tmp_rate;
-
- tmp_rate = tx_count_to_data_rate(ieee,
- ieee->softmac_stats.CurrentShowTxate);
- wrqu->bitrate.value = tmp_rate * 500000;
-
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_rate);
-
-int rtllib_wx_set_rts(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- if (wrqu->rts.disabled || !wrqu->rts.fixed) {
- ieee->rts = DEFAULT_RTS_THRESHOLD;
- } else {
- if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
- wrqu->rts.value > MAX_RTS_THRESHOLD)
- return -EINVAL;
- ieee->rts = wrqu->rts.value;
- }
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_rts);
-
-int rtllib_wx_get_rts(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- wrqu->rts.value = ieee->rts;
- wrqu->rts.fixed = 0; /* no auto select */
- wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_rts);
-
-int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int set_mode_status = 0;
-
- rtllib_stop_scan_syncro(ieee);
- mutex_lock(&ieee->wx_mutex);
- switch (wrqu->mode) {
- case IW_MODE_MONITOR:
- case IW_MODE_INFRA:
- break;
- case IW_MODE_AUTO:
- wrqu->mode = IW_MODE_INFRA;
- break;
- default:
- set_mode_status = -EINVAL;
- goto out;
- }
-
- if (wrqu->mode == ieee->iw_mode)
- goto out;
-
- if (wrqu->mode == IW_MODE_MONITOR) {
- ieee->dev->type = ARPHRD_IEEE80211;
- rtllib_enable_net_monitor_mode(ieee->dev, false);
- } else {
- ieee->dev->type = ARPHRD_ETHER;
- if (ieee->iw_mode == IW_MODE_MONITOR)
- rtllib_disable_net_monitor_mode(ieee->dev, false);
- }
-
- if (!ieee->proto_started) {
- ieee->iw_mode = wrqu->mode;
- } else {
- rtllib_stop_protocol(ieee);
- ieee->iw_mode = wrqu->mode;
- rtllib_start_protocol(ieee);
- }
-
-out:
- mutex_unlock(&ieee->wx_mutex);
- return set_mode_status;
-}
-EXPORT_SYMBOL(rtllib_wx_set_mode);
-
-void rtllib_wx_sync_scan_wq(void *data)
-{
- struct rtllib_device *ieee = container_of(data, struct rtllib_device, wx_sync_scan_wq);
- short chan;
- enum ht_extchnl_offset chan_offset = 0;
- enum ht_channel_width bandwidth = 0;
- int b40M = 0;
-
- mutex_lock(&ieee->wx_mutex);
- if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
- rtllib_start_scan_syncro(ieee);
- goto out;
- }
-
- chan = ieee->current_network.channel;
-
- ieee->leisure_ps_leave(ieee->dev);
- /* notify AP to be in PS mode */
- rtllib_sta_ps_send_null_frame(ieee, 1);
- rtllib_sta_ps_send_null_frame(ieee, 1);
-
- rtllib_stop_all_queues(ieee);
- ieee->link_state = MAC80211_LINKED_SCANNING;
- ieee->link_change(ieee->dev);
- /* wait for ps packet to be kicked out successfully */
- msleep(50);
-
- ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_BACKUP);
-
- if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht &&
- ieee->ht_info->cur_bw_40mhz) {
- b40M = 1;
- chan_offset = ieee->ht_info->cur_sta_ext_chnl_offset;
- bandwidth = (enum ht_channel_width)ieee->ht_info->cur_bw_40mhz;
- ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20,
- HT_EXTCHNL_OFFSET_NO_EXT);
- }
-
- rtllib_start_scan_syncro(ieee);
-
- if (b40M) {
- if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
- ieee->set_chan(ieee->dev, chan + 2);
- else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
- ieee->set_chan(ieee->dev, chan - 2);
- else
- ieee->set_chan(ieee->dev, chan);
- ieee->set_bw_mode_handler(ieee->dev, bandwidth, chan_offset);
- } else {
- ieee->set_chan(ieee->dev, chan);
- }
-
- ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_RESTORE);
-
- ieee->link_state = MAC80211_LINKED;
- ieee->link_change(ieee->dev);
-
- /* Notify AP that I wake up again */
- rtllib_sta_ps_send_null_frame(ieee, 0);
-
- if (ieee->link_detect_info.num_recv_bcn_in_period == 0 ||
- ieee->link_detect_info.num_recv_data_in_period == 0) {
- ieee->link_detect_info.num_recv_bcn_in_period = 1;
- ieee->link_detect_info.num_recv_data_in_period = 1;
- }
- rtllib_wake_all_queues(ieee);
-
-out:
- mutex_unlock(&ieee->wx_mutex);
-}
-
-int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- int ret = 0;
-
- if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
- ret = -1;
- goto out;
- }
-
- if (ieee->link_state == MAC80211_LINKED) {
- schedule_work(&ieee->wx_sync_scan_wq);
- /* intentionally forget to up sem */
- return 0;
- }
-
-out:
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_scan);
-
-int rtllib_wx_set_essid(struct rtllib_device *ieee,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
-{
- int ret = 0, len;
- short proto_started;
- unsigned long flags;
-
- rtllib_stop_scan_syncro(ieee);
- mutex_lock(&ieee->wx_mutex);
-
- proto_started = ieee->proto_started;
-
- len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- ret = -1;
- goto out;
- }
-
- if (proto_started)
- rtllib_stop_protocol(ieee);
-
- /* this is just to be sure that the GET wx callback
- * has consistent infos. not needed otherwise
- */
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (wrqu->essid.flags && wrqu->essid.length) {
- strncpy(ieee->current_network.ssid, extra, len);
- ieee->current_network.ssid_len = len;
- ieee->cannot_notify = false;
- ieee->ssid_set = 1;
- } else {
- ieee->ssid_set = 0;
- ieee->current_network.ssid[0] = '\0';
- ieee->current_network.ssid_len = 0;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (proto_started)
- rtllib_start_protocol(ieee);
-out:
- mutex_unlock(&ieee->wx_mutex);
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_essid);
-
-int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
- union iwreq_data *wrqu, char *b)
-{
- wrqu->mode = ieee->iw_mode;
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_mode);
-
-int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- const char *n = ieee->mode & (WIRELESS_MODE_N_24G) ? "n" : "";
-
- scnprintf(wrqu->name, sizeof(wrqu->name), "802.11bg%s", n);
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_name);
-
-/* this is mostly stolen from hostap */
-int rtllib_wx_set_power(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret = 0;
-
- if ((!ieee->sta_wake_up) ||
- (!ieee->enter_sleep_state) ||
- (!ieee->ps_is_queue_empty)) {
- netdev_warn(ieee->dev,
- "%s(): PS mode is tried to be use but driver missed a callback\n",
- __func__);
- return -1;
- }
-
- mutex_lock(&ieee->wx_mutex);
-
- if (wrqu->power.disabled) {
- ieee->ps = RTLLIB_PS_DISABLED;
- goto exit;
- }
- if (wrqu->power.flags & IW_POWER_TIMEOUT)
- ieee->ps_timeout = wrqu->power.value / 1000;
-
- if (wrqu->power.flags & IW_POWER_PERIOD)
- ieee->ps_period = wrqu->power.value / 1000;
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- ieee->ps = RTLLIB_PS_UNICAST;
- break;
- case IW_POWER_MULTICAST_R:
- ieee->ps = RTLLIB_PS_MBCAST;
- break;
- case IW_POWER_ALL_R:
- ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
- break;
-
- case IW_POWER_ON:
- break;
-
- default:
- ret = -EINVAL;
- goto exit;
- }
-exit:
- mutex_unlock(&ieee->wx_mutex);
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_power);
-
-/* this is stolen from hostap */
-int rtllib_wx_get_power(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- mutex_lock(&ieee->wx_mutex);
-
- if (ieee->ps == RTLLIB_PS_DISABLED) {
- wrqu->power.disabled = 1;
- goto exit;
- }
-
- wrqu->power.disabled = 0;
-
- if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- wrqu->power.flags = IW_POWER_TIMEOUT;
- wrqu->power.value = ieee->ps_timeout * 1000;
- } else {
- wrqu->power.flags = IW_POWER_PERIOD;
- wrqu->power.value = ieee->ps_period * 1000;
- }
-
- if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
- (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
- wrqu->power.flags |= IW_POWER_ALL_R;
- else if (ieee->ps & RTLLIB_PS_MBCAST)
- wrqu->power.flags |= IW_POWER_MULTICAST_R;
- else
- wrqu->power.flags |= IW_POWER_UNICAST_R;
-
-exit:
- mutex_unlock(&ieee->wx_mutex);
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_power);
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
deleted file mode 100644
index 8e2abd16eb86..000000000000
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ /dev/null
@@ -1,901 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * Few modifications for Realtek's Wi-Fi drivers by
- * Andrea Merello <andrea.merello@gmail.com>
- *
- * A special thanks goes to Realtek for their support !
- */
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <linux/if_vlan.h>
-
-#include "rtllib.h"
-
-/* 802.11 Data Frame
- *
- *
- * 802.11 frame_control for data frames - 2 bytes
- * ,--------------------------------------------------------------------.
- * bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e |
- * |---|---|---|---|---|---|---|---|---|----|----|-----|-----|-----|----|
- * val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x |
- * |---|---|---|---|---|---|---|---|---|----|----|-----|-----|-----|----|
- * desc | ver | type | ^-subtype-^ |to |from|more|retry| pwr |more |wep |
- * | | | x=0 data |DS | DS |frag| | mgm |data | |
- * | | | x=1 data+ack | | | | | | | |
- * '--------------------------------------------------------------------'
- * /\
- * |
- * 802.11 Data Frame |
- * ,--------- 'ctrl' expands to >---'
- * |
- * ,--'---,-------------------------------------------------------------.
- * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- * |------|------|---------|---------|---------|------|---------|------|
- * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
- * | | tion | (BSSID) | | | ence | data | |
- * `--------------------------------------------------| |------'
- * Total: 28 non-data bytes `----.----'
- * |
- * .- 'Frame data' expands to <---------------------------'
- * |
- * V
- * ,---------------------------------------------------.
- * Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
- * |------|------|---------|----------|------|---------|
- * Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
- * | DSAP | SSAP | | | | Packet |
- * | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
- * `-----------------------------------------| |
- * Total: 8 non-data bytes `----.----'
- * |
- * .- 'IP Packet' expands, if WEP enabled, to <--'
- * |
- * V
- * ,-----------------------.
- * Bytes | 4 | 0-2296 | 4 |
- * |-----|-----------|-----|
- * Desc. | IV | Encrypted | ICV |
- * | | IP Packet | |
- * `-----------------------'
- * Total: 8 non-data bytes
- *
- *
- * 802.3 Ethernet Data Frame
- *
- * ,-----------------------------------------.
- * Bytes | 6 | 6 | 2 | Variable | 4 |
- * |-------|-------|------|-----------|------|
- * Desc. | Dest. | Source| Type | IP Packet | fcs |
- * | MAC | MAC | | | |
- * `-----------------------------------------'
- * Total: 18 non-data bytes
- *
- * In the event that fragmentation is required, the incoming payload is split
- * into N parts of size ieee->fts. The first fragment contains the SNAP header
- * and the remaining packets are just data.
- *
- * If encryption is enabled, each fragment payload size is reduced by enough
- * space to add the prefix and postfix (IV and ICV totalling 8 bytes in
- * the case of WEP) So if you have 1500 bytes of payload with ieee->fts set to
- * 500 without encryption it will take 3 frames. With WEP it will take 4 frames
- * as the payload of each frame is reduced to 492 bytes.
- *
- * SKB visualization
- *
- * ,- skb->data
- * |
- * | ETHERNET HEADER ,-<-- PAYLOAD
- * | | 14 bytes from skb->data
- * | 2 bytes for Type --> ,T. | (sizeof ethhdr)
- * | | | |
- * |,-Dest.--. ,--Src.---. | | |
- * | 6 bytes| | 6 bytes | | | |
- * v | | | | | |
- * 0 | v 1 | v | v 2
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
- * ^ | ^ | ^ |
- * | | | | | |
- * | | | | `T' <---- 2 bytes for Type
- * | | | |
- * | | '---SNAP--' <-------- 6 bytes for SNAP
- * | |
- * `-IV--' <-------------------- 4 bytes for IV (WEP)
- *
- * SNAP HEADER
- *
- */
-
-static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
-static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-
-static int rtllib_put_snap(u8 *data, u16 h_proto)
-{
- struct rtllib_snap_hdr *snap;
- u8 *oui;
-
- snap = (struct rtllib_snap_hdr *)data;
- snap->dsap = 0xaa;
- snap->ssap = 0xaa;
- snap->ctrl = 0x03;
-
- if (h_proto == 0x8137 || h_proto == 0x80f3)
- oui = P802_1H_OUI;
- else
- oui = RFC1042_OUI;
- snap->oui[0] = oui[0];
- snap->oui[1] = oui[1];
- snap->oui[2] = oui[2];
-
- *(__be16 *)(data + SNAP_SIZE) = htons(h_proto);
-
- return SNAP_SIZE + sizeof(u16);
-}
-
-int rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag,
- int hdr_len)
-{
- struct lib80211_crypt_data *crypt = NULL;
- int res;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
-
- if (!(crypt && crypt->ops)) {
- netdev_info(ieee->dev, "=========>%s(), crypt is null\n",
- __func__);
- return -1;
- }
- /* To encrypt, frame format is:
- * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes)
- */
-
- /* 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(frag, hdr_len, crypt->priv);
- if (res == 0 && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
-
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- netdev_info(ieee->dev, "%s: Encryption failed: len=%d.\n",
- ieee->dev->name, frag->len);
- return -1;
- }
-
- return 0;
-}
-
-void rtllib_txb_free(struct rtllib_txb *txb)
-{
- if (unlikely(!txb))
- return;
- kfree(txb);
-}
-
-static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size,
- gfp_t gfp_mask)
-{
- struct rtllib_txb *txb;
- int i;
-
- txb = kzalloc(struct_size(txb, fragments, nr_frags), gfp_mask);
- if (!txb)
- return NULL;
-
- txb->nr_frags = nr_frags;
- txb->frag_size = cpu_to_le16(txb_size);
-
- for (i = 0; i < nr_frags; i++) {
- txb->fragments[i] = dev_alloc_skb(txb_size);
- if (unlikely(!txb->fragments[i]))
- goto err_free;
- memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb));
- }
-
- return txb;
-
-err_free:
- while (--i >= 0)
- dev_kfree_skb_any(txb->fragments[i]);
- kfree(txb);
-
- return NULL;
-}
-
-static int rtllib_classify(struct sk_buff *skb)
-{
- struct ethhdr *eth;
- struct iphdr *ip;
-
- eth = (struct ethhdr *)skb->data;
- if (eth->h_proto != htons(ETH_P_IP))
- return 0;
-
-#ifdef VERBOSE_DEBUG
- print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, skb->data,
- skb->len);
-#endif
- ip = ip_hdr(skb);
- switch (ip->tos & 0xfc) {
- case 0x20:
- return 2;
- case 0x40:
- return 1;
- case 0x60:
- return 3;
- case 0x80:
- return 4;
- case 0xa0:
- return 5;
- case 0xc0:
- return 6;
- case 0xe0:
- return 7;
- default:
- return 0;
- }
-}
-
-static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
- struct sk_buff *skb,
- struct cb_desc *tcb_desc)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct tx_ts_record *ts = NULL;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
- if (rtllib_act_scanning(ieee, false))
- return;
-
- if (!ht_info->current_ht_support || !ht_info->enable_ht)
- return;
- if (!is_qos_data_frame(skb->data))
- return;
- if (is_multicast_ether_addr(hdr->addr1))
- return;
-
- if (tcb_desc->bdhcp || ieee->cnt_after_link < 2)
- return;
-
- if (ht_info->iot_action & HT_IOT_ACT_TX_NO_AGGREGATION)
- return;
-
- if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev))
- return;
- if (ht_info->current_ampdu_enable) {
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), hdr->addr1,
- skb->priority, TX_DIR, true)) {
- netdev_info(ieee->dev, "%s: can't get TS\n", __func__);
- return;
- }
- if (!ts->tx_admitted_ba_record.b_valid) {
- if (ieee->wpa_ie_len && (ieee->pairwise_key_type ==
- KEY_TYPE_NA)) {
- ;
- } else if (tcb_desc->bdhcp == 1) {
- ;
- } else if (!ts->disable_add_ba) {
- rtllib_ts_start_add_ba_process(ieee, ts);
- }
- return;
- } else if (!ts->using_ba) {
- if (SN_LESS(ts->tx_admitted_ba_record.ba_start_seq_ctrl.field.seq_num,
- (ts->tx_cur_seq + 1) % 4096))
- ts->using_ba = true;
- else
- return;
- }
- if (ieee->iw_mode == IW_MODE_INFRA) {
- tcb_desc->ampdu_enable = true;
- tcb_desc->ampdu_factor = ht_info->current_ampdu_factor;
- tcb_desc->ampdu_density = ht_info->current_mpdu_density;
- }
- }
-}
-
-static void rtllib_query_short_preamble_mode(struct rtllib_device *ieee,
- struct cb_desc *tcb_desc)
-{
- tcb_desc->use_short_preamble = false;
- if (tcb_desc->data_rate == 2)
- return;
- else if (ieee->current_network.capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE)
- tcb_desc->use_short_preamble = true;
-}
-
-static void rtllib_query_ht_cap_short_gi(struct rtllib_device *ieee,
- struct cb_desc *tcb_desc)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- tcb_desc->use_short_gi = false;
-
- if (!ht_info->current_ht_support || !ht_info->enable_ht)
- return;
-
- if (ht_info->cur_bw_40mhz && ht_info->cur_short_gi_40mhz)
- tcb_desc->use_short_gi = true;
- else if (!ht_info->cur_bw_40mhz && ht_info->cur_short_gi_20mhz)
- tcb_desc->use_short_gi = true;
-}
-
-static void rtllib_query_bandwidth_mode(struct rtllib_device *ieee,
- struct cb_desc *tcb_desc)
-{
- struct rt_hi_throughput *ht_info = ieee->ht_info;
-
- tcb_desc->packet_bw = false;
-
- if (!ht_info->current_ht_support || !ht_info->enable_ht)
- return;
-
- if (tcb_desc->multicast || tcb_desc->broadcast)
- return;
-
- if ((tcb_desc->data_rate & 0x80) == 0)
- return;
- if (ht_info->cur_bw_40mhz && ht_info->cur_tx_bw40mhz &&
- !ieee->bandwidth_auto_switch.forced_tx_20MHz)
- tcb_desc->packet_bw = true;
-}
-
-static void rtllib_query_protectionmode(struct rtllib_device *ieee,
- struct cb_desc *tcb_desc,
- struct sk_buff *skb)
-{
- struct rt_hi_throughput *ht_info;
-
- tcb_desc->rtsstbc = false;
- tcb_desc->rts_use_short_gi = false;
- tcb_desc->cts_enable = false;
- tcb_desc->RTSSC = 0;
- tcb_desc->rts_bw = false;
-
- if (tcb_desc->broadcast || tcb_desc->multicast)
- return;
-
- if (is_broadcast_ether_addr(skb->data + 16))
- return;
-
- if (ieee->mode < WIRELESS_MODE_N_24G) {
- if (skb->len > ieee->rts) {
- tcb_desc->rts_enable = true;
- tcb_desc->rts_rate = MGN_24M;
- } else if (ieee->current_network.buseprotection) {
- tcb_desc->rts_enable = true;
- tcb_desc->cts_enable = true;
- tcb_desc->rts_rate = MGN_24M;
- }
- return;
- }
-
- ht_info = ieee->ht_info;
-
- while (true) {
- if (ht_info->iot_action & HT_IOT_ACT_FORCED_CTS2SELF) {
- tcb_desc->cts_enable = true;
- tcb_desc->rts_rate = MGN_24M;
- tcb_desc->rts_enable = true;
- break;
- } else if (ht_info->iot_action & (HT_IOT_ACT_FORCED_RTS |
- HT_IOT_ACT_PURE_N_MODE)) {
- tcb_desc->rts_enable = true;
- tcb_desc->rts_rate = MGN_24M;
- break;
- }
- if (ieee->current_network.buseprotection) {
- tcb_desc->rts_enable = true;
- tcb_desc->cts_enable = true;
- tcb_desc->rts_rate = MGN_24M;
- break;
- }
- if (ht_info->current_ht_support && ht_info->enable_ht) {
- u8 ht_op_mode = ht_info->current_op_mode;
-
- if ((ht_info->cur_bw_40mhz && (ht_op_mode == 2 ||
- ht_op_mode == 3)) ||
- (!ht_info->cur_bw_40mhz && ht_op_mode == 3)) {
- tcb_desc->rts_rate = MGN_24M;
- tcb_desc->rts_enable = true;
- break;
- }
- }
- if (skb->len > ieee->rts) {
- tcb_desc->rts_rate = MGN_24M;
- tcb_desc->rts_enable = true;
- break;
- }
- if (tcb_desc->ampdu_enable) {
- tcb_desc->rts_rate = MGN_24M;
- tcb_desc->rts_enable = false;
- break;
- }
- goto NO_PROTECTION;
- }
- if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- tcb_desc->use_short_preamble = true;
- return;
-NO_PROTECTION:
- tcb_desc->rts_enable = false;
- tcb_desc->cts_enable = false;
- tcb_desc->rts_rate = 0;
- tcb_desc->RTSSC = 0;
- tcb_desc->rts_bw = false;
-}
-
-static void rtllib_txrate_selectmode(struct rtllib_device *ieee,
- struct cb_desc *tcb_desc)
-{
- if (ieee->tx_dis_rate_fallback)
- tcb_desc->tx_dis_rate_fallback = true;
-
- if (ieee->tx_use_drv_assinged_rate)
- tcb_desc->tx_use_drv_assinged_rate = true;
- if (!tcb_desc->tx_dis_rate_fallback ||
- !tcb_desc->tx_use_drv_assinged_rate) {
- if (ieee->iw_mode == IW_MODE_INFRA)
- tcb_desc->ratr_index = 0;
- }
-}
-
-static u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb,
- u8 *dst)
-{
- u16 seqnum = 0;
-
- if (is_multicast_ether_addr(dst))
- return 0;
- if (is_qos_data_frame(skb->data)) {
- struct tx_ts_record *ts = NULL;
-
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), dst,
- skb->priority, TX_DIR, true))
- return 0;
- seqnum = ts->tx_cur_seq;
- ts->tx_cur_seq = (ts->tx_cur_seq + 1) % 4096;
- return seqnum;
- }
- return 0;
-}
-
-static int wme_downgrade_ac(struct sk_buff *skb)
-{
- switch (skb->priority) {
- case 6:
- case 7:
- skb->priority = 5; /* VO -> VI */
- return 0;
- case 4:
- case 5:
- skb->priority = 3; /* VI -> BE */
- return 0;
- case 0:
- case 3:
- skb->priority = 1; /* BE -> BK */
- return 0;
- default:
- return -1;
- }
-}
-
-static u8 rtllib_current_rate(struct rtllib_device *ieee)
-{
- if (ieee->mode & IEEE_MODE_MASK)
- return ieee->rate;
-
- if (ieee->ht_curr_op_rate)
- return ieee->ht_curr_op_rate;
- else
- return ieee->rate & 0x7F;
-}
-
-static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
-{
- struct rtllib_device *ieee = (struct rtllib_device *)
- netdev_priv_rsl(dev);
- struct rtllib_txb *txb = NULL;
- struct ieee80211_qos_hdr *frag_hdr;
- int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
- unsigned long flags;
- struct net_device_stats *stats = &ieee->stats;
- int ether_type = 0, encrypt;
- int bytes, fc, qos_ctl = 0, hdr_len;
- struct sk_buff *skb_frag;
- struct ieee80211_qos_hdr header = { /* Ensure zero initialized */
- .duration_id = 0,
- .seq_ctrl = 0,
- .qos_ctrl = 0
- };
- int qos_activated = ieee->current_network.qos_data.active;
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- struct cb_desc *tcb_desc;
- u8 is_multicast = false;
- bool bdhcp = false;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* If there is no driver handler to take the TXB, don't bother
- * creating it...
- */
- if (!(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) ||
- ((!ieee->softmac_data_hard_start_xmit &&
- (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
- netdev_warn(ieee->dev, "No xmit handler.\n");
- goto success;
- }
-
- if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
- netdev_warn(ieee->dev, "skb too small (%d).\n",
- skb->len);
- goto success;
- }
- /* Save source and destination addresses */
- ether_addr_copy(dest, skb->data);
- ether_addr_copy(src, skb->data + ETH_ALEN);
-
- memset(skb->cb, 0, sizeof(skb->cb));
- ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC);
- if (unlikely(!txb)) {
- netdev_warn(ieee->dev,
- "Could not allocate TXB\n");
- goto failed;
- }
-
- txb->encrypted = 0;
- txb->payload_size = cpu_to_le16(skb->len);
- skb_put_data(txb->fragments[0], skb->data, skb->len);
-
- goto success;
- }
-
- if (skb->len > 282) {
- if (ether_type == ETH_P_IP) {
- const struct iphdr *ip = (struct iphdr *)
- ((u8 *)skb->data + 14);
- if (ip->protocol == IPPROTO_UDP) {
- struct udphdr *udp;
-
- udp = (struct udphdr *)((u8 *)ip +
- (ip->ihl << 2));
- if (((((u8 *)udp)[1] == 68) &&
- (((u8 *)udp)[3] == 67)) ||
- ((((u8 *)udp)[1] == 67) &&
- (((u8 *)udp)[3] == 68))) {
- bdhcp = true;
- ieee->lps_delay_cnt = 200;
- }
- }
- } else if (ether_type == ETH_P_ARP) {
- netdev_info(ieee->dev,
- "=================>DHCP Protocol start tx ARP pkt!!\n");
- bdhcp = true;
- ieee->lps_delay_cnt =
- ieee->current_network.tim.tim_count;
- }
- }
-
- skb->priority = rtllib_classify(skb);
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && crypt && crypt->ops;
- if (!encrypt && ieee->ieee802_1x &&
- ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
- stats->tx_dropped++;
- goto success;
- }
- if (crypt && !encrypt && ether_type == ETH_P_PAE) {
- struct eapol *eap = (struct eapol *)(skb->data +
- sizeof(struct ethhdr) - SNAP_SIZE -
- sizeof(u16));
- netdev_dbg(ieee->dev,
- "TX: IEEE 802.11 EAPOL frame: %s\n",
- eap_get_type(eap->type));
- }
-
- /* Advance the SKB to the start of the payload */
- skb_pull(skb, sizeof(struct ethhdr));
-
- /* Determine total amount of storage required for TXB packets */
- bytes = skb->len + SNAP_SIZE + sizeof(u16);
-
- if (encrypt)
- fc = RTLLIB_FTYPE_DATA | IEEE80211_FCTL_PROTECTED;
- else
- fc = RTLLIB_FTYPE_DATA;
-
- if (qos_activated)
- fc |= IEEE80211_STYPE_QOS_DATA;
- else
- fc |= IEEE80211_STYPE_DATA;
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA,
- * Addr3 = DA
- */
- ether_addr_copy(header.addr1,
- ieee->current_network.bssid);
- ether_addr_copy(header.addr2, src);
- ether_addr_copy(header.addr3, dest);
- }
-
- is_multicast = is_multicast_ether_addr(header.addr1);
-
- header.frame_control = cpu_to_le16(fc);
-
- /* Determine fragmentation size based on destination (multicast
- * and broadcast are not fragmented)
- */
- if (is_multicast) {
- frag_size = MAX_FRAG_THRESHOLD;
- qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
- } else {
- frag_size = ieee->fts;
- qos_ctl = 0;
- }
-
- if (qos_activated) {
- hdr_len = RTLLIB_3ADDR_LEN + 2;
-
- /* in case we are a client verify acm is not set for this ac */
- while (unlikely(ieee->wmm_acm & (0x01 << skb->priority))) {
- netdev_info(ieee->dev, "skb->priority = %x\n",
- skb->priority);
- if (wme_downgrade_ac(skb))
- break;
- netdev_info(ieee->dev, "converted skb->priority = %x\n",
- skb->priority);
- }
-
- qos_ctl |= skb->priority;
- header.qos_ctrl = cpu_to_le16(qos_ctl & RTLLIB_QOS_TID);
-
- } else {
- hdr_len = RTLLIB_3ADDR_LEN;
- }
- /* Determine amount of payload per fragment. Regardless of if
- * this stack is providing the full 802.11 header, one will
- * eventually be affixed to this fragment -- so we must account
- * for it when determining the amount of payload space.
- */
- bytes_per_frag = frag_size - hdr_len;
- if (ieee->config &
- (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
- bytes_per_frag -= RTLLIB_FCS_LEN;
-
- /* Each fragment may need to have room for encrypting
- * pre/postfix
- */
- if (encrypt) {
- bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_mpdu_postfix_len +
- crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- }
- /* Number of fragments is the total bytes_per_frag /
- * payload_per_fragment
- */
- nr_frags = bytes / bytes_per_frag;
- bytes_last_frag = bytes % bytes_per_frag;
- if (bytes_last_frag)
- nr_frags++;
- else
- bytes_last_frag = bytes_per_frag;
-
- /* When we allocate the TXB we allocate enough space for the
- * reserve and full fragment bytes (bytes_per_frag doesn't
- * include prefix, postfix, header, FCS, etc.)
- */
- txb = rtllib_alloc_txb(nr_frags, frag_size +
- ieee->tx_headroom, GFP_ATOMIC);
- if (unlikely(!txb)) {
- netdev_warn(ieee->dev, "Could not allocate TXB\n");
- goto failed;
- }
- txb->encrypted = encrypt;
- txb->payload_size = cpu_to_le16(bytes);
-
- if (qos_activated)
- txb->queue_index = UP2AC(skb->priority);
- else
- txb->queue_index = WME_AC_BE;
-
- for (i = 0; i < nr_frags; i++) {
- skb_frag = txb->fragments[i];
- tcb_desc = (struct cb_desc *)(skb_frag->cb +
- MAX_DEV_ADDR_SIZE);
- if (qos_activated) {
- skb_frag->priority = skb->priority;
- tcb_desc->queue_index = UP2AC(skb->priority);
- } else {
- skb_frag->priority = WME_AC_BE;
- tcb_desc->queue_index = WME_AC_BE;
- }
- skb_reserve(skb_frag, ieee->tx_headroom);
-
- if (encrypt) {
- if (ieee->hwsec_active)
- tcb_desc->hw_sec = 1;
- else
- tcb_desc->hw_sec = 0;
- skb_reserve(skb_frag,
- crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_msdu_prefix_len);
- } else {
- tcb_desc->hw_sec = 0;
- }
- frag_hdr = skb_put_data(skb_frag, &header, hdr_len);
-
- /* If this is not the last fragment, then add the
- * MOREFRAGS bit to the frame control
- */
- if (i != nr_frags - 1) {
- frag_hdr->frame_control = cpu_to_le16(fc |
- IEEE80211_FCTL_MOREFRAGS);
- bytes = bytes_per_frag;
-
- } else {
- /* The last fragment has the remaining length */
- bytes = bytes_last_frag;
- }
- if ((qos_activated) && (!is_multicast)) {
- frag_hdr->seq_ctrl =
- cpu_to_le16(rtllib_query_seqnum(ieee, skb_frag,
- header.addr1));
- frag_hdr->seq_ctrl =
- cpu_to_le16(le16_to_cpu(frag_hdr->seq_ctrl) << 4 | i);
- } else {
- frag_hdr->seq_ctrl =
- cpu_to_le16(ieee->seq_ctrl[0] << 4 | i);
- }
- /* Put a SNAP header on the first fragment */
- if (i == 0) {
- rtllib_put_snap(skb_put(skb_frag,
- SNAP_SIZE +
- sizeof(u16)), ether_type);
- bytes -= SNAP_SIZE + sizeof(u16);
- }
-
- skb_put_data(skb_frag, skb->data, bytes);
-
- /* Advance the SKB... */
- skb_pull(skb, bytes);
-
- /* Encryption routine will move the header forward in
- * order to insert the IV between the header and the
- * payload
- */
- if (encrypt)
- rtllib_encrypt_fragment(ieee, skb_frag,
- hdr_len);
- if (ieee->config &
- (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
- skb_put(skb_frag, 4);
- }
-
- if ((qos_activated) && (!is_multicast)) {
- if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF)
- ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0;
- else
- ieee->seq_ctrl[UP2AC(skb->priority) + 1]++;
- } else {
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
- }
-
- success:
- if (txb) {
- tcb_desc = (struct cb_desc *)
- (txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
- tcb_desc->tx_enable_fw_calc_dur = 1;
- tcb_desc->priority = skb->priority;
-
- if (ether_type == ETH_P_PAE) {
- if (ieee->ht_info->iot_action &
- HT_IOT_ACT_WA_IOT_Broadcom) {
- tcb_desc->data_rate =
- mgnt_query_tx_rate_exclude_cck_rates(ieee);
- tcb_desc->tx_dis_rate_fallback = false;
- } else {
- tcb_desc->data_rate = ieee->basic_rate;
- tcb_desc->tx_dis_rate_fallback = 1;
- }
-
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- } else {
- if (is_multicast_ether_addr(header.addr1))
- tcb_desc->multicast = 1;
- if (is_broadcast_ether_addr(header.addr1))
- tcb_desc->broadcast = 1;
- rtllib_txrate_selectmode(ieee, tcb_desc);
- if (tcb_desc->multicast || tcb_desc->broadcast)
- tcb_desc->data_rate = ieee->basic_rate;
- else
- tcb_desc->data_rate = rtllib_current_rate(ieee);
-
- if (bdhcp) {
- if (ieee->ht_info->iot_action &
- HT_IOT_ACT_WA_IOT_Broadcom) {
- tcb_desc->data_rate =
- mgnt_query_tx_rate_exclude_cck_rates(ieee);
- tcb_desc->tx_dis_rate_fallback = false;
- } else {
- tcb_desc->data_rate = MGN_1M;
- tcb_desc->tx_dis_rate_fallback = 1;
- }
-
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- tcb_desc->bdhcp = 1;
- }
-
- rtllib_query_short_preamble_mode(ieee, tcb_desc);
- rtllib_tx_query_agg_cap(ieee, txb->fragments[0],
- tcb_desc);
- rtllib_query_ht_cap_short_gi(ieee, tcb_desc);
- rtllib_query_bandwidth_mode(ieee, tcb_desc);
- rtllib_query_protectionmode(ieee, tcb_desc,
- txb->fragments[0]);
- }
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
- dev_kfree_skb_any(skb);
- if (txb) {
- if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += le16_to_cpu(txb->payload_size);
- rtllib_softmac_xmit(txb, ieee);
- } else {
- rtllib_txb_free(txb);
- }
- }
-
- return 0;
-
- failed:
- spin_unlock_irqrestore(&ieee->lock, flags);
- netif_stop_queue(dev);
- stats->tx_errors++;
- return 1;
-}
-
-netdev_tx_t rtllib_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- memset(skb->cb, 0, sizeof(skb->cb));
- return rtllib_xmit_inter(skb, dev) ? NETDEV_TX_BUSY : NETDEV_TX_OK;
-}
-EXPORT_SYMBOL(rtllib_xmit);
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
deleted file mode 100644
index c730d921463d..000000000000
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ /dev/null
@@ -1,752 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright(c) 2004 Intel Corporation. All rights reserved.
- *
- * Portions of this file are based on the WEP enablement code provided by the
- * Host AP project hostap-drivers v0.1.3
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- */
-#include <linux/wireless.h>
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/etherdevice.h>
-#include "rtllib.h"
-
-static const char * const rtllib_modes[] = {
- "a", "b", "g", "?", "N-24G"
-};
-
-#define MAX_CUSTOM_LEN 64
-static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
- char *start, char *stop,
- struct rtllib_network *network,
- struct iw_request_info *info)
-{
- char custom[MAX_CUSTOM_LEN];
- char proto_name[6];
- char *pname = proto_name;
- char *p;
- struct iw_event iwe;
- int i, j;
- u16 max_rate, rate;
- static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
- /* Remaining entries will be displayed in the order we provide them */
-
- /* Add the ESSID */
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- if (network->ssid_len > 0) {
- iwe.u.data.length = min_t(u8, network->ssid_len, 32);
- start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
- } else if (network->hidden_ssid_len == 0) {
- iwe.u.data.length = sizeof("<hidden>");
- start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
- } else {
- iwe.u.data.length = min_t(u8, network->hidden_ssid_len, 32);
- start = iwe_stream_add_point(info, start, stop, &iwe, network->hidden_ssid);
- }
- /* Add the protocol name */
- iwe.cmd = SIOCGIWNAME;
- for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
- if (network->mode & BIT(i)) {
- strcpy(pname, rtllib_modes[i]);
- pname += strlen(rtllib_modes[i]);
- }
- }
- *pname = '\0';
- snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- if (network->capability &
- (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (network->capability & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add frequency/channel */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = network->channel;
- iwe.u.freq.e = 0;
- iwe.u.freq.i = 0;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (network->capability & 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;
- start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
- /* Add basic and extended rates */
- max_rate = 0;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
- for (i = 0, j = 0; i < network->rates_len;) {
- if (j < network->rates_ex_len &&
- ((network->rates_ex[j] & 0x7F) <
- (network->rates[i] & 0x7F)))
- rate = network->rates_ex[j++] & 0x7F;
- else
- rate = network->rates[i++] & 0x7F;
- if (rate > max_rate)
- max_rate = rate;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
- }
- for (; j < network->rates_ex_len; j++) {
- rate = network->rates_ex[j] & 0x7F;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
- if (rate > max_rate)
- max_rate = rate;
- }
-
- if (network->mode >= WIRELESS_MODE_N_24G) {
- struct ht_capab_ele *ht_cap = NULL;
- bool is40M = false, isShortGI = false;
- u8 max_mcs = 0;
-
- if (!memcmp(network->bssht.bd_ht_cap_buf, EWC11NHTCap, 4))
- ht_cap = (struct ht_capab_ele *)
- &network->bssht.bd_ht_cap_buf[4];
- else
- ht_cap = (struct ht_capab_ele *)
- &network->bssht.bd_ht_cap_buf[0];
- is40M = (ht_cap->chl_width) ? 1 : 0;
- isShortGI = (ht_cap->chl_width) ?
- ((ht_cap->short_gi_40mhz) ? 1 : 0) :
- ((ht_cap->short_gi_20mhz) ? 1 : 0);
-
- max_mcs = ht_get_highest_mcs_rate(ieee, ht_cap->MCS,
- MCS_FILTER_ALL);
- rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
- if (rate > max_rate)
- max_rate = rate;
- }
- iwe.cmd = SIOCGIWRATE;
- iwe.u.bitrate.disabled = 0;
- iwe.u.bitrate.fixed = 0;
- iwe.u.bitrate.value = max_rate * 500000;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
- /* Add quality statistics */
- /* TODO: Fix these values... */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = network->stats.signal;
- iwe.u.qual.level = network->stats.rssi;
- iwe.u.qual.noise = network->stats.noise;
- iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
- if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
- iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
- if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
- iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
- if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
- iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
- iwe.u.qual.updated = 7;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
- iwe.cmd = IWEVCUSTOM;
- p = custom;
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->wpa_ie_len) {
- char buf[MAX_WPA_IE_LEN];
-
- memcpy(buf, network->wpa_ie, network->wpa_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->wpa_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
- memset(&iwe, 0, sizeof(iwe));
- if (network->rsn_ie_len) {
- char buf[MAX_WPA_IE_LEN];
-
- memcpy(buf, network->rsn_ie, network->rsn_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->rsn_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- /* add info for WZC */
- memset(&iwe, 0, sizeof(iwe));
- if (network->wzc_ie_len) {
- char buf[MAX_WZC_IE_LEN];
-
- memcpy(buf, network->wzc_ie, network->wzc_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->wzc_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network.
- */
- iwe.cmd = IWEVCUSTOM;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- " Last beacon: %lums ago",
- (100 * (jiffies - network->last_scanned)) / HZ);
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- return start;
-}
-
-int rtllib_wx_get_scan(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct rtllib_network *network;
- unsigned long flags;
-
- char *ev = extra;
- char *stop = ev + wrqu->data.length;
- int i = 0;
- int err = 0;
-
- netdev_dbg(ieee->dev, "Getting scan\n");
- mutex_lock(&ieee->wx_mutex);
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(network, &ieee->network_list, list) {
- i++;
- if ((stop - ev) < 200) {
- err = -E2BIG;
- break;
- }
- if (ieee->scan_age == 0 ||
- time_after(network->last_scanned + ieee->scan_age, jiffies))
- ev = rtl819x_translate_scan(ieee, ev, stop, network,
- info);
- else
- netdev_dbg(ieee->dev,
- "Network '%s ( %pM)' hidden due to age (%lums).\n",
- escape_essid(network->ssid,
- network->ssid_len),
- network->bssid,
- (100 * (jiffies - network->last_scanned)) /
- HZ);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
- mutex_unlock(&ieee->wx_mutex);
- wrqu->data.length = ev - extra;
- wrqu->data.flags = 0;
-
- netdev_dbg(ieee->dev, "%s(): %d networks returned.\n", __func__, i);
-
- return err;
-}
-EXPORT_SYMBOL(rtllib_wx_get_scan);
-
-int rtllib_wx_set_encode(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct net_device *dev = ieee->dev;
- struct rtllib_security sec = {
- .flags = 0
- };
- int i, key, key_provided, len;
- struct lib80211_crypt_data **crypt;
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > NUM_WEP_KEYS)
- return -EINVAL;
- key--;
- key_provided = 1;
- } else {
- key_provided = 0;
- key = ieee->crypt_info.tx_keyidx;
- }
-
- netdev_dbg(ieee->dev, "Key: %d [%s]\n", key, key_provided ?
- "provided" : "default");
- crypt = &ieee->crypt_info.crypt[key];
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (key_provided && *crypt) {
- netdev_dbg(ieee->dev,
- "Disabling encryption on key %d.\n", key);
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- } else {
- netdev_dbg(ieee->dev, "Disabling encryption.\n");
- }
-
- /* Check all the keys to see if any are still configured,
- * and if no key index was provided, de-init them all
- */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ieee->crypt_info.crypt[i]) {
- if (key_provided)
- break;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info,
- &ieee->crypt_info.crypt[i]);
- }
- }
-
- if (i == NUM_WEP_KEYS) {
- sec.enabled = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_ENABLED | SEC_LEVEL;
- }
-
- goto done;
- }
-
- sec.enabled = 1;
- sec.flags |= SEC_ENABLED;
-
- if (*crypt && (*crypt)->ops &&
- strcmp((*crypt)->ops->name, "R-WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm
- * on this key
- */
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- }
-
- if (!*crypt) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
- if (!new_crypt)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
- if (!new_crypt->ops) {
- request_module("rtllib_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
- }
-
- if (new_crypt->ops)
- new_crypt->priv = new_crypt->ops->init(key);
-
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- netdev_warn(dev,
- "%s: could not initialize WEP: load module rtllib_crypt_wep\n",
- dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- /* If a new key was provided, set it up */
- if (erq->length > 0) {
- len = erq->length <= 5 ? 5 : 13;
- memcpy(sec.keys[key], keybuf, erq->length);
- if (len > erq->length)
- memset(sec.keys[key] + erq->length, 0,
- len - erq->length);
- netdev_dbg(ieee->dev, "Setting key %d to '%s' (%d:%d bytes)\n",
- key, escape_essid(sec.keys[key], len), erq->length,
- len);
- sec.key_sizes[key] = len;
- (*crypt)->ops->set_key(sec.keys[key], len, NULL,
- (*crypt)->priv);
- sec.flags |= (1 << key);
- /* This ensures a key will be activated if no key is
- * explicitly set
- */
- if (key == sec.active_key)
- sec.flags |= SEC_ACTIVE_KEY;
- ieee->crypt_info.tx_keyidx = key;
-
- } else {
- len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
- NULL, (*crypt)->priv);
- if (len == 0) {
- /* Set a default key of all 0 */
- netdev_info(ieee->dev, "Setting key %d to all zero.\n", key);
-
- memset(sec.keys[key], 0, 13);
- (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
- (*crypt)->priv);
- sec.key_sizes[key] = 13;
- sec.flags |= (1 << key);
- }
-
- /* No key data - just set the default TX key index */
- if (key_provided) {
- netdev_dbg(ieee->dev,
- "Setting key %d as default Tx key.\n", key);
- ieee->crypt_info.tx_keyidx = key;
- sec.active_key = key;
- sec.flags |= SEC_ACTIVE_KEY;
- }
- }
- done:
- ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
- ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
- WLAN_AUTH_SHARED_KEY;
- sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
- sec.flags |= SEC_AUTH_MODE;
- netdev_dbg(ieee->dev, "Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
- "OPEN" : "SHARED KEY");
-
- /* For now we just support WEP, so only set that security level...
- * TODO: When WPA is added this is one place that needs to change
- */
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_encode);
-
-int rtllib_wx_get_encode(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- int len, key;
- struct lib80211_crypt_data *crypt;
-
- if (ieee->iw_mode == IW_MODE_MONITOR)
- return -1;
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > NUM_WEP_KEYS)
- return -EINVAL;
- key--;
- } else {
- key = ieee->crypt_info.tx_keyidx;
- }
- crypt = ieee->crypt_info.crypt[key];
-
- erq->flags = key + 1;
-
- if (!crypt || !crypt->ops) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
- len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
-
- erq->length = max(len, 0);
-
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (ieee->open_wep)
- erq->flags |= IW_ENCODE_OPEN;
- else
- erq->flags |= IW_ENCODE_RESTRICTED;
-
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_get_encode);
-
-int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int ret = 0;
- struct net_device *dev = ieee->dev;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int i, idx;
- int group_key = 0;
- const char *alg, *module;
- const struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
-
- struct rtllib_security sec = {
- .flags = 0,
- };
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > NUM_WEP_KEYS)
- return -EINVAL;
- idx--;
- } else {
- idx = ieee->crypt_info.tx_keyidx;
- }
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- crypt = &ieee->crypt_info.crypt[idx];
- group_key = 1;
- } else {
- /* some Cisco APs use idx>0 for unicast in dynamic WEP */
- if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
- return -EINVAL;
- if (ieee->iw_mode == IW_MODE_INFRA)
- crypt = &ieee->crypt_info.crypt[idx];
- else
- return -EINVAL;
- }
-
- sec.flags |= SEC_ENABLED;
- if ((encoding->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ieee->crypt_info.crypt[i])
- break;
- }
- if (i == NUM_WEP_KEYS) {
- sec.enabled = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_LEVEL;
- }
- goto done;
- }
-
- sec.enabled = 1;
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "R-WEP";
- module = "rtllib_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "R-TKIP";
- module = "rtllib_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "R-CCMP";
- module = "rtllib_crypt_ccmp";
- break;
- default:
- netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg);
- ret = -EINVAL;
- goto done;
- }
- netdev_dbg(dev, "alg name:%s\n", alg);
-
- ops = lib80211_get_crypto_ops(alg);
- if (!ops) {
- char tempbuf[100];
-
- memset(tempbuf, 0x00, 100);
- sprintf(tempbuf, "%s", module);
- request_module("%s", tempbuf);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (!ops) {
- netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- if (!*crypt || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
- if (!new_crypt) {
- 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(idx);
-
- if (!new_crypt->priv) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
- *crypt = new_crypt;
- }
-
- if (ext->key_len > 0 && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- netdev_info(dev, "key setting failed\n");
- ret = -EINVAL;
- goto done;
- }
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- ieee->crypt_info.tx_keyidx = idx;
- sec.active_key = idx;
- sec.flags |= SEC_ACTIVE_KEY;
- }
- if (ext->alg != IW_ENCODE_ALG_NONE) {
- sec.key_sizes[idx] = ext->key_len;
- sec.flags |= (1 << idx);
- if (ext->alg == IW_ENCODE_ALG_WEP) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
- /* Don't set sec level for group keys. */
- if (group_key)
- sec.flags &= ~SEC_LEVEL;
- }
-done:
- return ret;
-}
-EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
-
-int rtllib_wx_set_mlme(struct rtllib_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 i = 0;
- bool deauth = false;
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- if (ieee->link_state != MAC80211_LINKED)
- return -ENOLINK;
-
- mutex_lock(&ieee->wx_mutex);
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- deauth = true;
- fallthrough;
- case IW_MLME_DISASSOC:
- if (deauth)
- netdev_info(ieee->dev, "disauth packet !\n");
- else
- netdev_info(ieee->dev, "dis associate packet!\n");
-
- ieee->cannot_notify = true;
-
- send_disassociation(ieee, deauth, mlme->reason_code);
- rtllib_disassociate(ieee);
-
- ieee->wap_set = 0;
- for (i = 0; i < 6; i++)
- ieee->current_network.bssid[i] = 0x55;
-
- ieee->ssid_set = 0;
- ieee->current_network.ssid[0] = '\0';
- ieee->current_network.ssid_len = 0;
- break;
- default:
- mutex_unlock(&ieee->wx_mutex);
- return -EOPNOTSUPP;
- }
-
- mutex_unlock(&ieee->wx_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_mlme);
-
-int rtllib_wx_set_auth(struct rtllib_device *ieee,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- break;
- 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:
- ieee->tkip_countermeasures = data->value;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- ieee->drop_unencrypted = data->value;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (data->value & IW_AUTH_ALG_SHARED_KEY) {
- ieee->open_wep = 0;
- ieee->auth_mode = 1;
- } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- ieee->open_wep = 1;
- ieee->auth_mode = 0;
- } else if (data->value & IW_AUTH_ALG_LEAP) {
- ieee->open_wep = 1;
- ieee->auth_mode = 2;
- } else {
- return -EINVAL;
- }
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ieee->wpa_enabled = (data->value) ? 1 : 0;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = data->value;
- break;
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = data->value;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_auth);
-
-int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
-{
- u8 *buf;
- u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
-
- if (len > MAX_WPA_IE_LEN || (len && !ie))
- return -EINVAL;
-
- if (len) {
- eid = ie[0];
- if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2], wps_oui, 4))) {
- ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
- buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- ieee->wps_ie = buf;
- return 0;
- }
- }
- ieee->wps_ie_len = 0;
- kfree(ieee->wps_ie);
- ieee->wps_ie = NULL;
- if (len) {
- if (len != ie[1] + 2)
- return -EINVAL;
- buf = kmemdup(ie, len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = len;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
- return 0;
-}
-EXPORT_SYMBOL(rtllib_wx_set_gen_ie);
diff --git a/drivers/staging/rtl8712/TODO b/drivers/staging/rtl8712/TODO
index 847c8c41f4f7..5aed36efa7cb 100644
--- a/drivers/staging/rtl8712/TODO
+++ b/drivers/staging/rtl8712/TODO
@@ -1,6 +1,5 @@
TODO:
- merge Realtek's bugfixes and new features into the driver
-- switch to use LIB80211
- switch to use MAC80211
- checkpatch.pl fixes - only a few remain
diff --git a/drivers/staging/rtl8723bs/TODO b/drivers/staging/rtl8723bs/TODO
index 3d8f5a634a10..4c413f9d3df0 100644
--- a/drivers/staging/rtl8723bs/TODO
+++ b/drivers/staging/rtl8723bs/TODO
@@ -5,7 +5,6 @@ TODO:
- checkpatch.pl fixes - most of the remaining ones are lines too long. Many
of them will require refactoring
- merge Realtek's bugfixes and new features into the driver
-- switch to use LIB80211
- switch to use MAC80211
Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index 3dbeffc650d3..6c488b1e2624 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -593,7 +593,7 @@ vchiq_platform_init_state(struct vchiq_state *state)
{
struct vchiq_arm_state *platform_state;
- platform_state = kzalloc(sizeof(*platform_state), GFP_KERNEL);
+ platform_state = devm_kzalloc(state->dev, sizeof(*platform_state), GFP_KERNEL);
if (!platform_state)
return -ENOMEM;
@@ -1731,7 +1731,7 @@ static int vchiq_probe(struct platform_device *pdev)
return -ENOENT;
}
- mgmt = kzalloc(sizeof(*mgmt), GFP_KERNEL);
+ mgmt = devm_kzalloc(&pdev->dev, sizeof(*mgmt), GFP_KERNEL);
if (!mgmt)
return -ENOMEM;
@@ -1789,8 +1789,6 @@ static void vchiq_remove(struct platform_device *pdev)
arm_state = vchiq_platform_get_arm_state(&mgmt->state);
kthread_stop(arm_state->ka_thread);
-
- kfree(mgmt);
}
static struct platform_driver vchiq_driver = {
diff --git a/drivers/staging/vt6655/TODO b/drivers/staging/vt6655/TODO
index 529bc22cd608..27654bd0ff5d 100644
--- a/drivers/staging/vt6655/TODO
+++ b/drivers/staging/vt6655/TODO
@@ -8,7 +8,6 @@ TODO:
- abstract VT3253 chipset specific code
- add common vt665x infrastructure
- kill ttype.h
-- switch to use LIB80211
- switch to use MAC80211
- verify unsigned long usage for x86-64 arch
- reduce .data footprint
diff --git a/drivers/staging/vt6656/TODO b/drivers/staging/vt6656/TODO
index 876cdccb6948..cca78d2d3cfe 100644
--- a/drivers/staging/vt6656/TODO
+++ b/drivers/staging/vt6656/TODO
@@ -8,7 +8,6 @@ TODO:
- abstract VT3184 chipset specific code
- add common vt665x infrastructure
- kill ttype.h -- done
-- switch to use LIB80211
- switch to use MAC80211
- use kernel coding style
- sparse fixes
diff --git a/drivers/thermal/qcom/lmh.c b/drivers/thermal/qcom/lmh.c
index 5225b3621a56..d2d49264cf83 100644
--- a/drivers/thermal/qcom/lmh.c
+++ b/drivers/thermal/qcom/lmh.c
@@ -73,7 +73,14 @@ static struct irq_chip lmh_irq_chip = {
static int lmh_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
struct lmh_hw_data *lmh_data = d->host_data;
+ static struct lock_class_key lmh_lock_key;
+ static struct lock_class_key lmh_request_key;
+ /*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+ irq_set_lockdep_class(irq, &lmh_lock_key, &lmh_request_key);
irq_set_chip_and_handler(irq, &lmh_irq_chip, handle_simple_irq);
irq_set_chip_data(irq, lmh_data);
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index a4caf7899f8e..07e09897165f 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -99,18 +99,15 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
struct device_node *trips;
int ret, count;
+ *ntrips = 0;
+
trips = of_get_child_by_name(np, "trips");
- if (!trips) {
- pr_err("Failed to find 'trips' node\n");
- return ERR_PTR(-EINVAL);
- }
+ if (!trips)
+ return NULL;
count = of_get_child_count(trips);
- if (!count) {
- pr_err("No trip point defined\n");
- ret = -EINVAL;
- goto out_of_node_put;
- }
+ if (!count)
+ return NULL;
tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
if (!tt) {
@@ -133,7 +130,6 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
out_kfree:
kfree(tt);
- *ntrips = 0;
out_of_node_put:
of_node_put(trips);
@@ -401,11 +397,14 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
trips = thermal_of_trips_init(np, &ntrips);
if (IS_ERR(trips)) {
- pr_err("Failed to find trip points for %pOFn id=%d\n", sensor, id);
+ pr_err("Failed to parse trip points for %pOFn id=%d\n", sensor, id);
ret = PTR_ERR(trips);
goto out_of_node_put;
}
+ if (!trips)
+ pr_info("No trip points found for %pOFn id=%d\n", sensor, id);
+
ret = thermal_of_monitor_init(np, &delay, &pdelay);
if (ret) {
pr_err("Failed to initialize monitoring delays from %pOFn\n", np);
diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c
index 721319329afa..89d2919d0193 100644
--- a/drivers/thunderbolt/retimer.c
+++ b/drivers/thunderbolt/retimer.c
@@ -516,7 +516,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
*/
tb_retimer_set_inbound_sbtx(port);
- for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
+ for (max = 1, i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
/*
* Last retimer is true only for the last on-board
* retimer (the one connected directly to the Type-C
@@ -527,10 +527,13 @@ int tb_retimer_scan(struct tb_port *port, bool add)
last_idx = i;
else if (ret < 0)
break;
+
+ max = i;
}
- max = i;
ret = 0;
+ if (!IS_ENABLED(CONFIG_USB4_DEBUGFS_MARGINING))
+ max = min(last_idx, max);
/* Add retimers if they do not exist already */
for (i = 1; i <= max; i++) {
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 10e719dd837c..4f777788e917 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -288,6 +288,24 @@ static void tb_increase_tmu_accuracy(struct tb_tunnel *tunnel)
device_for_each_child(&sw->dev, NULL, tb_increase_switch_tmu_accuracy);
}
+static int tb_switch_tmu_hifi_uni_required(struct device *dev, void *not_used)
+{
+ struct tb_switch *sw = tb_to_switch(dev);
+
+ if (sw && tb_switch_tmu_is_enabled(sw) &&
+ tb_switch_tmu_is_configured(sw, TB_SWITCH_TMU_MODE_HIFI_UNI))
+ return 1;
+
+ return device_for_each_child(dev, NULL,
+ tb_switch_tmu_hifi_uni_required);
+}
+
+static bool tb_tmu_hifi_uni_required(struct tb *tb)
+{
+ return device_for_each_child(&tb->dev, NULL,
+ tb_switch_tmu_hifi_uni_required) == 1;
+}
+
static int tb_enable_tmu(struct tb_switch *sw)
{
int ret;
@@ -302,12 +320,30 @@ static int tb_enable_tmu(struct tb_switch *sw)
ret = tb_switch_tmu_configure(sw,
TB_SWITCH_TMU_MODE_MEDRES_ENHANCED_UNI);
if (ret == -EOPNOTSUPP) {
- if (tb_switch_clx_is_enabled(sw, TB_CL1))
- ret = tb_switch_tmu_configure(sw,
- TB_SWITCH_TMU_MODE_LOWRES);
- else
- ret = tb_switch_tmu_configure(sw,
- TB_SWITCH_TMU_MODE_HIFI_BI);
+ if (tb_switch_clx_is_enabled(sw, TB_CL1)) {
+ /*
+ * Figure out uni-directional HiFi TMU requirements
+ * currently in the domain. If there are no
+ * uni-directional HiFi requirements we can put the TMU
+ * into LowRes mode.
+ *
+ * Deliberately skip bi-directional HiFi links
+ * as these work independently of other links
+ * (and they do not allow any CL states anyway).
+ */
+ if (tb_tmu_hifi_uni_required(sw->tb))
+ ret = tb_switch_tmu_configure(sw,
+ TB_SWITCH_TMU_MODE_HIFI_UNI);
+ else
+ ret = tb_switch_tmu_configure(sw,
+ TB_SWITCH_TMU_MODE_LOWRES);
+ } else {
+ ret = tb_switch_tmu_configure(sw, TB_SWITCH_TMU_MODE_HIFI_BI);
+ }
+
+ /* If not supported, fallback to bi-directional HiFi */
+ if (ret == -EOPNOTSUPP)
+ ret = tb_switch_tmu_configure(sw, TB_SWITCH_TMU_MODE_HIFI_BI);
}
if (ret)
return ret;
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 0a9b4aeb3fa1..402fdf8b1cde 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -48,7 +48,7 @@ enum usb4_ba_index {
/* Delays in us used with usb4_port_wait_for_bit() */
#define USB4_PORT_DELAY 50
-#define USB4_PORT_SB_DELAY 5000
+#define USB4_PORT_SB_DELAY 1000
static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode,
u32 *metadata, u8 *status,
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index a63dcf48e59d..abbe7135a977 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -8219,7 +8219,7 @@ static void ufshcd_update_rtc(struct ufs_hba *hba)
err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_SECONDS_PASSED,
0, 0, &val);
- ufshcd_rpm_put_sync(hba);
+ ufshcd_rpm_put(hba);
if (err)
dev_err(hba->dev, "%s: Failed to update rtc %d\n", __func__, err);
@@ -8636,6 +8636,14 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
ufshcd_init_clk_scaling_sysfs(hba);
}
+ /*
+ * The RTC update code accesses the hba->ufs_device_wlun->sdev_gendev
+ * pointer and hence must only be started after the WLUN pointer has
+ * been initialized by ufshcd_scsi_add_wlus().
+ */
+ schedule_delayed_work(&hba->ufs_rtc_update_work,
+ msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
+
ufs_bsg_probe(hba);
scsi_scan_host(hba->host);
@@ -8795,8 +8803,6 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params)
ufshcd_force_reset_auto_bkops(hba);
ufshcd_set_timestamp_attr(hba);
- schedule_delayed_work(&hba->ufs_rtc_update_work,
- msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS));
/* Gear up to HS gear if supported */
if (hba->max_pwr_info.is_valid) {
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 21585ed89ef8..03c22114214b 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -170,11 +170,11 @@ static int usb_acpi_add_usb4_devlink(struct usb_device *udev)
struct fwnode_handle *nhi_fwnode __free(fwnode_handle) =
fwnode_find_reference(dev_fwnode(&port_dev->dev), "usb4-host-interface", 0);
- if (IS_ERR(nhi_fwnode))
+ if (IS_ERR(nhi_fwnode) || !nhi_fwnode->dev)
return 0;
link = device_link_add(&port_dev->child->dev, nhi_fwnode->dev,
- DL_FLAG_AUTOREMOVE_CONSUMER |
+ DL_FLAG_STATELESS |
DL_FLAG_RPM_ACTIVE |
DL_FLAG_PM_RUNTIME);
if (!link) {
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 68226defdc60..4d73fae80b12 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -23,7 +23,6 @@ static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
p->max_transfer_size = 65535;
p->max_packet_count = 511;
p->ahbcfg = 0x10;
- p->no_clock_gating = true;
}
static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 427e5660f87c..98114c2827c0 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -2342,10 +2342,18 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
u32 reg;
int i;
- dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
- DWC3_GUSB2PHYCFG_SUSPHY) ||
- (dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)) &
- DWC3_GUSB3PIPECTL_SUSPHY);
+ if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
+ dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+ DWC3_GUSB2PHYCFG_SUSPHY) ||
+ (dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)) &
+ DWC3_GUSB3PIPECTL_SUSPHY);
+ /*
+ * TI AM62 platform requires SUSPHY to be
+ * enabled for system suspend to work.
+ */
+ if (!dwc->susphy_state)
+ dwc3_enable_susphy(dwc, true);
+ }
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -2398,15 +2406,6 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
break;
}
- if (!PMSG_IS_AUTO(msg)) {
- /*
- * TI AM62 platform requires SUSPHY to be
- * enabled for system suspend to work.
- */
- if (!dwc->susphy_state)
- dwc3_enable_susphy(dwc, true);
- }
-
return 0;
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7e538194a0a4..cb07cee9ed0c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -640,7 +640,7 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
pm_runtime_put_noidle(&dev->dev);
if (pci_choose_state(dev, PMSG_SUSPEND) == PCI_D0)
- pm_runtime_forbid(&dev->dev);
+ pm_runtime_get(&dev->dev);
else if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
pm_runtime_allow(&dev->dev);
@@ -683,7 +683,9 @@ void xhci_pci_remove(struct pci_dev *dev)
xhci->xhc_state |= XHCI_STATE_REMOVING;
- if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
+ if (pci_choose_state(dev, PMSG_SUSPEND) == PCI_D0)
+ pm_runtime_put(&dev->dev);
+ else if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
pm_runtime_forbid(&dev->dev);
if (xhci->shared_hcd) {
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b6eb928e260f..928b93ad1ee8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1718,6 +1718,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic);
+ cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
+
+ /* If CMD ring stopped we own the trbs between enqueue and dequeue */
+ if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
+ complete_all(&xhci->cmd_ring_stop_completion);
+ return;
+ }
+
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
cmd_trb);
/*
@@ -1734,14 +1742,6 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
cancel_delayed_work(&xhci->cmd_timer);
- cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
-
- /* If CMD ring stopped we own the trbs between enqueue and dequeue */
- if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
- complete_all(&xhci->cmd_ring_stop_completion);
- return;
- }
-
if (cmd->command_trb != xhci->cmd_ring->dequeue) {
xhci_err(xhci,
"Command completion event does not match command\n");
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
index d54283fd026b..05b6e7e52e02 100644
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -293,8 +293,6 @@ static int sunxi_musb_exit(struct musb *musb)
if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
sunxi_sram_release(musb->controller->parent);
- devm_usb_put_phy(glue->dev, glue->xceiv);
-
return 0;
}
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index 06e0fb23566c..06f789097989 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -628,7 +628,7 @@ void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
{
int r;
- r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
+ r = devres_release(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
}
EXPORT_SYMBOL_GPL(devm_usb_put_phy);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index c7d6b5e3f898..28c71d99e857 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -770,11 +770,12 @@ static void edge_bulk_out_data_callback(struct urb *urb)
static void edge_bulk_out_cmd_callback(struct urb *urb)
{
struct edgeport_port *edge_port = urb->context;
+ struct device *dev = &urb->dev->dev;
int status = urb->status;
atomic_dec(&CmdUrbs);
- dev_dbg(&urb->dev->dev, "%s - FREE URB %p (outstanding %d)\n",
- __func__, urb, atomic_read(&CmdUrbs));
+ dev_dbg(dev, "%s - FREE URB %p (outstanding %d)\n", __func__, urb,
+ atomic_read(&CmdUrbs));
/* clean up the transfer buffer */
@@ -784,8 +785,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
usb_free_urb(urb);
if (status) {
- dev_dbg(&urb->dev->dev,
- "%s - nonzero write bulk status received: %d\n",
+ dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
__func__, status);
return;
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 4f18f189f309..9ba5584061c8 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -251,6 +251,7 @@ static void option_instat_callback(struct urb *urb);
#define QUECTEL_VENDOR_ID 0x2c7c
/* These Quectel products use Quectel's vendor ID */
#define QUECTEL_PRODUCT_EC21 0x0121
+#define QUECTEL_PRODUCT_RG650V 0x0122
#define QUECTEL_PRODUCT_EM061K_LTA 0x0123
#define QUECTEL_PRODUCT_EM061K_LMS 0x0124
#define QUECTEL_PRODUCT_EC25 0x0125
@@ -1273,6 +1274,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG912Y, 0xff, 0, 0) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG916Q, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
@@ -2320,6 +2323,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0111, 0xff) }, /* Fibocom FM160 (MBIM mode) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0xff, 0x30) }, /* Fibocom FG132 Diag */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0xff, 0x40) }, /* Fibocom FG132 AT */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0, 0) }, /* Fibocom FG132 NMEA */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0115, 0xff), /* Fibocom FM135 (laptop MBIM) */
.driver_info = RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index c7de9585feb2..13c664317a05 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -166,6 +166,8 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */
{DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */
{DEVICE_SWI(0x1199, 0x90d2)}, /* Sierra Wireless EM9191 QDL */
+ {DEVICE_SWI(0x1199, 0x90e4)}, /* Sierra Wireless EM86xx QDL*/
+ {DEVICE_SWI(0x1199, 0x90e5)}, /* Sierra Wireless EM86xx */
{DEVICE_SWI(0x1199, 0xc080)}, /* Sierra Wireless EM7590 QDL */
{DEVICE_SWI(0x1199, 0xc081)}, /* Sierra Wireless EM7590 */
{DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index d61b4c74648d..58f40156de56 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -2293,7 +2293,7 @@ void typec_port_register_altmodes(struct typec_port *port,
const struct typec_altmode_ops *ops, void *drvdata,
struct typec_altmode **altmodes, size_t n)
{
- struct fwnode_handle *altmodes_node, *child;
+ struct fwnode_handle *child;
struct typec_altmode_desc desc;
struct typec_altmode *alt;
size_t index = 0;
@@ -2301,7 +2301,9 @@ void typec_port_register_altmodes(struct typec_port *port,
u32 vdo;
int ret;
- altmodes_node = device_get_named_child_node(&port->dev, "altmodes");
+ struct fwnode_handle *altmodes_node __free(fwnode_handle) =
+ device_get_named_child_node(&port->dev, "altmodes");
+
if (!altmodes_node)
return; /* No altmodes specified */
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
index 501eddb294e4..b80eb2d78d88 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
@@ -93,8 +93,10 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
return -EINVAL;
bridge_dev = devm_drm_dp_hpd_bridge_alloc(tcpm->dev, to_of_node(tcpm->tcpc.fwnode));
- if (IS_ERR(bridge_dev))
- return PTR_ERR(bridge_dev);
+ if (IS_ERR(bridge_dev)) {
+ ret = PTR_ERR(bridge_dev);
+ goto fwnode_remove;
+ }
tcpm->tcpm_port = tcpm_register_port(tcpm->dev, &tcpm->tcpc);
if (IS_ERR(tcpm->tcpm_port)) {
@@ -123,7 +125,7 @@ port_stop:
port_unregister:
tcpm_unregister_port(tcpm->tcpm_port);
fwnode_remove:
- fwnode_remove_software_node(tcpm->tcpc.fwnode);
+ fwnode_handle_put(tcpm->tcpc.fwnode);
return ret;
}
@@ -135,7 +137,7 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev)
tcpm->pdphy_stop(tcpm);
tcpm->port_stop(tcpm);
tcpm_unregister_port(tcpm->tcpm_port);
- fwnode_remove_software_node(tcpm->tcpc.fwnode);
+ fwnode_handle_put(tcpm->tcpc.fwnode);
}
static const struct pmic_typec_resources pm8150b_typec_res = {
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
index 5b7f52b74a40..726423684bae 100644
--- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
+++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
@@ -227,6 +227,10 @@ qcom_pmic_typec_pdphy_pd_transmit_payload(struct pmic_typec_pdphy *pmic_typec_pd
spin_lock_irqsave(&pmic_typec_pdphy->lock, flags);
+ hdr_len = sizeof(msg->header);
+ txbuf_len = pd_header_cnt_le(msg->header) * 4;
+ txsize_len = hdr_len + txbuf_len - 1;
+
ret = regmap_read(pmic_typec_pdphy->regmap,
pmic_typec_pdphy->base + USB_PDPHY_RX_ACKNOWLEDGE_REG,
&val);
@@ -244,10 +248,6 @@ qcom_pmic_typec_pdphy_pd_transmit_payload(struct pmic_typec_pdphy *pmic_typec_pd
if (ret)
goto done;
- hdr_len = sizeof(msg->header);
- txbuf_len = pd_header_cnt_le(msg->header) * 4;
- txsize_len = hdr_len + txbuf_len - 1;
-
/* Write message header sizeof(u16) to USB_PDPHY_TX_BUFFER_HDR_REG */
ret = regmap_bulk_write(pmic_typec_pdphy->regmap,
pmic_typec_pdphy->base + USB_PDPHY_TX_BUFFER_HDR_REG,
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index fc619478200f..7ae341a40342 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -4515,7 +4515,8 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
return ERROR_RECOVERY;
if (port->pwr_role == TYPEC_SOURCE)
return SRC_UNATTACHED;
- if (port->state == SNK_WAIT_CAPABILITIES_TIMEOUT)
+ if (port->state == SNK_WAIT_CAPABILITIES ||
+ port->state == SNK_WAIT_CAPABILITIES_TIMEOUT)
return SNK_READY;
return SNK_UNATTACHED;
}
@@ -5043,8 +5044,11 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, SNK_SOFT_RESET,
PD_T_SINK_WAIT_CAP);
} else {
- tcpm_set_state(port, SNK_WAIT_CAPABILITIES_TIMEOUT,
- PD_T_SINK_WAIT_CAP);
+ if (!port->self_powered)
+ upcoming_state = SNK_WAIT_CAPABILITIES_TIMEOUT;
+ else
+ upcoming_state = hard_reset_state(port);
+ tcpm_set_state(port, upcoming_state, PD_T_SINK_WAIT_CAP);
}
break;
case SNK_WAIT_CAPABILITIES_TIMEOUT:
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index ba58d11907bc..bccfc03b5986 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -482,6 +482,8 @@ static void ucsi_ccg_update_set_new_cam_cmd(struct ucsi_ccg *uc,
port = uc->orig;
new_cam = UCSI_SET_NEW_CAM_GET_AM(*cmd);
+ if (new_cam >= ARRAY_SIZE(uc->updated))
+ return;
new_port = &uc->updated[new_cam];
cam = new_port->linked_idx;
enter_new_mode = UCSI_SET_NEW_CAM_ENTER(*cmd);
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c
index 472daa588a9d..d5507b63b6cd 100644
--- a/drivers/vdpa/ifcvf/ifcvf_base.c
+++ b/drivers/vdpa/ifcvf/ifcvf_base.c
@@ -108,7 +108,7 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
u32 i;
ret = pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pos);
- if (ret < 0) {
+ if (ret) {
IFCVF_ERR(pdev, "Failed to read PCI capability list\n");
return -EIO;
}
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index 2dd21e0b399e..7d0c83b5b071 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -373,7 +373,7 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
struct page *pg;
unsigned int nsg;
int sglen;
- u64 pa;
+ u64 pa, offset;
u64 paend;
struct scatterlist *sg;
struct device *dma = mvdev->vdev.dma_dev;
@@ -396,8 +396,10 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr
sg = mr->sg_head.sgl;
for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1);
map; map = vhost_iotlb_itree_next(map, mr->start, mr->end - 1)) {
- paend = map->addr + maplen(map, mr);
- for (pa = map->addr; pa < paend; pa += sglen) {
+ offset = mr->start > map->start ? mr->start - map->start : 0;
+ pa = map->addr + offset;
+ paend = map->addr + offset + maplen(map, mr);
+ for (; pa < paend; pa += sglen) {
pg = pfn_to_page(__phys_to_pfn(pa));
if (!sg) {
mlx5_vdpa_warn(mvdev, "sg null. start 0x%llx, end 0x%llx\n",
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index dee019977716..5f581e71e201 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -3963,28 +3963,28 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
mvdev->vdev.dma_dev = &mdev->pdev->dev;
err = mlx5_vdpa_alloc_resources(&ndev->mvdev);
if (err)
- goto err_mpfs;
+ goto err_alloc;
err = mlx5_vdpa_init_mr_resources(mvdev);
if (err)
- goto err_res;
+ goto err_alloc;
if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
err = mlx5_vdpa_create_dma_mr(mvdev);
if (err)
- goto err_mr_res;
+ goto err_alloc;
}
err = alloc_fixed_resources(ndev);
if (err)
- goto err_mr;
+ goto err_alloc;
ndev->cvq_ent.mvdev = mvdev;
INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler);
mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq");
if (!mvdev->wq) {
err = -ENOMEM;
- goto err_res2;
+ goto err_alloc;
}
mvdev->vdev.mdev = &mgtdev->mgtdev;
@@ -4010,17 +4010,6 @@ err_setup_vq_res:
_vdpa_unregister_device(&mvdev->vdev);
err_reg:
destroy_workqueue(mvdev->wq);
-err_res2:
- free_fixed_resources(ndev);
-err_mr:
- mlx5_vdpa_clean_mrs(mvdev);
-err_mr_res:
- mlx5_vdpa_destroy_mr_resources(mvdev);
-err_res:
- mlx5_vdpa_free_resources(&ndev->mvdev);
-err_mpfs:
- if (!is_zero_ether_addr(config->mac))
- mlx5_mpfs_del_mac(pfmdev, config->mac);
err_alloc:
put_device(&mvdev->vdev.dev);
return err;
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
index 99428a04068d..c8b74980dbd1 100644
--- a/drivers/vdpa/solidrun/snet_main.c
+++ b/drivers/vdpa/solidrun/snet_main.c
@@ -555,7 +555,7 @@ static const struct vdpa_config_ops snet_config_ops = {
static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
{
- char name[50];
+ char *name;
int ret, i, mask = 0;
/* We don't know which BAR will be used to communicate..
* We will map every bar with len > 0.
@@ -573,7 +573,10 @@ static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
return -ENODEV;
}
- snprintf(name, sizeof(name), "psnet[%s]-bars", pci_name(pdev));
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "psnet[%s]-bars", pci_name(pdev));
+ if (!name)
+ return -ENOMEM;
+
ret = pcim_iomap_regions(pdev, mask, name);
if (ret) {
SNET_ERR(pdev, "Failed to request and map PCI BARs\n");
@@ -590,10 +593,13 @@ static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
static int snet_open_vf_bar(struct pci_dev *pdev, struct snet *snet)
{
- char name[50];
+ char *name;
int ret;
- snprintf(name, sizeof(name), "snet[%s]-bar", pci_name(pdev));
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "snet[%s]-bars", pci_name(pdev));
+ if (!name)
+ return -ENOMEM;
+
/* Request and map BAR */
ret = pcim_iomap_regions(pdev, BIT(snet->psnet->cfg.vf_bar), name);
if (ret) {
diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c
index ac4ab22f7d8b..16380764275e 100644
--- a/drivers/vdpa/virtio_pci/vp_vdpa.c
+++ b/drivers/vdpa/virtio_pci/vp_vdpa.c
@@ -612,7 +612,11 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto mdev_err;
}
- mdev_id = kzalloc(sizeof(struct virtio_device_id), GFP_KERNEL);
+ /*
+ * id_table should be a null terminated array, so allocate one additional
+ * entry here, see vdpa_mgmtdev_get_classes().
+ */
+ mdev_id = kcalloc(2, sizeof(struct virtio_device_id), GFP_KERNEL);
if (!mdev_id) {
err = -ENOMEM;
goto mdev_id_err;
@@ -632,8 +636,8 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto probe_err;
}
- mdev_id->device = mdev->id.device;
- mdev_id->vendor = mdev->id.vendor;
+ mdev_id[0].device = mdev->id.device;
+ mdev_id[0].vendor = mdev->id.vendor;
mgtdev->id_table = mdev_id;
mgtdev->max_supported_vqs = vp_modern_get_num_queues(mdev);
mgtdev->supported_features = vp_modern_get_features(mdev);
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index f16279351db5..9ad37c012189 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1325,7 +1325,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
vqs[VHOST_NET_VQ_RX]);
f->private_data = n;
- n->pf_cache.va = NULL;
+ page_frag_cache_init(&n->pf_cache);
return 0;
}
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index ea36c6956bf3..de035071fedb 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1236,7 +1236,6 @@ config FB_3DFX_I2C
config FB_VOODOO1
tristate "3Dfx Voodoo Graphics (sst1) support"
depends on FB && PCI
- depends on FB_DEVICE
select FB_IOMEM_HELPERS
help
Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or
@@ -1374,6 +1373,7 @@ config FB_VT8500
config FB_WM8505
bool "Wondermedia WM8xxx-series frame buffer support"
depends on (FB = y) && HAS_IOMEM && (ARCH_VT8500 || COMPILE_TEST)
+ select FB_IOMEM_FOPS
select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
select FB_SYS_IMAGEBLIT
@@ -1660,19 +1660,6 @@ config FB_SH7760
and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for
panels <= 320 pixel horizontal resolution.
-config FB_DA8XX
- tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support"
- depends on FB && HAVE_CLK && HAS_IOMEM
- depends on ARCH_DAVINCI_DA8XX || SOC_AM33XX || COMPILE_TEST
- select FB_CFB_REV_PIXELS_IN_BYTE
- select FB_IOMEM_HELPERS
- select FB_MODE_HELPERS
- select VIDEOMODE_HELPERS
- help
- This is the frame buffer device driver for the TI LCD controller
- found on DA8xx/OMAP-L1xx/AM335x SoCs.
- If unsure, say N.
-
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 3eecd51267fa..b3d12f977c06 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -121,7 +121,6 @@ obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
-obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
diff --git a/drivers/video/fbdev/bw2.c b/drivers/video/fbdev/bw2.c
index 4a64940e0c00..e757462af0a6 100644
--- a/drivers/video/fbdev/bw2.c
+++ b/drivers/video/fbdev/bw2.c
@@ -147,7 +147,7 @@ bw2_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map bw2_mmap_map[] = {
+static const struct sbus_mmap_map bw2_mmap_map[] = {
{
.size = SBUS_MMAP_FBSIZE(1)
},
diff --git a/drivers/video/fbdev/cg14.c b/drivers/video/fbdev/cg14.c
index 430e1a7b352b..5389f8f07346 100644
--- a/drivers/video/fbdev/cg14.c
+++ b/drivers/video/fbdev/cg14.c
@@ -360,7 +360,7 @@ static void cg14_init_fix(struct fb_info *info, int linebytes,
info->fix.accel = FB_ACCEL_SUN_CG14;
}
-static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] = {
+static const struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] = {
{
.voff = CG14_REGS,
.poff = 0x80000000,
diff --git a/drivers/video/fbdev/cg3.c b/drivers/video/fbdev/cg3.c
index e4c53c6632ba..a58a483014e6 100644
--- a/drivers/video/fbdev/cg3.c
+++ b/drivers/video/fbdev/cg3.c
@@ -209,7 +209,7 @@ static int cg3_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map cg3_mmap_map[] = {
+static const struct sbus_mmap_map cg3_mmap_map[] = {
{
.voff = CG3_MMAP_OFFSET,
.poff = CG3_RAM_OFFSET,
diff --git a/drivers/video/fbdev/cg6.c b/drivers/video/fbdev/cg6.c
index 0b60df51e7bc..56d74468040a 100644
--- a/drivers/video/fbdev/cg6.c
+++ b/drivers/video/fbdev/cg6.c
@@ -545,7 +545,7 @@ static int cg6_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map cg6_mmap_map[] = {
+static const struct sbus_mmap_map cg6_mmap_map[] = {
{
.voff = CG6_FBC,
.poff = CG6_FBC_OFFSET,
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c
deleted file mode 100644
index fad1e13c6332..000000000000
--- a/drivers/video/fbdev/da8xx-fb.c
+++ /dev/null
@@ -1,1665 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2008-2009 MontaVista Software Inc.
- * Copyright (C) 2008-2009 Texas Instruments Inc
- *
- * Based on the LCD driver for TI Avalanche processors written by
- * Ajay Singh and Shalom Hai.
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fb.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/uaccess.h>
-#include <linux/pm_runtime.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/console.h>
-#include <linux/regulator/consumer.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/lcm.h>
-#include <video/da8xx-fb.h>
-#include <asm/div64.h>
-
-#define DRIVER_NAME "da8xx_lcdc"
-
-#define LCD_VERSION_1 1
-#define LCD_VERSION_2 2
-
-/* LCD Status Register */
-#define LCD_END_OF_FRAME1 BIT(9)
-#define LCD_END_OF_FRAME0 BIT(8)
-#define LCD_PL_LOAD_DONE BIT(6)
-#define LCD_FIFO_UNDERFLOW BIT(5)
-#define LCD_SYNC_LOST BIT(2)
-#define LCD_FRAME_DONE BIT(0)
-
-/* LCD DMA Control Register */
-#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
-#define LCD_DMA_BURST_1 0x0
-#define LCD_DMA_BURST_2 0x1
-#define LCD_DMA_BURST_4 0x2
-#define LCD_DMA_BURST_8 0x3
-#define LCD_DMA_BURST_16 0x4
-#define LCD_V1_END_OF_FRAME_INT_ENA BIT(2)
-#define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8)
-#define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9)
-#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0)
-
-/* LCD Control Register */
-#define LCD_CLK_DIVISOR(x) ((x) << 8)
-#define LCD_RASTER_MODE 0x01
-
-/* LCD Raster Control Register */
-#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20)
-#define PALETTE_AND_DATA 0x00
-#define PALETTE_ONLY 0x01
-#define DATA_ONLY 0x02
-
-#define LCD_MONO_8BIT_MODE BIT(9)
-#define LCD_RASTER_ORDER BIT(8)
-#define LCD_TFT_MODE BIT(7)
-#define LCD_V1_UNDERFLOW_INT_ENA BIT(6)
-#define LCD_V2_UNDERFLOW_INT_ENA BIT(5)
-#define LCD_V1_PL_INT_ENA BIT(4)
-#define LCD_V2_PL_INT_ENA BIT(6)
-#define LCD_MONOCHROME_MODE BIT(1)
-#define LCD_RASTER_ENABLE BIT(0)
-#define LCD_TFT_ALT_ENABLE BIT(23)
-#define LCD_STN_565_ENABLE BIT(24)
-#define LCD_V2_DMA_CLK_EN BIT(2)
-#define LCD_V2_LIDD_CLK_EN BIT(1)
-#define LCD_V2_CORE_CLK_EN BIT(0)
-#define LCD_V2_LPP_B10 26
-#define LCD_V2_TFT_24BPP_MODE BIT(25)
-#define LCD_V2_TFT_24BPP_UNPACK BIT(26)
-
-/* LCD Raster Timing 2 Register */
-#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
-#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8)
-#define LCD_SYNC_CTRL BIT(25)
-#define LCD_SYNC_EDGE BIT(24)
-#define LCD_INVERT_PIXEL_CLOCK BIT(22)
-#define LCD_INVERT_LINE_CLOCK BIT(21)
-#define LCD_INVERT_FRAME_CLOCK BIT(20)
-
-/* LCD Block */
-#define LCD_PID_REG 0x0
-#define LCD_CTRL_REG 0x4
-#define LCD_STAT_REG 0x8
-#define LCD_RASTER_CTRL_REG 0x28
-#define LCD_RASTER_TIMING_0_REG 0x2C
-#define LCD_RASTER_TIMING_1_REG 0x30
-#define LCD_RASTER_TIMING_2_REG 0x34
-#define LCD_DMA_CTRL_REG 0x40
-#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44
-#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48
-#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C
-#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50
-
-/* Interrupt Registers available only in Version 2 */
-#define LCD_RAW_STAT_REG 0x58
-#define LCD_MASKED_STAT_REG 0x5c
-#define LCD_INT_ENABLE_SET_REG 0x60
-#define LCD_INT_ENABLE_CLR_REG 0x64
-#define LCD_END_OF_INT_IND_REG 0x68
-
-/* Clock registers available only on Version 2 */
-#define LCD_CLK_ENABLE_REG 0x6c
-#define LCD_CLK_RESET_REG 0x70
-#define LCD_CLK_MAIN_RESET BIT(3)
-
-#define LCD_NUM_BUFFERS 2
-
-#define PALETTE_SIZE 256
-
-#define CLK_MIN_DIV 2
-#define CLK_MAX_DIV 255
-
-static void __iomem *da8xx_fb_reg_base;
-static unsigned int lcd_revision;
-static irq_handler_t lcdc_irq_handler;
-static wait_queue_head_t frame_done_wq;
-static int frame_done_flag;
-
-static unsigned int lcdc_read(unsigned int addr)
-{
- return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr));
-}
-
-static void lcdc_write(unsigned int val, unsigned int addr)
-{
- __raw_writel(val, da8xx_fb_reg_base + (addr));
-}
-
-struct da8xx_fb_par {
- struct device *dev;
- dma_addr_t p_palette_base;
- unsigned char *v_palette_base;
- dma_addr_t vram_phys;
- unsigned long vram_size;
- void *vram_virt;
- unsigned int dma_start;
- unsigned int dma_end;
- struct clk *lcdc_clk;
- int irq;
- unsigned int palette_sz;
- int blank;
- wait_queue_head_t vsync_wait;
- int vsync_flag;
- int vsync_timeout;
- spinlock_t lock_for_chan_update;
-
- /*
- * LCDC has 2 ping pong DMA channels, channel 0
- * and channel 1.
- */
- unsigned int which_dma_channel_done;
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
-#endif
- unsigned int lcdc_clk_rate;
- struct regulator *lcd_supply;
- u32 pseudo_palette[16];
- struct fb_videomode mode;
- struct lcd_ctrl_config cfg;
-};
-
-static struct fb_var_screeninfo da8xx_fb_var;
-
-static struct fb_fix_screeninfo da8xx_fb_fix = {
- .id = "DA8xx FB Drv",
- .type = FB_TYPE_PACKED_PIXELS,
- .type_aux = 0,
- .visual = FB_VISUAL_PSEUDOCOLOR,
- .xpanstep = 0,
- .ypanstep = 1,
- .ywrapstep = 0,
- .accel = FB_ACCEL_NONE
-};
-
-static struct fb_videomode known_lcd_panels[] = {
- /* Sharp LCD035Q3DG01 */
- [0] = {
- .name = "Sharp_LCD035Q3DG01",
- .xres = 320,
- .yres = 240,
- .pixclock = KHZ2PICOS(4607),
- .left_margin = 6,
- .right_margin = 8,
- .upper_margin = 2,
- .lower_margin = 2,
- .hsync_len = 0,
- .vsync_len = 0,
- .sync = FB_SYNC_CLK_INVERT,
- },
- /* Sharp LK043T1DG01 */
- [1] = {
- .name = "Sharp_LK043T1DG01",
- .xres = 480,
- .yres = 272,
- .pixclock = KHZ2PICOS(7833),
- .left_margin = 2,
- .right_margin = 2,
- .upper_margin = 2,
- .lower_margin = 2,
- .hsync_len = 41,
- .vsync_len = 10,
- .sync = 0,
- .flag = 0,
- },
- [2] = {
- /* Hitachi SP10Q010 */
- .name = "SP10Q010",
- .xres = 320,
- .yres = 240,
- .pixclock = KHZ2PICOS(7833),
- .left_margin = 10,
- .right_margin = 10,
- .upper_margin = 10,
- .lower_margin = 10,
- .hsync_len = 10,
- .vsync_len = 10,
- .sync = 0,
- .flag = 0,
- },
- [3] = {
- /* Densitron 84-0023-001T */
- .name = "Densitron_84-0023-001T",
- .xres = 320,
- .yres = 240,
- .pixclock = KHZ2PICOS(6400),
- .left_margin = 0,
- .right_margin = 0,
- .upper_margin = 0,
- .lower_margin = 0,
- .hsync_len = 30,
- .vsync_len = 3,
- .sync = 0,
- },
-};
-
-static bool da8xx_fb_is_raster_enabled(void)
-{
- return !!(lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE);
-}
-
-/* Enable the Raster Engine of the LCD Controller */
-static void lcd_enable_raster(void)
-{
- u32 reg;
-
- /* Put LCDC in reset for several cycles */
- if (lcd_revision == LCD_VERSION_2)
- /* Write 1 to reset LCDC */
- lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
- mdelay(1);
-
- /* Bring LCDC out of reset */
- if (lcd_revision == LCD_VERSION_2)
- lcdc_write(0, LCD_CLK_RESET_REG);
- mdelay(1);
-
- /* Above reset sequence doesnot reset register context */
- reg = lcdc_read(LCD_RASTER_CTRL_REG);
- if (!(reg & LCD_RASTER_ENABLE))
- lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
-}
-
-/* Disable the Raster Engine of the LCD Controller */
-static void lcd_disable_raster(enum da8xx_frame_complete wait_for_frame_done)
-{
- u32 reg;
- int ret;
-
- reg = lcdc_read(LCD_RASTER_CTRL_REG);
- if (reg & LCD_RASTER_ENABLE)
- lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
- else
- /* return if already disabled */
- return;
-
- if ((wait_for_frame_done == DA8XX_FRAME_WAIT) &&
- (lcd_revision == LCD_VERSION_2)) {
- frame_done_flag = 0;
- ret = wait_event_interruptible_timeout(frame_done_wq,
- frame_done_flag != 0,
- msecs_to_jiffies(50));
- if (ret == 0)
- pr_err("LCD Controller timed out\n");
- }
-}
-
-static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
-{
- u32 start;
- u32 end;
- u32 reg_ras;
- u32 reg_dma;
- u32 reg_int;
-
- /* init reg to clear PLM (loading mode) fields */
- reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
- reg_ras &= ~(3 << 20);
-
- reg_dma = lcdc_read(LCD_DMA_CTRL_REG);
-
- if (load_mode == LOAD_DATA) {
- start = par->dma_start;
- end = par->dma_end;
-
- reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
- if (lcd_revision == LCD_VERSION_1) {
- reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
- } else {
- reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
- LCD_V2_END_OF_FRAME0_INT_ENA |
- LCD_V2_END_OF_FRAME1_INT_ENA |
- LCD_FRAME_DONE | LCD_SYNC_LOST;
- lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
- }
- reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
-
- lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- } else if (load_mode == LOAD_PALETTE) {
- start = par->p_palette_base;
- end = start + par->palette_sz - 1;
-
- reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
-
- if (lcd_revision == LCD_VERSION_1) {
- reg_ras |= LCD_V1_PL_INT_ENA;
- } else {
- reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
- LCD_V2_PL_INT_ENA;
- lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
- }
-
- lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- }
-
- lcdc_write(reg_dma, LCD_DMA_CTRL_REG);
- lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
-
- /*
- * The Raster enable bit must be set after all other control fields are
- * set.
- */
- lcd_enable_raster();
-}
-
-/* Configure the Burst Size and fifo threhold of DMA */
-static int lcd_cfg_dma(int burst_size, int fifo_th)
-{
- u32 reg;
-
- reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001;
- switch (burst_size) {
- case 1:
- reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
- break;
- case 2:
- reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
- break;
- case 4:
- reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
- break;
- case 8:
- reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
- break;
- case 16:
- default:
- reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
- break;
- }
-
- reg |= (fifo_th << 8);
-
- lcdc_write(reg, LCD_DMA_CTRL_REG);
-
- return 0;
-}
-
-static void lcd_cfg_ac_bias(int period, int transitions_per_int)
-{
- u32 reg;
-
- /* Set the AC Bias Period and Number of Transisitons per Interrupt */
- reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000;
- reg |= LCD_AC_BIAS_FREQUENCY(period) |
- LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
- lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
-}
-
-static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
- int front_porch)
-{
- u32 reg;
-
- reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0x3ff;
- reg |= (((back_porch-1) & 0xff) << 24)
- | (((front_porch-1) & 0xff) << 16)
- | (((pulse_width-1) & 0x3f) << 10);
- lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
-
- /*
- * LCDC Version 2 adds some extra bits that increase the allowable
- * size of the horizontal timing registers.
- * remember that the registers use 0 to represent 1 so all values
- * that get set into register need to be decremented by 1
- */
- if (lcd_revision == LCD_VERSION_2) {
- /* Mask off the bits we want to change */
- reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & ~0x780000ff;
- reg |= ((front_porch-1) & 0x300) >> 8;
- reg |= ((back_porch-1) & 0x300) >> 4;
- reg |= ((pulse_width-1) & 0x3c0) << 21;
- lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
- }
-}
-
-static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
- int front_porch)
-{
- u32 reg;
-
- reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff;
- reg |= ((back_porch & 0xff) << 24)
- | ((front_porch & 0xff) << 16)
- | (((pulse_width-1) & 0x3f) << 10);
- lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
-}
-
-static int lcd_cfg_display(const struct lcd_ctrl_config *cfg,
- struct fb_videomode *panel)
-{
- u32 reg;
- u32 reg_int;
-
- reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
- LCD_MONO_8BIT_MODE |
- LCD_MONOCHROME_MODE);
-
- switch (cfg->panel_shade) {
- case MONOCHROME:
- reg |= LCD_MONOCHROME_MODE;
- if (cfg->mono_8bit_mode)
- reg |= LCD_MONO_8BIT_MODE;
- break;
- case COLOR_ACTIVE:
- reg |= LCD_TFT_MODE;
- if (cfg->tft_alt_mode)
- reg |= LCD_TFT_ALT_ENABLE;
- break;
-
- case COLOR_PASSIVE:
- /* AC bias applicable only for Pasive panels */
- lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
- if (cfg->bpp == 12 && cfg->stn_565_mode)
- reg |= LCD_STN_565_ENABLE;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* enable additional interrupts here */
- if (lcd_revision == LCD_VERSION_1) {
- reg |= LCD_V1_UNDERFLOW_INT_ENA;
- } else {
- reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
- LCD_V2_UNDERFLOW_INT_ENA;
- lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
- }
-
- lcdc_write(reg, LCD_RASTER_CTRL_REG);
-
- reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
-
- reg |= LCD_SYNC_CTRL;
-
- if (cfg->sync_edge)
- reg |= LCD_SYNC_EDGE;
- else
- reg &= ~LCD_SYNC_EDGE;
-
- if ((panel->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
- reg |= LCD_INVERT_LINE_CLOCK;
- else
- reg &= ~LCD_INVERT_LINE_CLOCK;
-
- if ((panel->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
- reg |= LCD_INVERT_FRAME_CLOCK;
- else
- reg &= ~LCD_INVERT_FRAME_CLOCK;
-
- lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
-
- return 0;
-}
-
-static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
- u32 bpp, u32 raster_order)
-{
- u32 reg;
-
- if (bpp > 16 && lcd_revision == LCD_VERSION_1)
- return -EINVAL;
-
- /* Set the Panel Width */
- /* Pixels per line = (PPL + 1)*16 */
- if (lcd_revision == LCD_VERSION_1) {
- /*
- * 0x3F in bits 4..9 gives max horizontal resolution = 1024
- * pixels.
- */
- width &= 0x3f0;
- } else {
- /*
- * 0x7F in bits 4..10 gives max horizontal resolution = 2048
- * pixels.
- */
- width &= 0x7f0;
- }
-
- reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
- reg &= 0xfffffc00;
- if (lcd_revision == LCD_VERSION_1) {
- reg |= ((width >> 4) - 1) << 4;
- } else {
- width = (width >> 4) - 1;
- reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
- }
- lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
-
- /* Set the Panel Height */
- /* Set bits 9:0 of Lines Per Pixel */
- reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
- reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
- lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
-
- /* Set bit 10 of Lines Per Pixel */
- if (lcd_revision == LCD_VERSION_2) {
- reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
- reg |= ((height - 1) & 0x400) << 16;
- lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
- }
-
- /* Set the Raster Order of the Frame Buffer */
- reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
- if (raster_order)
- reg |= LCD_RASTER_ORDER;
-
- par->palette_sz = 16 * 2;
-
- switch (bpp) {
- case 1:
- case 2:
- case 4:
- case 16:
- break;
- case 24:
- reg |= LCD_V2_TFT_24BPP_MODE;
- break;
- case 32:
- reg |= LCD_V2_TFT_24BPP_MODE;
- reg |= LCD_V2_TFT_24BPP_UNPACK;
- break;
- case 8:
- par->palette_sz = 256 * 2;
- break;
-
- default:
- return -EINVAL;
- }
-
- lcdc_write(reg, LCD_RASTER_CTRL_REG);
-
- return 0;
-}
-
-#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
-static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
-{
- struct da8xx_fb_par *par = info->par;
- unsigned short *palette = (unsigned short *) par->v_palette_base;
- u_short pal;
- int update_hw = 0;
-
- if (regno > 255)
- return 1;
-
- if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
- return 1;
-
- if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
- return -EINVAL;
-
- switch (info->fix.visual) {
- case FB_VISUAL_TRUECOLOR:
- red = CNVT_TOHW(red, info->var.red.length);
- green = CNVT_TOHW(green, info->var.green.length);
- blue = CNVT_TOHW(blue, info->var.blue.length);
- break;
- case FB_VISUAL_PSEUDOCOLOR:
- switch (info->var.bits_per_pixel) {
- case 4:
- if (regno > 15)
- return -EINVAL;
-
- if (info->var.grayscale) {
- pal = regno;
- } else {
- red >>= 4;
- green >>= 8;
- blue >>= 12;
-
- pal = red & 0x0f00;
- pal |= green & 0x00f0;
- pal |= blue & 0x000f;
- }
- if (regno == 0)
- pal |= 0x2000;
- palette[regno] = pal;
- break;
-
- case 8:
- red >>= 4;
- green >>= 8;
- blue >>= 12;
-
- pal = (red & 0x0f00);
- pal |= (green & 0x00f0);
- pal |= (blue & 0x000f);
-
- if (palette[regno] != pal) {
- update_hw = 1;
- palette[regno] = pal;
- }
- break;
- }
- break;
- }
-
- /* Truecolor has hardware independent palette */
- if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
- u32 v;
-
- if (regno > 15)
- return -EINVAL;
-
- v = (red << info->var.red.offset) |
- (green << info->var.green.offset) |
- (blue << info->var.blue.offset);
-
- ((u32 *) (info->pseudo_palette))[regno] = v;
- if (palette[0] != 0x4000) {
- update_hw = 1;
- palette[0] = 0x4000;
- }
- }
-
- /* Update the palette in the h/w as needed. */
- if (update_hw)
- lcd_blit(LOAD_PALETTE, par);
-
- return 0;
-}
-#undef CNVT_TOHW
-
-static void da8xx_fb_lcd_reset(void)
-{
- /* DMA has to be disabled */
- lcdc_write(0, LCD_DMA_CTRL_REG);
- lcdc_write(0, LCD_RASTER_CTRL_REG);
-
- if (lcd_revision == LCD_VERSION_2) {
- lcdc_write(0, LCD_INT_ENABLE_SET_REG);
- /* Write 1 to reset */
- lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
- lcdc_write(0, LCD_CLK_RESET_REG);
- }
-}
-
-static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par,
- unsigned lcdc_clk_div,
- unsigned lcdc_clk_rate)
-{
- int ret;
-
- if (par->lcdc_clk_rate != lcdc_clk_rate) {
- ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate);
- if (ret) {
- dev_err(par->dev,
- "unable to set clock rate at %u\n",
- lcdc_clk_rate);
- return ret;
- }
- par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
- }
-
- /* Configure the LCD clock divisor. */
- lcdc_write(LCD_CLK_DIVISOR(lcdc_clk_div) |
- (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
-
- if (lcd_revision == LCD_VERSION_2)
- lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
- LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);
-
- return 0;
-}
-
-static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par,
- unsigned pixclock,
- unsigned *lcdc_clk_rate)
-{
- unsigned lcdc_clk_div;
-
- pixclock = PICOS2KHZ(pixclock) * 1000;
-
- *lcdc_clk_rate = par->lcdc_clk_rate;
-
- if (pixclock < (*lcdc_clk_rate / CLK_MAX_DIV)) {
- *lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
- pixclock * CLK_MAX_DIV);
- lcdc_clk_div = CLK_MAX_DIV;
- } else if (pixclock > (*lcdc_clk_rate / CLK_MIN_DIV)) {
- *lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
- pixclock * CLK_MIN_DIV);
- lcdc_clk_div = CLK_MIN_DIV;
- } else {
- lcdc_clk_div = *lcdc_clk_rate / pixclock;
- }
-
- return lcdc_clk_div;
-}
-
-static int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par,
- struct fb_videomode *mode)
-{
- unsigned lcdc_clk_rate;
- unsigned lcdc_clk_div = da8xx_fb_calc_clk_divider(par, mode->pixclock,
- &lcdc_clk_rate);
-
- return da8xx_fb_config_clk_divider(par, lcdc_clk_div, lcdc_clk_rate);
-}
-
-static unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par,
- unsigned pixclock)
-{
- unsigned lcdc_clk_div, lcdc_clk_rate;
-
- lcdc_clk_div = da8xx_fb_calc_clk_divider(par, pixclock, &lcdc_clk_rate);
- return KHZ2PICOS(lcdc_clk_rate / (1000 * lcdc_clk_div));
-}
-
-static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
- struct fb_videomode *panel)
-{
- u32 bpp;
- int ret = 0;
-
- ret = da8xx_fb_calc_config_clk_divider(par, panel);
- if (ret) {
- dev_err(par->dev, "unable to configure clock\n");
- return ret;
- }
-
- if (panel->sync & FB_SYNC_CLK_INVERT)
- lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |
- LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
- else
- lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) &
- ~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
-
- /* Configure the DMA burst size and fifo threshold. */
- ret = lcd_cfg_dma(cfg->dma_burst_sz, cfg->fifo_th);
- if (ret < 0)
- return ret;
-
- /* Configure the vertical and horizontal sync properties. */
- lcd_cfg_vertical_sync(panel->upper_margin, panel->vsync_len,
- panel->lower_margin);
- lcd_cfg_horizontal_sync(panel->left_margin, panel->hsync_len,
- panel->right_margin);
-
- /* Configure for disply */
- ret = lcd_cfg_display(cfg, panel);
- if (ret < 0)
- return ret;
-
- bpp = cfg->bpp;
-
- if (bpp == 12)
- bpp = 16;
- ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->xres,
- (unsigned int)panel->yres, bpp,
- cfg->raster_order);
- if (ret < 0)
- return ret;
-
- /* Configure FDD */
- lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) |
- (cfg->fdd << 12), LCD_RASTER_CTRL_REG);
-
- return 0;
-}
-
-/* IRQ handler for version 2 of LCDC */
-static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
-{
- struct da8xx_fb_par *par = arg;
- u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
-
- if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
- lcd_disable_raster(DA8XX_FRAME_NOWAIT);
- lcdc_write(stat, LCD_MASKED_STAT_REG);
- lcd_enable_raster();
- } else if (stat & LCD_PL_LOAD_DONE) {
- /*
- * Must disable raster before changing state of any control bit.
- * And also must be disabled before clearing the PL loading
- * interrupt via the following write to the status register. If
- * this is done after then one gets multiple PL done interrupts.
- */
- lcd_disable_raster(DA8XX_FRAME_NOWAIT);
-
- lcdc_write(stat, LCD_MASKED_STAT_REG);
-
- /* Disable PL completion interrupt */
- lcdc_write(LCD_V2_PL_INT_ENA, LCD_INT_ENABLE_CLR_REG);
-
- /* Setup and start data loading mode */
- lcd_blit(LOAD_DATA, par);
- } else {
- lcdc_write(stat, LCD_MASKED_STAT_REG);
-
- if (stat & LCD_END_OF_FRAME0) {
- par->which_dma_channel_done = 0;
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- par->vsync_flag = 1;
- wake_up_interruptible(&par->vsync_wait);
- }
-
- if (stat & LCD_END_OF_FRAME1) {
- par->which_dma_channel_done = 1;
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- par->vsync_flag = 1;
- wake_up_interruptible(&par->vsync_wait);
- }
-
- /* Set only when controller is disabled and at the end of
- * active frame
- */
- if (stat & BIT(0)) {
- frame_done_flag = 1;
- wake_up_interruptible(&frame_done_wq);
- }
- }
-
- lcdc_write(0, LCD_END_OF_INT_IND_REG);
- return IRQ_HANDLED;
-}
-
-/* IRQ handler for version 1 LCDC */
-static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
-{
- struct da8xx_fb_par *par = arg;
- u32 stat = lcdc_read(LCD_STAT_REG);
- u32 reg_ras;
-
- if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
- lcd_disable_raster(DA8XX_FRAME_NOWAIT);
- lcdc_write(stat, LCD_STAT_REG);
- lcd_enable_raster();
- } else if (stat & LCD_PL_LOAD_DONE) {
- /*
- * Must disable raster before changing state of any control bit.
- * And also must be disabled before clearing the PL loading
- * interrupt via the following write to the status register. If
- * this is done after then one gets multiple PL done interrupts.
- */
- lcd_disable_raster(DA8XX_FRAME_NOWAIT);
-
- lcdc_write(stat, LCD_STAT_REG);
-
- /* Disable PL completion inerrupt */
- reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
- reg_ras &= ~LCD_V1_PL_INT_ENA;
- lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
-
- /* Setup and start data loading mode */
- lcd_blit(LOAD_DATA, par);
- } else {
- lcdc_write(stat, LCD_STAT_REG);
-
- if (stat & LCD_END_OF_FRAME0) {
- par->which_dma_channel_done = 0;
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- par->vsync_flag = 1;
- wake_up_interruptible(&par->vsync_wait);
- }
-
- if (stat & LCD_END_OF_FRAME1) {
- par->which_dma_channel_done = 1;
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- par->vsync_flag = 1;
- wake_up_interruptible(&par->vsync_wait);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-static int fb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- int err = 0;
- struct da8xx_fb_par *par = info->par;
- int bpp = var->bits_per_pixel >> 3;
- unsigned long line_size = var->xres_virtual * bpp;
-
- if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
- return -EINVAL;
-
- switch (var->bits_per_pixel) {
- case 1:
- case 8:
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->nonstd = 0;
- break;
- case 4:
- var->red.offset = 0;
- var->red.length = 4;
- var->green.offset = 0;
- var->green.length = 4;
- var->blue.offset = 0;
- var->blue.length = 4;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->nonstd = FB_NONSTD_REV_PIX_IN_B;
- break;
- case 16: /* RGB 565 */
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- var->nonstd = 0;
- break;
- case 24:
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->nonstd = 0;
- break;
- case 32:
- var->transp.offset = 24;
- var->transp.length = 8;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->nonstd = 0;
- break;
- default:
- err = -EINVAL;
- }
-
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
-
- if (line_size * var->yres_virtual > par->vram_size)
- var->yres_virtual = par->vram_size / line_size;
-
- if (var->yres > var->yres_virtual)
- var->yres = var->yres_virtual;
-
- if (var->xres > var->xres_virtual)
- var->xres = var->xres_virtual;
-
- if (var->xres + var->xoffset > var->xres_virtual)
- var->xoffset = var->xres_virtual - var->xres;
- if (var->yres + var->yoffset > var->yres_virtual)
- var->yoffset = var->yres_virtual - var->yres;
-
- var->pixclock = da8xx_fb_round_clk(par, var->pixclock);
-
- return err;
-}
-
-#ifdef CONFIG_CPU_FREQ
-static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct da8xx_fb_par *par;
-
- par = container_of(nb, struct da8xx_fb_par, freq_transition);
- if (val == CPUFREQ_POSTCHANGE) {
- if (par->lcdc_clk_rate != clk_get_rate(par->lcdc_clk)) {
- par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
- lcd_disable_raster(DA8XX_FRAME_WAIT);
- da8xx_fb_calc_config_clk_divider(par, &par->mode);
- if (par->blank == FB_BLANK_UNBLANK)
- lcd_enable_raster();
- }
- }
-
- return 0;
-}
-
-static int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par)
-{
- par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition;
-
- return cpufreq_register_notifier(&par->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
-{
- cpufreq_unregister_notifier(&par->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-#endif
-
-static void fb_remove(struct platform_device *dev)
-{
- struct fb_info *info = platform_get_drvdata(dev);
- struct da8xx_fb_par *par = info->par;
- int ret;
-
-#ifdef CONFIG_CPU_FREQ
- lcd_da8xx_cpufreq_deregister(par);
-#endif
- if (par->lcd_supply) {
- ret = regulator_disable(par->lcd_supply);
- if (ret)
- dev_warn(&dev->dev, "Failed to disable regulator (%pe)\n",
- ERR_PTR(ret));
- }
-
- lcd_disable_raster(DA8XX_FRAME_WAIT);
- lcdc_write(0, LCD_RASTER_CTRL_REG);
-
- /* disable DMA */
- lcdc_write(0, LCD_DMA_CTRL_REG);
-
- unregister_framebuffer(info);
- fb_dealloc_cmap(&info->cmap);
- pm_runtime_put_sync(&dev->dev);
- pm_runtime_disable(&dev->dev);
- framebuffer_release(info);
-}
-
-/*
- * Function to wait for vertical sync which for this LCD peripheral
- * translates into waiting for the current raster frame to complete.
- */
-static int fb_wait_for_vsync(struct fb_info *info)
-{
- struct da8xx_fb_par *par = info->par;
- int ret;
-
- /*
- * Set flag to 0 and wait for isr to set to 1. It would seem there is a
- * race condition here where the ISR could have occurred just before or
- * just after this set. But since we are just coarsely waiting for
- * a frame to complete then that's OK. i.e. if the frame completed
- * just before this code executed then we have to wait another full
- * frame time but there is no way to avoid such a situation. On the
- * other hand if the frame completed just after then we don't need
- * to wait long at all. Either way we are guaranteed to return to the
- * user immediately after a frame completion which is all that is
- * required.
- */
- par->vsync_flag = 0;
- ret = wait_event_interruptible_timeout(par->vsync_wait,
- par->vsync_flag != 0,
- par->vsync_timeout);
- if (ret < 0)
- return ret;
- if (ret == 0)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-static int fb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
-{
- struct lcd_sync_arg sync_arg;
-
- switch (cmd) {
- case FBIOGET_CONTRAST:
- case FBIOPUT_CONTRAST:
- case FBIGET_BRIGHTNESS:
- case FBIPUT_BRIGHTNESS:
- case FBIGET_COLOR:
- case FBIPUT_COLOR:
- return -ENOTTY;
- case FBIPUT_HSYNC:
- if (copy_from_user(&sync_arg, (char *)arg,
- sizeof(struct lcd_sync_arg)))
- return -EFAULT;
- lcd_cfg_horizontal_sync(sync_arg.back_porch,
- sync_arg.pulse_width,
- sync_arg.front_porch);
- break;
- case FBIPUT_VSYNC:
- if (copy_from_user(&sync_arg, (char *)arg,
- sizeof(struct lcd_sync_arg)))
- return -EFAULT;
- lcd_cfg_vertical_sync(sync_arg.back_porch,
- sync_arg.pulse_width,
- sync_arg.front_porch);
- break;
- case FBIO_WAITFORVSYNC:
- return fb_wait_for_vsync(info);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int cfb_blank(int blank, struct fb_info *info)
-{
- struct da8xx_fb_par *par = info->par;
- int ret = 0;
-
- if (par->blank == blank)
- return 0;
-
- par->blank = blank;
- switch (blank) {
- case FB_BLANK_UNBLANK:
- lcd_enable_raster();
-
- if (par->lcd_supply) {
- ret = regulator_enable(par->lcd_supply);
- if (ret)
- return ret;
- }
- break;
- case FB_BLANK_NORMAL:
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- case FB_BLANK_POWERDOWN:
- if (par->lcd_supply) {
- ret = regulator_disable(par->lcd_supply);
- if (ret)
- return ret;
- }
-
- lcd_disable_raster(DA8XX_FRAME_WAIT);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/*
- * Set new x,y offsets in the virtual display for the visible area and switch
- * to the new mode.
- */
-static int da8xx_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *fbi)
-{
- int ret = 0;
- struct fb_var_screeninfo new_var;
- struct da8xx_fb_par *par = fbi->par;
- struct fb_fix_screeninfo *fix = &fbi->fix;
- unsigned int end;
- unsigned int start;
- unsigned long irq_flags;
-
- if (var->xoffset != fbi->var.xoffset ||
- var->yoffset != fbi->var.yoffset) {
- memcpy(&new_var, &fbi->var, sizeof(new_var));
- new_var.xoffset = var->xoffset;
- new_var.yoffset = var->yoffset;
- if (fb_check_var(&new_var, fbi))
- ret = -EINVAL;
- else {
- memcpy(&fbi->var, &new_var, sizeof(new_var));
-
- start = fix->smem_start +
- new_var.yoffset * fix->line_length +
- new_var.xoffset * fbi->var.bits_per_pixel / 8;
- end = start + fbi->var.yres * fix->line_length - 1;
- par->dma_start = start;
- par->dma_end = end;
- spin_lock_irqsave(&par->lock_for_chan_update,
- irq_flags);
- if (par->which_dma_channel_done == 0) {
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- } else if (par->which_dma_channel_done == 1) {
- lcdc_write(par->dma_start,
- LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(par->dma_end,
- LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- }
- spin_unlock_irqrestore(&par->lock_for_chan_update,
- irq_flags);
- }
- }
-
- return ret;
-}
-
-static int da8xxfb_set_par(struct fb_info *info)
-{
- struct da8xx_fb_par *par = info->par;
- int ret;
- bool raster = da8xx_fb_is_raster_enabled();
-
- if (raster)
- lcd_disable_raster(DA8XX_FRAME_WAIT);
-
- fb_var_to_videomode(&par->mode, &info->var);
-
- par->cfg.bpp = info->var.bits_per_pixel;
-
- info->fix.visual = (par->cfg.bpp <= 8) ?
- FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length = (par->mode.xres * par->cfg.bpp) / 8;
-
- ret = lcd_init(par, &par->cfg, &par->mode);
- if (ret < 0) {
- dev_err(par->dev, "lcd init failed\n");
- return ret;
- }
-
- par->dma_start = info->fix.smem_start +
- info->var.yoffset * info->fix.line_length +
- info->var.xoffset * info->var.bits_per_pixel / 8;
- par->dma_end = par->dma_start +
- info->var.yres * info->fix.line_length - 1;
-
- lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
-
- if (raster)
- lcd_enable_raster();
-
- return 0;
-}
-
-static const struct fb_ops da8xx_fb_ops = {
- .owner = THIS_MODULE,
- FB_DEFAULT_IOMEM_OPS,
- .fb_check_var = fb_check_var,
- .fb_set_par = da8xxfb_set_par,
- .fb_setcolreg = fb_setcolreg,
- .fb_pan_display = da8xx_pan_display,
- .fb_ioctl = fb_ioctl,
- .fb_blank = cfb_blank,
-};
-
-static struct fb_videomode *da8xx_fb_get_videomode(struct platform_device *dev)
-{
- struct da8xx_lcdc_platform_data *fb_pdata = dev_get_platdata(&dev->dev);
- struct fb_videomode *lcdc_info;
- int i;
-
- for (i = 0, lcdc_info = known_lcd_panels;
- i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) {
- if (strcmp(fb_pdata->type, lcdc_info->name) == 0)
- break;
- }
-
- if (i == ARRAY_SIZE(known_lcd_panels)) {
- dev_err(&dev->dev, "no panel found\n");
- return NULL;
- }
- dev_info(&dev->dev, "found %s panel\n", lcdc_info->name);
-
- return lcdc_info;
-}
-
-static int fb_probe(struct platform_device *device)
-{
- struct da8xx_lcdc_platform_data *fb_pdata =
- dev_get_platdata(&device->dev);
- struct lcd_ctrl_config *lcd_cfg;
- struct fb_videomode *lcdc_info;
- struct fb_info *da8xx_fb_info;
- struct da8xx_fb_par *par;
- struct clk *tmp_lcdc_clk;
- int ret;
- unsigned long ulcm;
-
- if (fb_pdata == NULL) {
- dev_err(&device->dev, "Can not get platform data\n");
- return -ENOENT;
- }
-
- lcdc_info = da8xx_fb_get_videomode(device);
- if (lcdc_info == NULL)
- return -ENODEV;
-
- da8xx_fb_reg_base = devm_platform_ioremap_resource(device, 0);
- if (IS_ERR(da8xx_fb_reg_base))
- return PTR_ERR(da8xx_fb_reg_base);
-
- tmp_lcdc_clk = devm_clk_get(&device->dev, "fck");
- if (IS_ERR(tmp_lcdc_clk))
- return dev_err_probe(&device->dev, PTR_ERR(tmp_lcdc_clk),
- "Can not get device clock\n");
-
- pm_runtime_enable(&device->dev);
- pm_runtime_get_sync(&device->dev);
-
- /* Determine LCD IP Version */
- switch (lcdc_read(LCD_PID_REG)) {
- case 0x4C100102:
- lcd_revision = LCD_VERSION_1;
- break;
- case 0x4F200800:
- case 0x4F201000:
- lcd_revision = LCD_VERSION_2;
- break;
- default:
- dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
- "defaulting to LCD revision 1\n",
- lcdc_read(LCD_PID_REG));
- lcd_revision = LCD_VERSION_1;
- break;
- }
-
- lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data;
-
- if (!lcd_cfg) {
- ret = -EINVAL;
- goto err_pm_runtime_disable;
- }
-
- da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
- &device->dev);
- if (!da8xx_fb_info) {
- ret = -ENOMEM;
- goto err_pm_runtime_disable;
- }
-
- par = da8xx_fb_info->par;
- par->dev = &device->dev;
- par->lcdc_clk = tmp_lcdc_clk;
- par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
-
- par->lcd_supply = devm_regulator_get_optional(&device->dev, "lcd");
- if (IS_ERR(par->lcd_supply)) {
- if (PTR_ERR(par->lcd_supply) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto err_release_fb;
- }
-
- par->lcd_supply = NULL;
- } else {
- ret = regulator_enable(par->lcd_supply);
- if (ret)
- goto err_release_fb;
- }
-
- fb_videomode_to_var(&da8xx_fb_var, lcdc_info);
- par->cfg = *lcd_cfg;
-
- da8xx_fb_lcd_reset();
-
- /* allocate frame buffer */
- par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp;
- ulcm = lcm((lcdc_info->xres * lcd_cfg->bpp)/8, PAGE_SIZE);
- par->vram_size = roundup(par->vram_size/8, ulcm);
- par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
-
- par->vram_virt = dmam_alloc_coherent(par->dev,
- par->vram_size,
- &par->vram_phys,
- GFP_KERNEL | GFP_DMA);
- if (!par->vram_virt) {
- dev_err(&device->dev,
- "GLCD: kmalloc for frame buffer failed\n");
- ret = -EINVAL;
- goto err_disable_reg;
- }
-
- da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
- da8xx_fb_fix.smem_start = par->vram_phys;
- da8xx_fb_fix.smem_len = par->vram_size;
- da8xx_fb_fix.line_length = (lcdc_info->xres * lcd_cfg->bpp) / 8;
-
- par->dma_start = par->vram_phys;
- par->dma_end = par->dma_start + lcdc_info->yres *
- da8xx_fb_fix.line_length - 1;
-
- /* allocate palette buffer */
- par->v_palette_base = dmam_alloc_coherent(par->dev, PALETTE_SIZE,
- &par->p_palette_base,
- GFP_KERNEL | GFP_DMA);
- if (!par->v_palette_base) {
- dev_err(&device->dev,
- "GLCD: kmalloc for palette buffer failed\n");
- ret = -EINVAL;
- goto err_release_fb;
- }
-
- par->irq = platform_get_irq(device, 0);
- if (par->irq < 0) {
- ret = -ENOENT;
- goto err_release_fb;
- }
-
- da8xx_fb_var.grayscale =
- lcd_cfg->panel_shade == MONOCHROME ? 1 : 0;
- da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;
-
- /* Initialize fbinfo */
- da8xx_fb_info->fix = da8xx_fb_fix;
- da8xx_fb_info->var = da8xx_fb_var;
- da8xx_fb_info->fbops = &da8xx_fb_ops;
- da8xx_fb_info->pseudo_palette = par->pseudo_palette;
- da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
- FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-
- ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
- if (ret)
- goto err_disable_reg;
- da8xx_fb_info->cmap.len = par->palette_sz;
-
- /* initialize var_screeninfo */
- da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
- fb_set_var(da8xx_fb_info, &da8xx_fb_var);
-
- platform_set_drvdata(device, da8xx_fb_info);
-
- /* initialize the vsync wait queue */
- init_waitqueue_head(&par->vsync_wait);
- par->vsync_timeout = HZ / 5;
- par->which_dma_channel_done = -1;
- spin_lock_init(&par->lock_for_chan_update);
-
- /* Register the Frame Buffer */
- if (register_framebuffer(da8xx_fb_info) < 0) {
- dev_err(&device->dev,
- "GLCD: Frame Buffer Registration Failed!\n");
- ret = -EINVAL;
- goto err_dealloc_cmap;
- }
-
-#ifdef CONFIG_CPU_FREQ
- ret = lcd_da8xx_cpufreq_register(par);
- if (ret) {
- dev_err(&device->dev, "failed to register cpufreq\n");
- goto err_cpu_freq;
- }
-#endif
-
- if (lcd_revision == LCD_VERSION_1)
- lcdc_irq_handler = lcdc_irq_handler_rev01;
- else {
- init_waitqueue_head(&frame_done_wq);
- lcdc_irq_handler = lcdc_irq_handler_rev02;
- }
-
- ret = devm_request_irq(&device->dev, par->irq, lcdc_irq_handler, 0,
- DRIVER_NAME, par);
- if (ret)
- goto irq_freq;
- return 0;
-
-irq_freq:
-#ifdef CONFIG_CPU_FREQ
- lcd_da8xx_cpufreq_deregister(par);
-err_cpu_freq:
-#endif
- unregister_framebuffer(da8xx_fb_info);
-
-err_dealloc_cmap:
- fb_dealloc_cmap(&da8xx_fb_info->cmap);
-
-err_disable_reg:
- if (par->lcd_supply)
- regulator_disable(par->lcd_supply);
-err_release_fb:
- framebuffer_release(da8xx_fb_info);
-
-err_pm_runtime_disable:
- pm_runtime_put_sync(&device->dev);
- pm_runtime_disable(&device->dev);
-
- return ret;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static struct lcdc_context {
- u32 clk_enable;
- u32 ctrl;
- u32 dma_ctrl;
- u32 raster_timing_0;
- u32 raster_timing_1;
- u32 raster_timing_2;
- u32 int_enable_set;
- u32 dma_frm_buf_base_addr_0;
- u32 dma_frm_buf_ceiling_addr_0;
- u32 dma_frm_buf_base_addr_1;
- u32 dma_frm_buf_ceiling_addr_1;
- u32 raster_ctrl;
-} reg_context;
-
-static void lcd_context_save(void)
-{
- if (lcd_revision == LCD_VERSION_2) {
- reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG);
- reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG);
- }
-
- reg_context.ctrl = lcdc_read(LCD_CTRL_REG);
- reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG);
- reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG);
- reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG);
- reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG);
- reg_context.dma_frm_buf_base_addr_0 =
- lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- reg_context.dma_frm_buf_ceiling_addr_0 =
- lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- reg_context.dma_frm_buf_base_addr_1 =
- lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- reg_context.dma_frm_buf_ceiling_addr_1 =
- lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG);
- return;
-}
-
-static void lcd_context_restore(void)
-{
- if (lcd_revision == LCD_VERSION_2) {
- lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG);
- lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG);
- }
-
- lcdc_write(reg_context.ctrl, LCD_CTRL_REG);
- lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG);
- lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG);
- lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG);
- lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG);
- lcdc_write(reg_context.dma_frm_buf_base_addr_0,
- LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0,
- LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
- lcdc_write(reg_context.dma_frm_buf_base_addr_1,
- LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
- lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1,
- LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
- lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG);
- return;
-}
-
-static int fb_suspend(struct device *dev)
-{
- struct fb_info *info = dev_get_drvdata(dev);
- struct da8xx_fb_par *par = info->par;
- int ret;
-
- console_lock();
- if (par->lcd_supply) {
- ret = regulator_disable(par->lcd_supply);
- if (ret)
- return ret;
- }
-
- fb_set_suspend(info, 1);
- lcd_disable_raster(DA8XX_FRAME_WAIT);
- lcd_context_save();
- pm_runtime_put_sync(dev);
- console_unlock();
-
- return 0;
-}
-static int fb_resume(struct device *dev)
-{
- struct fb_info *info = dev_get_drvdata(dev);
- struct da8xx_fb_par *par = info->par;
- int ret;
-
- console_lock();
- pm_runtime_get_sync(dev);
- lcd_context_restore();
- if (par->blank == FB_BLANK_UNBLANK) {
- lcd_enable_raster();
-
- if (par->lcd_supply) {
- ret = regulator_enable(par->lcd_supply);
- if (ret)
- return ret;
- }
- }
-
- fb_set_suspend(info, 0);
- console_unlock();
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(fb_pm_ops, fb_suspend, fb_resume);
-
-static struct platform_driver da8xx_fb_driver = {
- .probe = fb_probe,
- .remove = fb_remove,
- .driver = {
- .name = DRIVER_NAME,
- .pm = &fb_pm_ops,
- },
-};
-module_platform_driver(da8xx_fb_driver);
-
-MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx");
-MODULE_AUTHOR("Texas Instruments");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/ffb.c b/drivers/video/fbdev/ffb.c
index 0b7e7b38c05a..34b6abff9493 100644
--- a/drivers/video/fbdev/ffb.c
+++ b/drivers/video/fbdev/ffb.c
@@ -710,7 +710,7 @@ static int ffb_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map ffb_mmap_map[] = {
+static const struct sbus_mmap_map ffb_mmap_map[] = {
{
.voff = FFB_SFB8R_VOFF,
.poff = FFB_SFB8R_POFF,
diff --git a/drivers/video/fbdev/leo.c b/drivers/video/fbdev/leo.c
index 271e2e8c6a84..b9fb059df2c7 100644
--- a/drivers/video/fbdev/leo.c
+++ b/drivers/video/fbdev/leo.c
@@ -338,7 +338,7 @@ static int leo_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map leo_mmap_map[] = {
+static const struct sbus_mmap_map leo_mmap_map[] = {
{
.voff = LEO_SS0_MAP,
.poff = LEO_OFF_SS0,
diff --git a/drivers/video/fbdev/nvidia/nv_hw.c b/drivers/video/fbdev/nvidia/nv_hw.c
index 9b0a324bb1b4..75afaa07e7eb 100644
--- a/drivers/video/fbdev/nvidia/nv_hw.c
+++ b/drivers/video/fbdev/nvidia/nv_hw.c
@@ -1509,10 +1509,10 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001);
NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001);
- if (!state) {
- par->CurrentState = NULL;
- return;
- }
+ if (!state) {
+ par->CurrentState = NULL;
+ return;
+ }
if (par->Architecture >= NV_ARCH_10) {
if (par->twoHeads) {
diff --git a/drivers/video/fbdev/p9100.c b/drivers/video/fbdev/p9100.c
index 124468f0e9ef..0bc0f78fe4b9 100644
--- a/drivers/video/fbdev/p9100.c
+++ b/drivers/video/fbdev/p9100.c
@@ -206,7 +206,7 @@ p9100_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map p9100_mmap_map[] = {
+static const struct sbus_mmap_map p9100_mmap_map[] = {
{ CG3_MMAP_OFFSET, 0, SBUS_MMAP_FBSIZE(1) },
{ 0, 0, 0 }
};
diff --git a/drivers/video/fbdev/sbuslib.c b/drivers/video/fbdev/sbuslib.c
index 634e3d159452..4c79654bda30 100644
--- a/drivers/video/fbdev/sbuslib.c
+++ b/drivers/video/fbdev/sbuslib.c
@@ -38,7 +38,7 @@ static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)
return fbsize * (-size);
}
-int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+int sbusfb_mmap_helper(const struct sbus_mmap_map *map,
unsigned long physbase,
unsigned long fbsize,
unsigned long iospace,
diff --git a/drivers/video/fbdev/sbuslib.h b/drivers/video/fbdev/sbuslib.h
index 6466b4cbcd7b..e9af2dc93f94 100644
--- a/drivers/video/fbdev/sbuslib.h
+++ b/drivers/video/fbdev/sbuslib.h
@@ -19,7 +19,7 @@ struct sbus_mmap_map {
extern void sbusfb_fill_var(struct fb_var_screeninfo *var,
struct device_node *dp, int bpp);
-extern int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+extern int sbusfb_mmap_helper(const struct sbus_mmap_map *map,
unsigned long physbase, unsigned long fbsize,
unsigned long iospace,
struct vm_area_struct *vma);
diff --git a/drivers/video/fbdev/sstfb.c b/drivers/video/fbdev/sstfb.c
index f8ae54ca0cc3..2ea947f57efb 100644
--- a/drivers/video/fbdev/sstfb.c
+++ b/drivers/video/fbdev/sstfb.c
@@ -716,6 +716,7 @@ static void sstfb_setvgapass( struct fb_info *info, int enable )
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
}
+#ifdef CONFIG_FB_DEVICE
static ssize_t store_vgapass(struct device *device, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -739,7 +740,8 @@ static ssize_t show_vgapass(struct device *device, struct device_attribute *attr
static struct device_attribute device_attrs[] = {
__ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass)
- };
+};
+#endif
static int sstfb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
@@ -1436,9 +1438,10 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sstfb_clear_screen(info);
+#ifdef CONFIG_FB_DEVICE
if (device_create_file(info->dev, &device_attrs[0]))
printk(KERN_WARNING "sstfb: can't create sysfs entry.\n");
-
+#endif
fb_info(info, "%s frame buffer device at 0x%p\n",
fix->id, info->screen_base);
@@ -1468,7 +1471,9 @@ static void sstfb_remove(struct pci_dev *pdev)
info = pci_get_drvdata(pdev);
par = info->par;
+#ifdef CONFIG_FB_DEVICE
device_remove_file(info->dev, &device_attrs[0]);
+#endif
sst_shutdown(info);
iounmap(info->screen_base);
iounmap(par->mmio_vbase);
diff --git a/drivers/video/fbdev/tcx.c b/drivers/video/fbdev/tcx.c
index 6eb8bb2e3501..f9a0085ad72b 100644
--- a/drivers/video/fbdev/tcx.c
+++ b/drivers/video/fbdev/tcx.c
@@ -236,7 +236,7 @@ tcx_blank(int blank, struct fb_info *info)
return 0;
}
-static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
+static const struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
{
.voff = TCX_RAM8BIT,
.size = SBUS_MMAP_FBSIZE(1)
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index c44d8ba00c02..88074451dd61 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -24,6 +24,16 @@ MODULE_PARM_DESC(force_legacy,
"Force legacy mode for transitional virtio 1 devices");
#endif
+bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return false;
+
+ return index == vp_dev->admin_vq.vq_index;
+}
+
/* wait for pending irq handlers */
void vp_synchronize_vectors(struct virtio_device *vdev)
{
@@ -234,10 +244,9 @@ out_info:
return vq;
}
-static void vp_del_vq(struct virtqueue *vq)
+static void vp_del_vq(struct virtqueue *vq, struct virtio_pci_vq_info *info)
{
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
- struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
unsigned long flags;
/*
@@ -258,13 +267,16 @@ static void vp_del_vq(struct virtqueue *vq)
void vp_del_vqs(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_vq_info *info;
struct virtqueue *vq, *n;
int i;
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
- if (vp_dev->per_vq_vectors) {
- int v = vp_dev->vqs[vq->index]->msix_vector;
+ info = vp_is_avq(vdev, vq->index) ? vp_dev->admin_vq.info :
+ vp_dev->vqs[vq->index];
+ if (vp_dev->per_vq_vectors) {
+ int v = info->msix_vector;
if (v != VIRTIO_MSI_NO_VECTOR &&
!vp_is_slow_path_vector(v)) {
int irq = pci_irq_vector(vp_dev->pci_dev, v);
@@ -273,7 +285,7 @@ void vp_del_vqs(struct virtio_device *vdev)
free_irq(irq, vq);
}
}
- vp_del_vq(vq);
+ vp_del_vq(vq, info);
}
vp_dev->per_vq_vectors = false;
@@ -354,7 +366,7 @@ vp_find_one_vq_msix(struct virtio_device *vdev, int queue_idx,
vring_interrupt, 0,
vp_dev->msix_names[msix_vec], vq);
if (err) {
- vp_del_vq(vq);
+ vp_del_vq(vq, *p_info);
return ERR_PTR(err);
}
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
index 1d9c49947f52..8beecf23ec85 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -178,6 +178,7 @@ struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev);
#define VIRTIO_ADMIN_CMD_BITMAP 0
#endif
+bool vp_is_avq(struct virtio_device *vdev, unsigned int index);
void vp_modern_avq_done(struct virtqueue *vq);
int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
struct virtio_admin_cmd *cmd);
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index 9193c30d640a..4fbcbc7a9ae1 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -43,16 +43,6 @@ static int vp_avq_index(struct virtio_device *vdev, u16 *index, u16 *num)
return 0;
}
-static bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
- return false;
-
- return index == vp_dev->admin_vq.vq_index;
-}
-
void vp_modern_avq_done(struct virtqueue *vq)
{
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
@@ -245,7 +235,7 @@ static void vp_modern_avq_cleanup(struct virtio_device *vdev)
if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
return;
- vq = vp_dev->vqs[vp_dev->admin_vq.vq_index]->vq;
+ vq = vp_dev->admin_vq.info->vq;
if (!vq)
return;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 98374ed7c577..8167be01b400 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -69,12 +69,20 @@
struct vring_desc_state_split {
void *data; /* Data for callback. */
- struct vring_desc *indir_desc; /* Indirect descriptor, if any. */
+
+ /* Indirect desc table and extra table, if any. These two will be
+ * allocated together. So we won't stress more to the memory allocator.
+ */
+ struct vring_desc *indir_desc;
};
struct vring_desc_state_packed {
void *data; /* Data for callback. */
- struct vring_packed_desc *indir_desc; /* Indirect descriptor, if any. */
+
+ /* Indirect desc table and extra table, if any. These two will be
+ * allocated together. So we won't stress more to the memory allocator.
+ */
+ struct vring_packed_desc *indir_desc;
u16 num; /* Descriptor list length. */
u16 last; /* The last desc state in a list. */
};
@@ -172,14 +180,6 @@ struct vring_virtqueue {
/* Host publishes avail event idx */
bool event;
- /* Do DMA mapping by driver */
- bool premapped;
-
- /* Do unmap or not for desc. Just when premapped is False and
- * use_dma_api is true, this is true.
- */
- bool do_unmap;
-
/* Head of free buffer list. */
unsigned int free_head;
/* Number we've added since last sync. */
@@ -297,6 +297,12 @@ static bool vring_use_dma_api(const struct virtio_device *vdev)
return false;
}
+static bool vring_need_unmap_buffer(const struct vring_virtqueue *vring,
+ const struct vring_desc_extra *extra)
+{
+ return vring->use_dma_api && (extra->addr != DMA_MAPPING_ERROR);
+}
+
size_t virtio_max_dma_size(const struct virtio_device *vdev)
{
size_t max_segment_size = SIZE_MAX;
@@ -364,13 +370,17 @@ static struct device *vring_dma_dev(const struct vring_virtqueue *vq)
/* Map one sg entry. */
static int vring_map_one_sg(const struct vring_virtqueue *vq, struct scatterlist *sg,
- enum dma_data_direction direction, dma_addr_t *addr)
+ enum dma_data_direction direction, dma_addr_t *addr,
+ u32 *len, bool premapped)
{
- if (vq->premapped) {
+ if (premapped) {
*addr = sg_dma_address(sg);
+ *len = sg_dma_len(sg);
return 0;
}
+ *len = sg->length;
+
if (!vq->use_dma_api) {
/*
* If DMA is not used, KMSAN doesn't know that the scatterlist
@@ -440,61 +450,44 @@ static void virtqueue_init(struct vring_virtqueue *vq, u32 num)
* Split ring specific functions - *_split().
*/
-static void vring_unmap_one_split_indirect(const struct vring_virtqueue *vq,
- const struct vring_desc *desc)
-{
- u16 flags;
-
- if (!vq->do_unmap)
- return;
-
- flags = virtio16_to_cpu(vq->vq.vdev, desc->flags);
-
- dma_unmap_page(vring_dma_dev(vq),
- virtio64_to_cpu(vq->vq.vdev, desc->addr),
- virtio32_to_cpu(vq->vq.vdev, desc->len),
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-}
-
static unsigned int vring_unmap_one_split(const struct vring_virtqueue *vq,
- unsigned int i)
+ struct vring_desc_extra *extra)
{
- struct vring_desc_extra *extra = vq->split.desc_extra;
u16 flags;
- flags = extra[i].flags;
+ flags = extra->flags;
if (flags & VRING_DESC_F_INDIRECT) {
if (!vq->use_dma_api)
goto out;
dma_unmap_single(vring_dma_dev(vq),
- extra[i].addr,
- extra[i].len,
+ extra->addr,
+ extra->len,
(flags & VRING_DESC_F_WRITE) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
} else {
- if (!vq->do_unmap)
+ if (!vring_need_unmap_buffer(vq, extra))
goto out;
dma_unmap_page(vring_dma_dev(vq),
- extra[i].addr,
- extra[i].len,
+ extra->addr,
+ extra->len,
(flags & VRING_DESC_F_WRITE) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
out:
- return extra[i].next;
+ return extra->next;
}
static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
unsigned int total_sg,
gfp_t gfp)
{
+ struct vring_desc_extra *extra;
struct vring_desc *desc;
- unsigned int i;
+ unsigned int i, size;
/*
* We require lowmem mappings for the descriptors because
@@ -503,40 +496,41 @@ static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
*/
gfp &= ~__GFP_HIGHMEM;
- desc = kmalloc_array(total_sg, sizeof(struct vring_desc), gfp);
+ size = sizeof(*desc) * total_sg + sizeof(*extra) * total_sg;
+
+ desc = kmalloc(size, gfp);
if (!desc)
return NULL;
+ extra = (struct vring_desc_extra *)&desc[total_sg];
+
for (i = 0; i < total_sg; i++)
- desc[i].next = cpu_to_virtio16(_vq->vdev, i + 1);
+ extra[i].next = i + 1;
+
return desc;
}
static inline unsigned int virtqueue_add_desc_split(struct virtqueue *vq,
struct vring_desc *desc,
+ struct vring_desc_extra *extra,
unsigned int i,
dma_addr_t addr,
unsigned int len,
- u16 flags,
- bool indirect)
+ u16 flags, bool premapped)
{
- struct vring_virtqueue *vring = to_vvq(vq);
- struct vring_desc_extra *extra = vring->split.desc_extra;
u16 next;
desc[i].flags = cpu_to_virtio16(vq->vdev, flags);
desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
desc[i].len = cpu_to_virtio32(vq->vdev, len);
- if (!indirect) {
- next = extra[i].next;
- desc[i].next = cpu_to_virtio16(vq->vdev, next);
+ extra[i].addr = premapped ? DMA_MAPPING_ERROR : addr;
+ extra[i].len = len;
+ extra[i].flags = flags;
- extra[i].addr = addr;
- extra[i].len = len;
- extra[i].flags = flags;
- } else
- next = virtio16_to_cpu(vq->vdev, desc[i].next);
+ next = extra[i].next;
+
+ desc[i].next = cpu_to_virtio16(vq->vdev, next);
return next;
}
@@ -548,9 +542,11 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
unsigned int in_sgs,
void *data,
void *ctx,
+ bool premapped,
gfp_t gfp)
{
struct vring_virtqueue *vq = to_vvq(_vq);
+ struct vring_desc_extra *extra;
struct scatterlist *sg;
struct vring_desc *desc;
unsigned int i, n, avail, descs_used, prev, err_idx;
@@ -586,9 +582,11 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
/* Set up rest to use this indirect table. */
i = 0;
descs_used = 1;
+ extra = (struct vring_desc_extra *)&desc[total_sg];
} else {
indirect = false;
desc = vq->split.vring.desc;
+ extra = vq->split.desc_extra;
i = head;
descs_used = total_sg;
}
@@ -610,40 +608,41 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
for (n = 0; n < out_sgs; n++) {
for (sg = sgs[n]; sg; sg = sg_next(sg)) {
dma_addr_t addr;
+ u32 len;
- if (vring_map_one_sg(vq, sg, DMA_TO_DEVICE, &addr))
+ if (vring_map_one_sg(vq, sg, DMA_TO_DEVICE, &addr, &len, premapped))
goto unmap_release;
prev = i;
/* Note that we trust indirect descriptor
* table since it use stream DMA mapping.
*/
- i = virtqueue_add_desc_split(_vq, desc, i, addr, sg->length,
+ i = virtqueue_add_desc_split(_vq, desc, extra, i, addr, len,
VRING_DESC_F_NEXT,
- indirect);
+ premapped);
}
}
for (; n < (out_sgs + in_sgs); n++) {
for (sg = sgs[n]; sg; sg = sg_next(sg)) {
dma_addr_t addr;
+ u32 len;
- if (vring_map_one_sg(vq, sg, DMA_FROM_DEVICE, &addr))
+ if (vring_map_one_sg(vq, sg, DMA_FROM_DEVICE, &addr, &len, premapped))
goto unmap_release;
prev = i;
/* Note that we trust indirect descriptor
* table since it use stream DMA mapping.
*/
- i = virtqueue_add_desc_split(_vq, desc, i, addr,
- sg->length,
+ i = virtqueue_add_desc_split(_vq, desc, extra, i, addr, len,
VRING_DESC_F_NEXT |
VRING_DESC_F_WRITE,
- indirect);
+ premapped);
}
}
/* Last one doesn't continue. */
desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT);
- if (!indirect && vq->do_unmap)
+ if (!indirect && vring_need_unmap_buffer(vq, &extra[prev]))
vq->split.desc_extra[prev & (vq->split.vring.num - 1)].flags &=
~VRING_DESC_F_NEXT;
@@ -652,18 +651,14 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
dma_addr_t addr = vring_map_single(
vq, desc, total_sg * sizeof(struct vring_desc),
DMA_TO_DEVICE);
- if (vring_mapping_error(vq, addr)) {
- if (vq->premapped)
- goto free_indirect;
-
+ if (vring_mapping_error(vq, addr))
goto unmap_release;
- }
virtqueue_add_desc_split(_vq, vq->split.vring.desc,
+ vq->split.desc_extra,
head, addr,
total_sg * sizeof(struct vring_desc),
- VRING_DESC_F_INDIRECT,
- false);
+ VRING_DESC_F_INDIRECT, false);
}
/* We're using some buffers from the free list. */
@@ -716,14 +711,10 @@ unmap_release:
for (n = 0; n < total_sg; n++) {
if (i == err_idx)
break;
- if (indirect) {
- vring_unmap_one_split_indirect(vq, &desc[i]);
- i = virtio16_to_cpu(_vq->vdev, desc[i].next);
- } else
- i = vring_unmap_one_split(vq, i);
+
+ i = vring_unmap_one_split(vq, &extra[i]);
}
-free_indirect:
if (indirect)
kfree(desc);
@@ -765,22 +756,25 @@ static bool virtqueue_kick_prepare_split(struct virtqueue *_vq)
static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
void **ctx)
{
+ struct vring_desc_extra *extra;
unsigned int i, j;
__virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT);
/* Clear data ptr. */
vq->split.desc_state[head].data = NULL;
+ extra = vq->split.desc_extra;
+
/* Put back on free list: unmap first-level descriptors and find end */
i = head;
while (vq->split.vring.desc[i].flags & nextflag) {
- vring_unmap_one_split(vq, i);
+ vring_unmap_one_split(vq, &extra[i]);
i = vq->split.desc_extra[i].next;
vq->vq.num_free++;
}
- vring_unmap_one_split(vq, i);
+ vring_unmap_one_split(vq, &extra[i]);
vq->split.desc_extra[i].next = vq->free_head;
vq->free_head = head;
@@ -790,21 +784,24 @@ static void detach_buf_split(struct vring_virtqueue *vq, unsigned int head,
if (vq->indirect) {
struct vring_desc *indir_desc =
vq->split.desc_state[head].indir_desc;
- u32 len;
+ u32 len, num;
/* Free the indirect table, if any, now that it's unmapped. */
if (!indir_desc)
return;
-
len = vq->split.desc_extra[head].len;
BUG_ON(!(vq->split.desc_extra[head].flags &
VRING_DESC_F_INDIRECT));
BUG_ON(len == 0 || len % sizeof(struct vring_desc));
- if (vq->do_unmap) {
- for (j = 0; j < len / sizeof(struct vring_desc); j++)
- vring_unmap_one_split_indirect(vq, &indir_desc[j]);
+ num = len / sizeof(struct vring_desc);
+
+ extra = (struct vring_desc_extra *)&indir_desc[num];
+
+ if (vq->use_dma_api) {
+ for (j = 0; j < num; j++)
+ vring_unmap_one_split(vq, &extra[j]);
}
kfree(indir_desc);
@@ -1236,7 +1233,7 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
(flags & VRING_DESC_F_WRITE) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
} else {
- if (!vq->do_unmap)
+ if (!vring_need_unmap_buffer(vq, extra))
return;
dma_unmap_page(vring_dma_dev(vq),
@@ -1246,27 +1243,12 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq,
}
}
-static void vring_unmap_desc_packed(const struct vring_virtqueue *vq,
- const struct vring_packed_desc *desc)
-{
- u16 flags;
-
- if (!vq->do_unmap)
- return;
-
- flags = le16_to_cpu(desc->flags);
-
- dma_unmap_page(vring_dma_dev(vq),
- le64_to_cpu(desc->addr),
- le32_to_cpu(desc->len),
- (flags & VRING_DESC_F_WRITE) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
-}
-
static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
gfp_t gfp)
{
+ struct vring_desc_extra *extra;
struct vring_packed_desc *desc;
+ int i, size;
/*
* We require lowmem mappings for the descriptors because
@@ -1275,7 +1257,16 @@ static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg,
*/
gfp &= ~__GFP_HIGHMEM;
- desc = kmalloc_array(total_sg, sizeof(struct vring_packed_desc), gfp);
+ size = (sizeof(*desc) + sizeof(*extra)) * total_sg;
+
+ desc = kmalloc(size, gfp);
+ if (!desc)
+ return NULL;
+
+ extra = (struct vring_desc_extra *)&desc[total_sg];
+
+ for (i = 0; i < total_sg; i++)
+ extra[i].next = i + 1;
return desc;
}
@@ -1286,11 +1277,13 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
unsigned int out_sgs,
unsigned int in_sgs,
void *data,
+ bool premapped,
gfp_t gfp)
{
+ struct vring_desc_extra *extra;
struct vring_packed_desc *desc;
struct scatterlist *sg;
- unsigned int i, n, err_idx;
+ unsigned int i, n, err_idx, len;
u16 head, id;
dma_addr_t addr;
@@ -1299,6 +1292,8 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
if (!desc)
return -ENOMEM;
+ extra = (struct vring_desc_extra *)&desc[total_sg];
+
if (unlikely(vq->vq.num_free < 1)) {
pr_debug("Can't add buf len 1 - avail = 0\n");
kfree(desc);
@@ -1313,13 +1308,21 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
for (n = 0; n < out_sgs + in_sgs; n++) {
for (sg = sgs[n]; sg; sg = sg_next(sg)) {
if (vring_map_one_sg(vq, sg, n < out_sgs ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE, &addr))
+ DMA_TO_DEVICE : DMA_FROM_DEVICE,
+ &addr, &len, premapped))
goto unmap_release;
desc[i].flags = cpu_to_le16(n < out_sgs ?
0 : VRING_DESC_F_WRITE);
desc[i].addr = cpu_to_le64(addr);
- desc[i].len = cpu_to_le32(sg->length);
+ desc[i].len = cpu_to_le32(len);
+
+ if (unlikely(vq->use_dma_api)) {
+ extra[i].addr = premapped ? DMA_MAPPING_ERROR : addr;
+ extra[i].len = len;
+ extra[i].flags = n < out_sgs ? 0 : VRING_DESC_F_WRITE;
+ }
+
i++;
}
}
@@ -1328,12 +1331,8 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
addr = vring_map_single(vq, desc,
total_sg * sizeof(struct vring_packed_desc),
DMA_TO_DEVICE);
- if (vring_mapping_error(vq, addr)) {
- if (vq->premapped)
- goto free_desc;
-
+ if (vring_mapping_error(vq, addr))
goto unmap_release;
- }
vq->packed.vring.desc[head].addr = cpu_to_le64(addr);
vq->packed.vring.desc[head].len = cpu_to_le32(total_sg *
@@ -1389,9 +1388,8 @@ unmap_release:
err_idx = i;
for (i = 0; i < err_idx; i++)
- vring_unmap_desc_packed(vq, &desc[i]);
+ vring_unmap_extra_packed(vq, &extra[i]);
-free_desc:
kfree(desc);
END_USE(vq);
@@ -1405,12 +1403,13 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
unsigned int in_sgs,
void *data,
void *ctx,
+ bool premapped,
gfp_t gfp)
{
struct vring_virtqueue *vq = to_vvq(_vq);
struct vring_packed_desc *desc;
struct scatterlist *sg;
- unsigned int i, n, c, descs_used, err_idx;
+ unsigned int i, n, c, descs_used, err_idx, len;
__le16 head_flags, flags;
u16 head, id, prev, curr, avail_used_flags;
int err;
@@ -1431,7 +1430,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
if (virtqueue_use_indirect(vq, total_sg)) {
err = virtqueue_add_indirect_packed(vq, sgs, total_sg, out_sgs,
- in_sgs, data, gfp);
+ in_sgs, data, premapped, gfp);
if (err != -ENOMEM) {
END_USE(vq);
return err;
@@ -1466,7 +1465,8 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
dma_addr_t addr;
if (vring_map_one_sg(vq, sg, n < out_sgs ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE, &addr))
+ DMA_TO_DEVICE : DMA_FROM_DEVICE,
+ &addr, &len, premapped))
goto unmap_release;
flags = cpu_to_le16(vq->packed.avail_used_flags |
@@ -1478,12 +1478,13 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
desc[i].flags = flags;
desc[i].addr = cpu_to_le64(addr);
- desc[i].len = cpu_to_le32(sg->length);
+ desc[i].len = cpu_to_le32(len);
desc[i].id = cpu_to_le16(id);
if (unlikely(vq->use_dma_api)) {
- vq->packed.desc_extra[curr].addr = addr;
- vq->packed.desc_extra[curr].len = sg->length;
+ vq->packed.desc_extra[curr].addr = premapped ?
+ DMA_MAPPING_ERROR : addr;
+ vq->packed.desc_extra[curr].len = len;
vq->packed.desc_extra[curr].flags =
le16_to_cpu(flags);
}
@@ -1625,18 +1626,22 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
}
if (vq->indirect) {
- u32 len;
+ struct vring_desc_extra *extra;
+ u32 len, num;
/* Free the indirect table, if any, now that it's unmapped. */
desc = state->indir_desc;
if (!desc)
return;
- if (vq->do_unmap) {
+ if (vq->use_dma_api) {
len = vq->packed.desc_extra[id].len;
- for (i = 0; i < len / sizeof(struct vring_packed_desc);
- i++)
- vring_unmap_desc_packed(vq, &desc[i]);
+ num = len / sizeof(struct vring_packed_desc);
+
+ extra = (struct vring_desc_extra *)&desc[num];
+
+ for (i = 0; i < num; i++)
+ vring_unmap_extra_packed(vq, &extra[i]);
}
kfree(desc);
state->indir_desc = NULL;
@@ -2090,8 +2095,6 @@ static struct virtqueue *vring_create_virtqueue_packed(
vq->packed_ring = true;
vq->dma_dev = dma_dev;
vq->use_dma_api = vring_use_dma_api(vdev);
- vq->premapped = false;
- vq->do_unmap = vq->use_dma_api;
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
!context;
@@ -2201,14 +2204,15 @@ static inline int virtqueue_add(struct virtqueue *_vq,
unsigned int in_sgs,
void *data,
void *ctx,
+ bool premapped,
gfp_t gfp)
{
struct vring_virtqueue *vq = to_vvq(_vq);
return vq->packed_ring ? virtqueue_add_packed(_vq, sgs, total_sg,
- out_sgs, in_sgs, data, ctx, gfp) :
+ out_sgs, in_sgs, data, ctx, premapped, gfp) :
virtqueue_add_split(_vq, sgs, total_sg,
- out_sgs, in_sgs, data, ctx, gfp);
+ out_sgs, in_sgs, data, ctx, premapped, gfp);
}
/**
@@ -2242,7 +2246,7 @@ int virtqueue_add_sgs(struct virtqueue *_vq,
total_sg++;
}
return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs,
- data, NULL, gfp);
+ data, NULL, false, gfp);
}
EXPORT_SYMBOL_GPL(virtqueue_add_sgs);
@@ -2264,11 +2268,34 @@ int virtqueue_add_outbuf(struct virtqueue *vq,
void *data,
gfp_t gfp)
{
- return virtqueue_add(vq, &sg, num, 1, 0, data, NULL, gfp);
+ return virtqueue_add(vq, &sg, num, 1, 0, data, NULL, false, gfp);
}
EXPORT_SYMBOL_GPL(virtqueue_add_outbuf);
/**
+ * virtqueue_add_outbuf_premapped - expose output buffers to other end
+ * @vq: the struct virtqueue we're talking about.
+ * @sg: scatterlist (must be well-formed and terminated!)
+ * @num: the number of entries in @sg readable by other side
+ * @data: the token identifying the buffer.
+ * @gfp: how to do memory allocations (if necessary).
+ *
+ * Caller must ensure we don't call this with other virtqueue operations
+ * at the same time (except where noted).
+ *
+ * Return:
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
+ */
+int virtqueue_add_outbuf_premapped(struct virtqueue *vq,
+ struct scatterlist *sg, unsigned int num,
+ void *data,
+ gfp_t gfp)
+{
+ return virtqueue_add(vq, &sg, num, 1, 0, data, NULL, true, gfp);
+}
+EXPORT_SYMBOL_GPL(virtqueue_add_outbuf_premapped);
+
+/**
* virtqueue_add_inbuf - expose input buffers to other end
* @vq: the struct virtqueue we're talking about.
* @sg: scatterlist (must be well-formed and terminated!)
@@ -2286,7 +2313,7 @@ int virtqueue_add_inbuf(struct virtqueue *vq,
void *data,
gfp_t gfp)
{
- return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, gfp);
+ return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, false, gfp);
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf);
@@ -2310,11 +2337,36 @@ int virtqueue_add_inbuf_ctx(struct virtqueue *vq,
void *ctx,
gfp_t gfp)
{
- return virtqueue_add(vq, &sg, num, 0, 1, data, ctx, gfp);
+ return virtqueue_add(vq, &sg, num, 0, 1, data, ctx, false, gfp);
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_ctx);
/**
+ * virtqueue_add_inbuf_premapped - expose input buffers to other end
+ * @vq: the struct virtqueue we're talking about.
+ * @sg: scatterlist (must be well-formed and terminated!)
+ * @num: the number of entries in @sg writable by other side
+ * @data: the token identifying the buffer.
+ * @ctx: extra context for the token
+ * @gfp: how to do memory allocations (if necessary).
+ *
+ * Caller must ensure we don't call this with other virtqueue operations
+ * at the same time (except where noted).
+ *
+ * Return:
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
+ */
+int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
+ struct scatterlist *sg, unsigned int num,
+ void *data,
+ void *ctx,
+ gfp_t gfp)
+{
+ return virtqueue_add(vq, &sg, num, 0, 1, data, ctx, true, gfp);
+}
+EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_premapped);
+
+/**
* virtqueue_dma_dev - get the dma dev
* @_vq: the struct virtqueue we're talking about.
*
@@ -2635,8 +2687,6 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
#endif
vq->dma_dev = dma_dev;
vq->use_dma_api = vring_use_dma_api(vdev);
- vq->premapped = false;
- vq->do_unmap = vq->use_dma_api;
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
!context;
@@ -2764,50 +2814,6 @@ int virtqueue_resize(struct virtqueue *_vq, u32 num,
EXPORT_SYMBOL_GPL(virtqueue_resize);
/**
- * virtqueue_set_dma_premapped - set the vring premapped mode
- * @_vq: the struct virtqueue we're talking about.
- *
- * Enable the premapped mode of the vq.
- *
- * The vring in premapped mode does not do dma internally, so the driver must
- * do dma mapping in advance. The driver must pass the dma_address through
- * dma_address of scatterlist. When the driver got a used buffer from
- * the vring, it has to unmap the dma address.
- *
- * This function must be called immediately after creating the vq, or after vq
- * reset, and before adding any buffers to it.
- *
- * Caller must ensure we don't call this with other virtqueue operations
- * at the same time (except where noted).
- *
- * Returns zero or a negative error.
- * 0: success.
- * -EINVAL: too late to enable premapped mode, the vq already contains buffers.
- */
-int virtqueue_set_dma_premapped(struct virtqueue *_vq)
-{
- struct vring_virtqueue *vq = to_vvq(_vq);
- u32 num;
-
- START_USE(vq);
-
- num = vq->packed_ring ? vq->packed.vring.num : vq->split.vring.num;
-
- if (num != vq->vq.num_free) {
- END_USE(vq);
- return -EINVAL;
- }
-
- vq->premapped = true;
- vq->do_unmap = false;
-
- END_USE(vq);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(virtqueue_set_dma_premapped);
-
-/**
* virtqueue_reset - detach and recycle all unused buffers
* @_vq: the struct virtqueue we're talking about.
* @recycle: callback to recycle unused buffers
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 1775fcc7f0e8..698c43dd5dc8 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -179,14 +179,16 @@ extern int v9fs_vfs_rename(struct mnt_idmap *idmap,
struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags);
-extern struct inode *v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid,
- bool new);
+extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
+ struct p9_fid *fid,
+ struct super_block *sb, int new);
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
extern const struct inode_operations v9fs_file_inode_operations_dotl;
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
extern const struct netfs_request_ops v9fs_req_ops;
-extern struct inode *v9fs_fid_iget_dotl(struct super_block *sb,
- struct p9_fid *fid, bool new);
+extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
+ struct p9_fid *fid,
+ struct super_block *sb, int new);
/* other default globals */
#define V9FS_PORT 564
@@ -225,12 +227,30 @@ static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
*/
static inline struct inode *
v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
- struct super_block *sb, bool new)
+ struct super_block *sb)
{
if (v9fs_proto_dotl(v9ses))
- return v9fs_fid_iget_dotl(sb, fid, new);
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 0);
else
- return v9fs_fid_iget(sb, fid, new);
+ return v9fs_inode_from_fid(v9ses, fid, sb, 0);
+}
+
+/**
+ * v9fs_get_new_inode_from_fid - Helper routine to populate an inode by
+ * issuing a attribute request
+ * @v9ses: session information
+ * @fid: fid to issue attribute request for
+ * @sb: superblock on which to create inode
+ *
+ */
+static inline struct inode *
+v9fs_get_new_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb)
+{
+ if (v9fs_proto_dotl(v9ses))
+ return v9fs_inode_from_fid_dotl(v9ses, fid, sb, 1);
+ else
+ return v9fs_inode_from_fid(v9ses, fid, sb, 1);
}
#endif
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 7923c3c347cb..d3aefbec4de6 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -42,7 +42,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_free_inode(struct inode *inode);
void v9fs_set_netfs_context(struct inode *inode);
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, struct p9_qid *qid, umode_t mode, dev_t rdev);
+ struct inode *inode, umode_t mode, dev_t rdev);
void v9fs_evict_inode(struct inode *inode);
#if (BITS_PER_LONG == 32)
#define QID2INO(q) ((ino_t) (((q)->path+2) ^ (((q)->path) >> 32)))
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index fd72fc38c8f5..3e68521f4e2f 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -256,12 +256,9 @@ void v9fs_set_netfs_context(struct inode *inode)
}
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, struct p9_qid *qid, umode_t mode, dev_t rdev)
+ struct inode *inode, umode_t mode, dev_t rdev)
{
int err = 0;
- struct v9fs_inode *v9inode = V9FS_I(inode);
-
- memcpy(&v9inode->qid, qid, sizeof(struct p9_qid));
inode_init_owner(&nop_mnt_idmap, inode, NULL, mode);
inode->i_blocks = 0;
@@ -365,59 +362,105 @@ void v9fs_evict_inode(struct inode *inode)
clear_inode(inode);
}
-struct inode *
-v9fs_fid_iget(struct super_block *sb, struct p9_fid *fid, bool new)
+static int v9fs_test_inode(struct inode *inode, void *data)
+{
+ int umode;
+ dev_t rdev;
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+ struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
+
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ /* don't match inode of different type */
+ if (inode_wrong_type(inode, umode))
+ return 0;
+
+ /* compare qid details */
+ if (memcmp(&v9inode->qid.version,
+ &st->qid.version, sizeof(v9inode->qid.version)))
+ return 0;
+
+ if (v9inode->qid.type != st->qid.type)
+ return 0;
+
+ if (v9inode->qid.path != st->qid.path)
+ return 0;
+ return 1;
+}
+
+static int v9fs_test_new_inode(struct inode *inode, void *data)
+{
+ return 0;
+}
+
+static int v9fs_set_inode(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_wstat *st = (struct p9_wstat *)data;
+
+ memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
+ return 0;
+}
+
+static struct inode *v9fs_qid_iget(struct super_block *sb,
+ struct p9_qid *qid,
+ struct p9_wstat *st,
+ int new)
{
dev_t rdev;
int retval;
umode_t umode;
struct inode *inode;
- struct p9_wstat *st;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ int (*test)(struct inode *inode, void *data);
- inode = iget_locked(sb, QID2INO(&fid->qid));
- if (unlikely(!inode))
- return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
- if (!new) {
- goto done;
- } else {
- p9_debug(P9_DEBUG_VFS, "WARNING: Inode collision %ld\n",
- inode->i_ino);
- iput(inode);
- remove_inode_hash(inode);
- inode = iget_locked(sb, QID2INO(&fid->qid));
- WARN_ON(!(inode->i_state & I_NEW));
- }
- }
+ if (new)
+ test = v9fs_test_new_inode;
+ else
+ test = v9fs_test_inode;
+ inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
/*
* initialize the inode with the stat info
* FIXME!! we may need support for stale inodes
* later.
*/
- st = p9_client_stat(fid);
- if (IS_ERR(st)) {
- retval = PTR_ERR(st);
- goto error;
- }
-
+ inode->i_ino = QID2INO(qid);
umode = p9mode2unixmode(v9ses, st, &rdev);
- retval = v9fs_init_inode(v9ses, inode, &fid->qid, umode, rdev);
- v9fs_stat2inode(st, inode, sb, 0);
- p9stat_free(st);
- kfree(st);
+ retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval)
goto error;
+ v9fs_stat2inode(st, inode, sb, 0);
v9fs_set_netfs_context(inode);
v9fs_cache_inode_get_cookie(inode);
unlock_new_inode(inode);
-done:
return inode;
error:
iget_failed(inode);
return ERR_PTR(retval);
+
+}
+
+struct inode *
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb, int new)
+{
+ struct p9_wstat *st;
+ struct inode *inode = NULL;
+
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return ERR_CAST(st);
+
+ inode = v9fs_qid_iget(sb, &st->qid, st, new);
+ p9stat_free(st);
+ kfree(st);
+ return inode;
}
/**
@@ -449,15 +492,8 @@ static int v9fs_at_to_dotl_flags(int flags)
*/
static void v9fs_dec_count(struct inode *inode)
{
- if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) {
- if (inode->i_nlink) {
- drop_nlink(inode);
- } else {
- p9_debug(P9_DEBUG_VFS,
- "WARNING: unexpected i_nlink zero %d inode %ld\n",
- inode->i_nlink, inode->i_ino);
- }
- }
+ if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
+ drop_nlink(inode);
}
/**
@@ -508,9 +544,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
} else
v9fs_dec_count(inode);
- if (inode->i_nlink <= 0) /* no more refs unhash it */
- remove_inode_hash(inode);
-
v9fs_invalidate_inode_attr(inode);
v9fs_invalidate_inode_attr(dir);
@@ -576,7 +609,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
/*
* instantiate inode and assign the unopened fid to the dentry
*/
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, true);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
p9_debug(P9_DEBUG_VFS,
@@ -704,8 +737,10 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
inode = NULL;
else if (IS_ERR(fid))
inode = ERR_CAST(fid);
+ else if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
+ inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
else
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb, false);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
/*
* If we had a rename on the server and a parallel lookup
* for the new name, then make sure we instantiate with
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index c61b97bd13b9..143ac03b7425 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -52,50 +52,80 @@ static kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
return current_fsgid();
}
+static int v9fs_test_inode_dotl(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
+ /* don't match inode of different type */
+ if (inode_wrong_type(inode, st->st_mode))
+ return 0;
-struct inode *
-v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid, bool new)
+ if (inode->i_generation != st->st_gen)
+ return 0;
+
+ /* compare qid details */
+ if (memcmp(&v9inode->qid.version,
+ &st->qid.version, sizeof(v9inode->qid.version)))
+ return 0;
+
+ if (v9inode->qid.type != st->qid.type)
+ return 0;
+
+ if (v9inode->qid.path != st->qid.path)
+ return 0;
+ return 1;
+}
+
+/* Always get a new inode */
+static int v9fs_test_new_inode_dotl(struct inode *inode, void *data)
+{
+ return 0;
+}
+
+static int v9fs_set_inode_dotl(struct inode *inode, void *data)
+{
+ struct v9fs_inode *v9inode = V9FS_I(inode);
+ struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
+
+ memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
+ inode->i_generation = st->st_gen;
+ return 0;
+}
+
+static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
+ struct p9_qid *qid,
+ struct p9_fid *fid,
+ struct p9_stat_dotl *st,
+ int new)
{
int retval;
struct inode *inode;
- struct p9_stat_dotl *st;
struct v9fs_session_info *v9ses = sb->s_fs_info;
+ int (*test)(struct inode *inode, void *data);
- inode = iget_locked(sb, QID2INO(&fid->qid));
- if (unlikely(!inode))
- return ERR_PTR(-ENOMEM);
- if (!(inode->i_state & I_NEW)) {
- if (!new) {
- goto done;
- } else { /* deal with race condition in inode number reuse */
- p9_debug(P9_DEBUG_ERROR, "WARNING: Inode collision %lx\n",
- inode->i_ino);
- iput(inode);
- remove_inode_hash(inode);
- inode = iget_locked(sb, QID2INO(&fid->qid));
- WARN_ON(!(inode->i_state & I_NEW));
- }
- }
+ if (new)
+ test = v9fs_test_new_inode_dotl;
+ else
+ test = v9fs_test_inode_dotl;
+ inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode_dotl, st);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
/*
* initialize the inode with the stat info
* FIXME!! we may need support for stale inodes
* later.
*/
- st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
- if (IS_ERR(st)) {
- retval = PTR_ERR(st);
- goto error;
- }
-
- retval = v9fs_init_inode(v9ses, inode, &fid->qid,
+ inode->i_ino = QID2INO(qid);
+ retval = v9fs_init_inode(v9ses, inode,
st->st_mode, new_decode_dev(st->st_rdev));
- v9fs_stat2inode_dotl(st, inode, 0);
- kfree(st);
if (retval)
goto error;
+ v9fs_stat2inode_dotl(st, inode, 0);
v9fs_set_netfs_context(inode);
v9fs_cache_inode_get_cookie(inode);
retval = v9fs_get_acl(inode, fid);
@@ -103,11 +133,27 @@ v9fs_fid_iget_dotl(struct super_block *sb, struct p9_fid *fid, bool new)
goto error;
unlock_new_inode(inode);
-done:
return inode;
error:
iget_failed(inode);
return ERR_PTR(retval);
+
+}
+
+struct inode *
+v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
+ struct super_block *sb, int new)
+{
+ struct p9_stat_dotl *st;
+ struct inode *inode = NULL;
+
+ st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
+ if (IS_ERR(st))
+ return ERR_CAST(st);
+
+ inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new);
+ kfree(st);
+ return inode;
}
struct dotl_openflag_map {
@@ -259,7 +305,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
goto out;
}
- inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
@@ -309,6 +355,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap,
umode_t omode)
{
int err;
+ struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
kgid_t gid;
const unsigned char *name;
@@ -318,6 +365,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap,
struct posix_acl *dacl = NULL, *pacl = NULL;
p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
+ v9ses = v9fs_inode2v9ses(dir);
omode |= S_IFDIR;
if (dir->i_mode & S_ISGID)
@@ -352,7 +400,7 @@ static int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap,
}
/* instantiate inode and assign the unopened fid to the dentry */
- inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
@@ -749,6 +797,7 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir,
kgid_t gid;
const unsigned char *name;
umode_t mode;
+ struct v9fs_session_info *v9ses;
struct p9_fid *fid = NULL, *dfid = NULL;
struct inode *inode;
struct p9_qid qid;
@@ -758,6 +807,7 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir,
dir->i_ino, dentry, omode,
MAJOR(rdev), MINOR(rdev));
+ v9ses = v9fs_inode2v9ses(dir);
dfid = v9fs_parent_fid(dentry);
if (IS_ERR(dfid)) {
err = PTR_ERR(dfid);
@@ -788,7 +838,7 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir,
err);
goto error;
}
- inode = v9fs_fid_iget_dotl(dir->i_sb, fid, true);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index f52fdf42945c..489db161abc9 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -139,7 +139,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
else
sb->s_d_op = &v9fs_dentry_operations;
- inode = v9fs_get_inode_from_fid(v9ses, fid, sb, true);
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
goto release_sb;
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index f8622ed72e08..ada363af5aab 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -12,6 +12,7 @@
#include <linux/swap.h>
#include <linux/ctype.h>
#include <linux/sched.h>
+#include <linux/iversion.h>
#include <linux/task_io_accounting_ops.h>
#include "internal.h"
#include "afs_fs.h"
@@ -1823,6 +1824,8 @@ error:
static void afs_rename_success(struct afs_operation *op)
{
+ struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
+
_enter("op=%08x", op->debug_id);
op->ctime = op->file[0].scb.status.mtime_client;
@@ -1832,6 +1835,22 @@ static void afs_rename_success(struct afs_operation *op)
op->ctime = op->file[1].scb.status.mtime_client;
afs_vnode_commit_status(op, &op->file[1]);
}
+
+ /* If we're moving a subdir between dirs, we need to update
+ * its DV counter too as the ".." will be altered.
+ */
+ if (S_ISDIR(vnode->netfs.inode.i_mode) &&
+ op->file[0].vnode != op->file[1].vnode) {
+ u64 new_dv;
+
+ write_seqlock(&vnode->cb_lock);
+
+ new_dv = vnode->status.data_version + 1;
+ vnode->status.data_version = new_dv;
+ inode_set_iversion_raw(&vnode->netfs.inode, new_dv);
+
+ write_sequnlock(&vnode->cb_lock);
+ }
}
static void afs_rename_edit_dir(struct afs_operation *op)
@@ -1873,6 +1892,12 @@ static void afs_rename_edit_dir(struct afs_operation *op)
&vnode->fid, afs_edit_dir_for_rename_2);
}
+ if (S_ISDIR(vnode->netfs.inode.i_mode) &&
+ new_dvnode != orig_dvnode &&
+ test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
+ afs_edit_dir_update_dotdot(vnode, new_dvnode,
+ afs_edit_dir_for_rename_sub);
+
new_inode = d_inode(new_dentry);
if (new_inode) {
spin_lock(&new_inode->i_lock);
diff --git a/fs/afs/dir_edit.c b/fs/afs/dir_edit.c
index a71bff10496b..fe223fb78111 100644
--- a/fs/afs/dir_edit.c
+++ b/fs/afs/dir_edit.c
@@ -127,10 +127,10 @@ static struct folio *afs_dir_get_folio(struct afs_vnode *vnode, pgoff_t index)
/*
* Scan a directory block looking for a dirent of the right name.
*/
-static int afs_dir_scan_block(union afs_xdr_dir_block *block, struct qstr *name,
+static int afs_dir_scan_block(const union afs_xdr_dir_block *block, const struct qstr *name,
unsigned int blocknum)
{
- union afs_xdr_dirent *de;
+ const union afs_xdr_dirent *de;
u64 bitmap;
int d, len, n;
@@ -492,3 +492,90 @@ error:
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
goto out_unmap;
}
+
+/*
+ * Edit a subdirectory that has been moved between directories to update the
+ * ".." entry.
+ */
+void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
+ enum afs_edit_dir_reason why)
+{
+ union afs_xdr_dir_block *block;
+ union afs_xdr_dirent *de;
+ struct folio *folio;
+ unsigned int nr_blocks, b;
+ pgoff_t index;
+ loff_t i_size;
+ int slot;
+
+ _enter("");
+
+ i_size = i_size_read(&vnode->netfs.inode);
+ if (i_size < AFS_DIR_BLOCK_SIZE) {
+ clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
+ return;
+ }
+ nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
+
+ /* Find a block that has sufficient slots available. Each folio
+ * contains two or more directory blocks.
+ */
+ for (b = 0; b < nr_blocks; b++) {
+ index = b / AFS_DIR_BLOCKS_PER_PAGE;
+ folio = afs_dir_get_folio(vnode, index);
+ if (!folio)
+ goto error;
+
+ block = kmap_local_folio(folio, b * AFS_DIR_BLOCK_SIZE - folio_pos(folio));
+
+ /* Abandon the edit if we got a callback break. */
+ if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
+ goto invalidated;
+
+ slot = afs_dir_scan_block(block, &dotdot_name, b);
+ if (slot >= 0)
+ goto found_dirent;
+
+ kunmap_local(block);
+ folio_unlock(folio);
+ folio_put(folio);
+ }
+
+ /* Didn't find the dirent to clobber. Download the directory again. */
+ trace_afs_edit_dir(vnode, why, afs_edit_dir_update_nodd,
+ 0, 0, 0, 0, "..");
+ clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
+ goto out;
+
+found_dirent:
+ de = &block->dirents[slot];
+ de->u.vnode = htonl(new_dvnode->fid.vnode);
+ de->u.unique = htonl(new_dvnode->fid.unique);
+
+ trace_afs_edit_dir(vnode, why, afs_edit_dir_update_dd, b, slot,
+ ntohl(de->u.vnode), ntohl(de->u.unique), "..");
+
+ kunmap_local(block);
+ folio_unlock(folio);
+ folio_put(folio);
+ inode_set_iversion_raw(&vnode->netfs.inode, vnode->status.data_version);
+
+out:
+ _leave("");
+ return;
+
+invalidated:
+ kunmap_local(block);
+ folio_unlock(folio);
+ folio_put(folio);
+ trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
+ 0, 0, 0, 0, "..");
+ clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
+ goto out;
+
+error:
+ trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
+ 0, 0, 0, 0, "..");
+ clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
+ goto out;
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 52aab09a32a9..c9d620175e80 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1073,6 +1073,8 @@ extern void afs_check_for_remote_deletion(struct afs_operation *);
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
enum afs_edit_dir_reason);
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
+void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
+ enum afs_edit_dir_reason why);
/*
* dir_silly.c
diff --git a/fs/autofs/dev-ioctl.c b/fs/autofs/dev-ioctl.c
index f011e026358e..6d57efbb8110 100644
--- a/fs/autofs/dev-ioctl.c
+++ b/fs/autofs/dev-ioctl.c
@@ -110,6 +110,7 @@ static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
*/
static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
{
+ unsigned int inr = _IOC_NR(cmd);
int err;
err = check_dev_ioctl_version(cmd, param);
@@ -133,7 +134,7 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
* check_name() return for AUTOFS_DEV_IOCTL_TIMEOUT_CMD.
*/
err = check_name(param->path);
- if (cmd == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
+ if (inr == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
err = err ? 0 : -EINVAL;
if (err) {
pr_warn("invalid path supplied for cmd(0x%08x)\n",
@@ -141,8 +142,6 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
goto out;
}
} else {
- unsigned int inr = _IOC_NR(cmd);
-
if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) {
diff --git a/fs/backing-file.c b/fs/backing-file.c
index 8860dac58c37..09a9be945d45 100644
--- a/fs/backing-file.c
+++ b/fs/backing-file.c
@@ -80,7 +80,7 @@ struct backing_aio {
refcount_t ref;
struct kiocb *orig_iocb;
/* used for aio completion */
- void (*end_write)(struct file *);
+ void (*end_write)(struct file *, loff_t, ssize_t);
struct work_struct work;
long res;
};
@@ -109,7 +109,7 @@ static void backing_aio_cleanup(struct backing_aio *aio, long res)
struct kiocb *orig_iocb = aio->orig_iocb;
if (aio->end_write)
- aio->end_write(orig_iocb->ki_filp);
+ aio->end_write(orig_iocb->ki_filp, iocb->ki_pos, res);
orig_iocb->ki_pos = iocb->ki_pos;
backing_aio_put(aio);
@@ -239,7 +239,7 @@ ssize_t backing_file_write_iter(struct file *file, struct iov_iter *iter,
ret = vfs_iter_write(file, iter, &iocb->ki_pos, rwf);
if (ctx->end_write)
- ctx->end_write(ctx->user_file);
+ ctx->end_write(ctx->user_file, iocb->ki_pos, ret);
} else {
struct backing_aio *aio;
@@ -317,7 +317,7 @@ ssize_t backing_file_splice_write(struct pipe_inode_info *pipe,
revert_creds(old_cred);
if (ctx->end_write)
- ctx->end_write(ctx->user_file);
+ ctx->end_write(ctx->user_file, ppos ? *ppos : 0, ret);
return ret;
}
diff --git a/fs/bcachefs/alloc_background.h b/fs/bcachefs/alloc_background.h
index f8e87c6721b1..163a67b97a40 100644
--- a/fs/bcachefs/alloc_background.h
+++ b/fs/bcachefs/alloc_background.h
@@ -168,6 +168,9 @@ static inline bool data_type_movable(enum bch_data_type type)
static inline u64 alloc_lru_idx_fragmentation(struct bch_alloc_v4 a,
struct bch_dev *ca)
{
+ if (a.data_type >= BCH_DATA_NR)
+ return 0;
+
if (!data_type_movable(a.data_type) ||
!bch2_bucket_sectors_fragmented(ca, a))
return 0;
diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c
index 5836870ab882..372178c8d416 100644
--- a/fs/bcachefs/alloc_foreground.c
+++ b/fs/bcachefs/alloc_foreground.c
@@ -162,6 +162,10 @@ static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
ARRAY_SIZE(c->open_buckets_partial));
spin_lock(&c->freelist_lock);
+ rcu_read_lock();
+ bch2_dev_rcu(c, ob->dev)->nr_partial_buckets++;
+ rcu_read_unlock();
+
ob->on_partial_list = true;
c->open_buckets_partial[c->open_buckets_partial_nr++] =
ob - c->open_buckets;
@@ -972,7 +976,7 @@ static int bucket_alloc_set_partial(struct bch_fs *c,
u64 avail;
bch2_dev_usage_read_fast(ca, &usage);
- avail = dev_buckets_free(ca, usage, watermark);
+ avail = dev_buckets_free(ca, usage, watermark) + ca->nr_partial_buckets;
if (!avail)
continue;
@@ -981,6 +985,10 @@ static int bucket_alloc_set_partial(struct bch_fs *c,
i);
ob->on_partial_list = false;
+ rcu_read_lock();
+ bch2_dev_rcu(c, ob->dev)->nr_partial_buckets--;
+ rcu_read_unlock();
+
ret = add_new_bucket(c, ptrs, devs_may_alloc,
nr_replicas, nr_effective,
have_cache, ob);
@@ -1191,7 +1199,13 @@ void bch2_open_buckets_stop(struct bch_fs *c, struct bch_dev *ca,
--c->open_buckets_partial_nr;
swap(c->open_buckets_partial[i],
c->open_buckets_partial[c->open_buckets_partial_nr]);
+
ob->on_partial_list = false;
+
+ rcu_read_lock();
+ bch2_dev_rcu(c, ob->dev)->nr_partial_buckets--;
+ rcu_read_unlock();
+
spin_unlock(&c->freelist_lock);
bch2_open_bucket_put(c, ob);
spin_lock(&c->freelist_lock);
@@ -1610,8 +1624,7 @@ void bch2_open_buckets_to_text(struct printbuf *out, struct bch_fs *c,
ob < c->open_buckets + ARRAY_SIZE(c->open_buckets);
ob++) {
spin_lock(&ob->lock);
- if (ob->valid && !ob->on_partial_list &&
- (!ca || ob->dev == ca->dev_idx))
+ if (ob->valid && (!ca || ob->dev == ca->dev_idx))
bch2_open_bucket_to_text(out, c, ob);
spin_unlock(&ob->lock);
}
diff --git a/fs/bcachefs/backpointers.c b/fs/bcachefs/backpointers.c
index 47455a85c909..654a58132a4d 100644
--- a/fs/bcachefs/backpointers.c
+++ b/fs/bcachefs/backpointers.c
@@ -52,6 +52,12 @@ int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
enum bch_validate_flags flags)
{
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
+ int ret = 0;
+
+ bkey_fsck_err_on(bp.v->level > BTREE_MAX_DEPTH,
+ c, backpointer_level_bad,
+ "backpointer level bad: %u >= %u",
+ bp.v->level, BTREE_MAX_DEPTH);
rcu_read_lock();
struct bch_dev *ca = bch2_dev_rcu_noerror(c, bp.k->p.inode);
@@ -64,7 +70,6 @@ int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
struct bpos bucket = bp_pos_to_bucket(ca, bp.k->p);
struct bpos bp_pos = bucket_pos_to_bp_noerror(ca, bucket, bp.v->bucket_offset);
rcu_read_unlock();
- int ret = 0;
bkey_fsck_err_on((bp.v->bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT) >= ca->mi.bucket_size ||
!bpos_eq(bp.k->p, bp_pos),
@@ -947,9 +952,13 @@ int bch2_check_extents_to_backpointers(struct bch_fs *c)
static int check_one_backpointer(struct btree_trans *trans,
struct bbpos start,
struct bbpos end,
- struct bkey_s_c_backpointer bp,
+ struct bkey_s_c bp_k,
struct bkey_buf *last_flushed)
{
+ if (bp_k.k->type != KEY_TYPE_backpointer)
+ return 0;
+
+ struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(bp_k);
struct bch_fs *c = trans->c;
struct btree_iter iter;
struct bbpos pos = bp_to_bbpos(*bp.v);
@@ -1004,9 +1013,7 @@ static int bch2_check_backpointers_to_extents_pass(struct btree_trans *trans,
POS_MIN, BTREE_ITER_prefetch, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
progress_update_iter(trans, &progress, &iter, "backpointers_to_extents");
- check_one_backpointer(trans, start, end,
- bkey_s_c_to_backpointer(k),
- &last_flushed);
+ check_one_backpointer(trans, start, end, k, &last_flushed);
}));
bch2_bkey_buf_exit(&last_flushed, c);
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index f4151ee51b03..e94a83b8113e 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -555,6 +555,7 @@ struct bch_dev {
u64 alloc_cursor[3];
unsigned nr_open_buckets;
+ unsigned nr_partial_buckets;
unsigned nr_btree_reserve;
size_t inc_gen_needs_gc;
diff --git a/fs/bcachefs/bkey.c b/fs/bcachefs/bkey.c
index 587d7318a2e8..995ba32e9b6e 100644
--- a/fs/bcachefs/bkey.c
+++ b/fs/bcachefs/bkey.c
@@ -643,7 +643,7 @@ int bch2_bkey_format_invalid(struct bch_fs *c,
enum bch_validate_flags flags,
struct printbuf *err)
{
- unsigned i, bits = KEY_PACKED_BITS_START;
+ unsigned bits = KEY_PACKED_BITS_START;
if (f->nr_fields != BKEY_NR_FIELDS) {
prt_printf(err, "incorrect number of fields: got %u, should be %u",
@@ -655,9 +655,8 @@ int bch2_bkey_format_invalid(struct bch_fs *c,
* Verify that the packed format can't represent fields larger than the
* unpacked format:
*/
- for (i = 0; i < f->nr_fields; i++) {
- if ((!c || c->sb.version_min >= bcachefs_metadata_version_snapshot) &&
- bch2_bkey_format_field_overflows(f, i)) {
+ for (unsigned i = 0; i < f->nr_fields; i++) {
+ if (bch2_bkey_format_field_overflows(f, i)) {
unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
unsigned packed_bits = min(64, f->bits_per_field[i]);
diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c
index 6e4afb2b5441..7123019ab3bc 100644
--- a/fs/bcachefs/btree_cache.c
+++ b/fs/bcachefs/btree_cache.c
@@ -59,16 +59,38 @@ static inline size_t btree_cache_can_free(struct btree_cache_list *list)
static void btree_node_to_freedlist(struct btree_cache *bc, struct btree *b)
{
+ BUG_ON(!list_empty(&b->list));
+
if (b->c.lock.readers)
- list_move(&b->list, &bc->freed_pcpu);
+ list_add(&b->list, &bc->freed_pcpu);
else
- list_move(&b->list, &bc->freed_nonpcpu);
+ list_add(&b->list, &bc->freed_nonpcpu);
+}
+
+static void __bch2_btree_node_to_freelist(struct btree_cache *bc, struct btree *b)
+{
+ BUG_ON(!list_empty(&b->list));
+ BUG_ON(!b->data);
+
+ bc->nr_freeable++;
+ list_add(&b->list, &bc->freeable);
}
-static void btree_node_data_free(struct bch_fs *c, struct btree *b)
+void bch2_btree_node_to_freelist(struct bch_fs *c, struct btree *b)
{
struct btree_cache *bc = &c->btree_cache;
+ mutex_lock(&bc->lock);
+ __bch2_btree_node_to_freelist(bc, b);
+ mutex_unlock(&bc->lock);
+
+ six_unlock_write(&b->c.lock);
+ six_unlock_intent(&b->c.lock);
+}
+
+static void __btree_node_data_free(struct btree_cache *bc, struct btree *b)
+{
+ BUG_ON(!list_empty(&b->list));
BUG_ON(btree_node_hashed(b));
/*
@@ -94,11 +116,17 @@ static void btree_node_data_free(struct bch_fs *c, struct btree *b)
#endif
b->aux_data = NULL;
- bc->nr_freeable--;
-
btree_node_to_freedlist(bc, b);
}
+static void btree_node_data_free(struct btree_cache *bc, struct btree *b)
+{
+ BUG_ON(list_empty(&b->list));
+ list_del_init(&b->list);
+ --bc->nr_freeable;
+ __btree_node_data_free(bc, b);
+}
+
static int bch2_btree_cache_cmp_fn(struct rhashtable_compare_arg *arg,
const void *obj)
{
@@ -174,21 +202,10 @@ struct btree *__bch2_btree_node_mem_alloc(struct bch_fs *c)
bch2_btree_lock_init(&b->c, 0);
- bc->nr_freeable++;
- list_add(&b->list, &bc->freeable);
+ __bch2_btree_node_to_freelist(bc, b);
return b;
}
-void bch2_btree_node_to_freelist(struct bch_fs *c, struct btree *b)
-{
- mutex_lock(&c->btree_cache.lock);
- list_move(&b->list, &c->btree_cache.freeable);
- mutex_unlock(&c->btree_cache.lock);
-
- six_unlock_write(&b->c.lock);
- six_unlock_intent(&b->c.lock);
-}
-
static inline bool __btree_node_pinned(struct btree_cache *bc, struct btree *b)
{
struct bbpos pos = BBPOS(b->c.btree_id, b->key.k.p);
@@ -236,11 +253,11 @@ void bch2_btree_cache_unpin(struct bch_fs *c)
/* Btree in memory cache - hash table */
-void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
+void __bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
{
lockdep_assert_held(&bc->lock);
- int ret = rhashtable_remove_fast(&bc->table, &b->hash, bch_btree_cache_params);
+ int ret = rhashtable_remove_fast(&bc->table, &b->hash, bch_btree_cache_params);
BUG_ON(ret);
/* Cause future lookups for this node to fail: */
@@ -248,17 +265,22 @@ void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
if (b->c.btree_id < BTREE_ID_NR)
--bc->nr_by_btree[b->c.btree_id];
+ --bc->live[btree_node_pinned(b)].nr;
+ list_del_init(&b->list);
+}
- bc->live[btree_node_pinned(b)].nr--;
- bc->nr_freeable++;
- list_move(&b->list, &bc->freeable);
+void bch2_btree_node_hash_remove(struct btree_cache *bc, struct btree *b)
+{
+ __bch2_btree_node_hash_remove(bc, b);
+ __bch2_btree_node_to_freelist(bc, b);
}
int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b)
{
+ BUG_ON(!list_empty(&b->list));
BUG_ON(b->hash_val);
- b->hash_val = btree_ptr_hash_val(&b->key);
+ b->hash_val = btree_ptr_hash_val(&b->key);
int ret = rhashtable_lookup_insert_fast(&bc->table, &b->hash,
bch_btree_cache_params);
if (ret)
@@ -270,10 +292,8 @@ int __bch2_btree_node_hash_insert(struct btree_cache *bc, struct btree *b)
bool p = __btree_node_pinned(bc, b);
mod_bit(BTREE_NODE_pinned, &b->flags, p);
- list_move_tail(&b->list, &bc->live[p].list);
+ list_add_tail(&b->list, &bc->live[p].list);
bc->live[p].nr++;
-
- bc->nr_freeable--;
return 0;
}
@@ -485,7 +505,7 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink,
goto out;
if (!btree_node_reclaim(c, b, true)) {
- btree_node_data_free(c, b);
+ btree_node_data_free(bc, b);
six_unlock_write(&b->c.lock);
six_unlock_intent(&b->c.lock);
freed++;
@@ -501,10 +521,10 @@ restart:
bc->not_freed[BCH_BTREE_CACHE_NOT_FREED_access_bit]++;
--touched;;
} else if (!btree_node_reclaim(c, b, true)) {
- bch2_btree_node_hash_remove(bc, b);
+ __bch2_btree_node_hash_remove(bc, b);
+ __btree_node_data_free(bc, b);
freed++;
- btree_node_data_free(c, b);
bc->nr_freed++;
six_unlock_write(&b->c.lock);
@@ -587,7 +607,7 @@ void bch2_fs_btree_cache_exit(struct bch_fs *c)
BUG_ON(btree_node_read_in_flight(b) ||
btree_node_write_in_flight(b));
- btree_node_data_free(c, b);
+ btree_node_data_free(bc, b);
}
BUG_ON(!bch2_journal_error(&c->journal) &&
@@ -786,8 +806,8 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea
BUG_ON(!six_trylock_intent(&b->c.lock));
BUG_ON(!six_trylock_write(&b->c.lock));
-got_node:
+got_node:
/*
* btree_free() doesn't free memory; it sticks the node on the end of
* the list. Check if there's any freed nodes there:
@@ -796,7 +816,12 @@ got_node:
if (!btree_node_reclaim(c, b2, false)) {
swap(b->data, b2->data);
swap(b->aux_data, b2->aux_data);
+
+ list_del_init(&b2->list);
+ --bc->nr_freeable;
btree_node_to_freedlist(bc, b2);
+ mutex_unlock(&bc->lock);
+
six_unlock_write(&b2->c.lock);
six_unlock_intent(&b2->c.lock);
goto got_mem;
@@ -810,11 +835,8 @@ got_node:
goto err;
}
- mutex_lock(&bc->lock);
- bc->nr_freeable++;
got_mem:
- mutex_unlock(&bc->lock);
-
+ BUG_ON(!list_empty(&b->list));
BUG_ON(btree_node_hashed(b));
BUG_ON(btree_node_dirty(b));
BUG_ON(btree_node_write_in_flight(b));
@@ -845,7 +867,7 @@ err:
if (bc->alloc_lock == current) {
b2 = btree_node_cannibalize(c);
clear_btree_node_just_written(b2);
- bch2_btree_node_hash_remove(bc, b2);
+ __bch2_btree_node_hash_remove(bc, b2);
if (b) {
swap(b->data, b2->data);
@@ -855,9 +877,9 @@ err:
six_unlock_intent(&b2->c.lock);
} else {
b = b2;
- list_del_init(&b->list);
}
+ BUG_ON(!list_empty(&b->list));
mutex_unlock(&bc->lock);
trace_and_count(c, btree_cache_cannibalize, trans);
@@ -936,7 +958,7 @@ static noinline struct btree *bch2_btree_node_fill(struct btree_trans *trans,
b->hash_val = 0;
mutex_lock(&bc->lock);
- list_add(&b->list, &bc->freeable);
+ __bch2_btree_node_to_freelist(bc, b);
mutex_unlock(&bc->lock);
six_unlock_write(&b->c.lock);
@@ -1312,9 +1334,12 @@ int bch2_btree_node_prefetch(struct btree_trans *trans,
b = bch2_btree_node_fill(trans, path, k, btree_id,
level, SIX_LOCK_read, false);
- if (!IS_ERR_OR_NULL(b))
+ int ret = PTR_ERR_OR_ZERO(b);
+ if (ret)
+ return ret;
+ if (b)
six_unlock_read(&b->c.lock);
- return bch2_trans_relock(trans) ?: PTR_ERR_OR_ZERO(b);
+ return 0;
}
void bch2_btree_node_evict(struct btree_trans *trans, const struct bkey_i *k)
@@ -1353,7 +1378,7 @@ wait_on_io:
mutex_lock(&bc->lock);
bch2_btree_node_hash_remove(bc, b);
- btree_node_data_free(c, b);
+ btree_node_data_free(bc, b);
mutex_unlock(&bc->lock);
out:
six_unlock_write(&b->c.lock);
diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h
index 367acd217c6a..66e86d1a178d 100644
--- a/fs/bcachefs/btree_cache.h
+++ b/fs/bcachefs/btree_cache.h
@@ -14,7 +14,9 @@ void bch2_recalc_btree_reserve(struct bch_fs *);
void bch2_btree_node_to_freelist(struct bch_fs *, struct btree *);
+void __bch2_btree_node_hash_remove(struct btree_cache *, struct btree *);
void bch2_btree_node_hash_remove(struct btree_cache *, struct btree *);
+
int __bch2_btree_node_hash_insert(struct btree_cache *, struct btree *);
int bch2_btree_node_hash_insert(struct btree_cache *, struct btree *,
unsigned, enum btree_id);
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index 0ca3feeb42c8..81dcf9e512c0 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -182,7 +182,7 @@ static int set_node_max(struct bch_fs *c, struct btree *b, struct bpos new_max)
bch2_btree_node_drop_keys_outside_node(b);
mutex_lock(&c->btree_cache.lock);
- bch2_btree_node_hash_remove(&c->btree_cache, b);
+ __bch2_btree_node_hash_remove(&c->btree_cache, b);
bkey_copy(&b->key, &new->k_i);
ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c
index 6296a11ccb09..839d68802e42 100644
--- a/fs/bcachefs/btree_io.c
+++ b/fs/bcachefs/btree_io.c
@@ -733,11 +733,8 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
c, ca, b, i, NULL,
bset_past_end_of_btree_node,
"bset past end of btree node (offset %u len %u but written %zu)",
- offset, sectors, ptr_written ?: btree_sectors(c))) {
+ offset, sectors, ptr_written ?: btree_sectors(c)))
i->u64s = 0;
- ret = 0;
- goto out;
- }
btree_err_on(offset && !i->u64s,
-BCH_ERR_btree_node_read_err_fixable,
@@ -829,7 +826,6 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
BSET_BIG_ENDIAN(i), write,
&bn->format);
}
-out:
fsck_err:
printbuf_exit(&buf2);
printbuf_exit(&buf1);
diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c
index 0883cf6e1a3e..eef9b89c561d 100644
--- a/fs/bcachefs/btree_iter.c
+++ b/fs/bcachefs/btree_iter.c
@@ -882,6 +882,18 @@ static noinline int btree_node_iter_and_journal_peek(struct btree_trans *trans,
__bch2_btree_and_journal_iter_init_node_iter(trans, &jiter, l->b, l->iter, path->pos);
k = bch2_btree_and_journal_iter_peek(&jiter);
+ if (!k.k) {
+ struct printbuf buf = PRINTBUF;
+
+ prt_str(&buf, "node not found at pos ");
+ bch2_bpos_to_text(&buf, path->pos);
+ prt_str(&buf, " at btree ");
+ bch2_btree_pos_to_text(&buf, c, l->b);
+
+ ret = bch2_fs_topology_error(c, "%s", buf.buf);
+ printbuf_exit(&buf);
+ goto err;
+ }
bch2_bkey_buf_reassemble(out, c, k);
@@ -889,6 +901,7 @@ static noinline int btree_node_iter_and_journal_peek(struct btree_trans *trans,
c->opts.btree_node_prefetch)
ret = btree_path_prefetch_j(trans, path, &jiter);
+err:
bch2_btree_and_journal_iter_exit(&jiter);
return ret;
}
diff --git a/fs/bcachefs/btree_node_scan.c b/fs/bcachefs/btree_node_scan.c
index a7aedb134e9f..30131c3bdd97 100644
--- a/fs/bcachefs/btree_node_scan.c
+++ b/fs/bcachefs/btree_node_scan.c
@@ -186,7 +186,7 @@ static void try_read_btree_node(struct find_btree_nodes *f, struct bch_dev *ca,
.ptrs[0].type = 1 << BCH_EXTENT_ENTRY_ptr,
.ptrs[0].offset = offset,
.ptrs[0].dev = ca->dev_idx,
- .ptrs[0].gen = *bucket_gen(ca, sector_to_bucket(ca, offset)),
+ .ptrs[0].gen = bucket_gen_get(ca, sector_to_bucket(ca, offset)),
};
rcu_read_unlock();
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 64f0928e1137..d596ef93239f 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -237,10 +237,6 @@ static void __btree_node_free(struct btree_trans *trans, struct btree *b)
BUG_ON(b->will_make_reachable);
clear_btree_node_noevict(b);
-
- mutex_lock(&c->btree_cache.lock);
- list_move(&b->list, &c->btree_cache.freeable);
- mutex_unlock(&c->btree_cache.lock);
}
static void bch2_btree_node_free_inmem(struct btree_trans *trans,
@@ -252,12 +248,12 @@ static void bch2_btree_node_free_inmem(struct btree_trans *trans,
bch2_btree_node_lock_write_nofail(trans, path, &b->c);
+ __btree_node_free(trans, b);
+
mutex_lock(&c->btree_cache.lock);
bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock);
- __btree_node_free(trans, b);
-
six_unlock_write(&b->c.lock);
mark_btree_node_locked_noreset(path, level, BTREE_NODE_INTENT_LOCKED);
@@ -289,7 +285,7 @@ static void bch2_btree_node_free_never_used(struct btree_update *as,
clear_btree_node_need_write(b);
mutex_lock(&c->btree_cache.lock);
- bch2_btree_node_hash_remove(&c->btree_cache, b);
+ __bch2_btree_node_hash_remove(&c->btree_cache, b);
mutex_unlock(&c->btree_cache.lock);
BUG_ON(p->nr >= ARRAY_SIZE(p->b));
@@ -521,8 +517,7 @@ static void bch2_btree_reserve_put(struct btree_update *as, struct btree_trans *
btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_intent);
btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_write);
__btree_node_free(trans, b);
- six_unlock_write(&b->c.lock);
- six_unlock_intent(&b->c.lock);
+ bch2_btree_node_to_freelist(c, b);
}
}
}
@@ -1434,6 +1429,15 @@ bch2_btree_insert_keys_interior(struct btree_update *as,
}
}
+static bool key_deleted_in_insert(struct keylist *insert_keys, struct bpos pos)
+{
+ if (insert_keys)
+ for_each_keylist_key(insert_keys, k)
+ if (bkey_deleted(&k->k) && bpos_eq(k->k.p, pos))
+ return true;
+ return false;
+}
+
/*
* Move keys from n1 (original replacement node, now lower node) to n2 (higher
* node)
@@ -1441,7 +1445,8 @@ bch2_btree_insert_keys_interior(struct btree_update *as,
static void __btree_split_node(struct btree_update *as,
struct btree_trans *trans,
struct btree *b,
- struct btree *n[2])
+ struct btree *n[2],
+ struct keylist *insert_keys)
{
struct bkey_packed *k;
struct bpos n1_pos = POS_MIN;
@@ -1476,7 +1481,8 @@ static void __btree_split_node(struct btree_update *as,
if (b->c.level &&
u64s < n1_u64s &&
u64s + k->u64s >= n1_u64s &&
- bch2_key_deleted_in_journal(trans, b->c.btree_id, b->c.level, uk.p))
+ (bch2_key_deleted_in_journal(trans, b->c.btree_id, b->c.level, uk.p) ||
+ key_deleted_in_insert(insert_keys, uk.p)))
n1_u64s += k->u64s;
i = u64s >= n1_u64s;
@@ -1603,7 +1609,7 @@ static int btree_split(struct btree_update *as, struct btree_trans *trans,
n[0] = n1 = bch2_btree_node_alloc(as, trans, b->c.level);
n[1] = n2 = bch2_btree_node_alloc(as, trans, b->c.level);
- __btree_split_node(as, trans, b, n);
+ __btree_split_node(as, trans, b, n, keys);
if (keys) {
btree_split_insert_keys(as, trans, path, n1, keys);
@@ -2392,7 +2398,8 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
if (new_hash) {
mutex_lock(&c->btree_cache.lock);
bch2_btree_node_hash_remove(&c->btree_cache, new_hash);
- bch2_btree_node_hash_remove(&c->btree_cache, b);
+
+ __bch2_btree_node_hash_remove(&c->btree_cache, b);
bkey_copy(&b->key, new_key);
ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
diff --git a/fs/bcachefs/btree_write_buffer.c b/fs/bcachefs/btree_write_buffer.c
index 3f56b584f8ec..1639c60dffa0 100644
--- a/fs/bcachefs/btree_write_buffer.c
+++ b/fs/bcachefs/btree_write_buffer.c
@@ -277,6 +277,10 @@ static int bch2_btree_write_buffer_flush_locked(struct btree_trans *trans)
bool accounting_replay_done = test_bit(BCH_FS_accounting_replay_done, &c->flags);
int ret = 0;
+ ret = bch2_journal_error(&c->journal);
+ if (ret)
+ return ret;
+
bch2_trans_unlock(trans);
bch2_trans_begin(trans);
@@ -491,7 +495,8 @@ static int fetch_wb_keys_from_journal(struct bch_fs *c, u64 seq)
return ret;
}
-static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)
+static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq,
+ bool *did_work)
{
struct bch_fs *c = trans->c;
struct btree_write_buffer *wb = &c->btree_write_buffer;
@@ -502,6 +507,8 @@ static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)
fetch_from_journal_err = fetch_wb_keys_from_journal(c, seq);
+ *did_work |= wb->inc.keys.nr || wb->flushing.keys.nr;
+
/*
* On memory allocation failure, bch2_btree_write_buffer_flush_locked()
* is not guaranteed to empty wb->inc:
@@ -521,17 +528,34 @@ static int bch2_btree_write_buffer_journal_flush(struct journal *j,
struct journal_entry_pin *_pin, u64 seq)
{
struct bch_fs *c = container_of(j, struct bch_fs, journal);
+ bool did_work = false;
- return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq));
+ return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq, &did_work));
}
int bch2_btree_write_buffer_flush_sync(struct btree_trans *trans)
{
struct bch_fs *c = trans->c;
+ bool did_work = false;
trace_and_count(c, write_buffer_flush_sync, trans, _RET_IP_);
- return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal));
+ return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal), &did_work);
+}
+
+/*
+ * The write buffer requires flushing when going RO: keys in the journal for the
+ * write buffer don't have a journal pin yet
+ */
+bool bch2_btree_write_buffer_flush_going_ro(struct bch_fs *c)
+{
+ if (bch2_journal_error(&c->journal))
+ return false;
+
+ bool did_work = false;
+ bch2_trans_run(c, btree_write_buffer_flush_seq(trans,
+ journal_cur_seq(&c->journal), &did_work));
+ return did_work;
}
int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *trans)
diff --git a/fs/bcachefs/btree_write_buffer.h b/fs/bcachefs/btree_write_buffer.h
index 725e79654216..d535cea28bde 100644
--- a/fs/bcachefs/btree_write_buffer.h
+++ b/fs/bcachefs/btree_write_buffer.h
@@ -21,6 +21,7 @@ static inline bool bch2_btree_write_buffer_must_wait(struct bch_fs *c)
struct btree_trans;
int bch2_btree_write_buffer_flush_sync(struct btree_trans *);
+bool bch2_btree_write_buffer_flush_going_ro(struct bch_fs *);
int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *);
int bch2_btree_write_buffer_tryflush(struct btree_trans *);
diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h
index fd5e6ccad45e..ccc78bfe2fd4 100644
--- a/fs/bcachefs/buckets.h
+++ b/fs/bcachefs/buckets.h
@@ -103,12 +103,18 @@ static inline u8 *bucket_gen(struct bch_dev *ca, size_t b)
return gens->b + b;
}
-static inline u8 bucket_gen_get(struct bch_dev *ca, size_t b)
+static inline int bucket_gen_get_rcu(struct bch_dev *ca, size_t b)
+{
+ u8 *gen = bucket_gen(ca, b);
+ return gen ? *gen : -1;
+}
+
+static inline int bucket_gen_get(struct bch_dev *ca, size_t b)
{
rcu_read_lock();
- u8 gen = *bucket_gen(ca, b);
+ int ret = bucket_gen_get_rcu(ca, b);
rcu_read_unlock();
- return gen;
+ return ret;
}
static inline size_t PTR_BUCKET_NR(const struct bch_dev *ca,
@@ -169,10 +175,8 @@ static inline int gen_after(u8 a, u8 b)
static inline int dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr)
{
- u8 *gen = bucket_gen(ca, PTR_BUCKET_NR(ca, ptr));
- if (!gen)
- return -1;
- return gen_after(*gen, ptr->gen);
+ int gen = bucket_gen_get_rcu(ca, PTR_BUCKET_NR(ca, ptr));
+ return gen < 0 ? gen : gen_after(gen, ptr->gen);
}
/**
@@ -184,7 +188,6 @@ static inline int dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr
rcu_read_lock();
int ret = dev_ptr_stale_rcu(ca, ptr);
rcu_read_unlock();
-
return ret;
}
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c
index a6ee0beee6b0..8e75a852b358 100644
--- a/fs/bcachefs/data_update.c
+++ b/fs/bcachefs/data_update.c
@@ -236,7 +236,8 @@ static int __bch2_data_update_index_update(struct btree_trans *trans,
if (((1U << i) & m->data_opts.rewrite_ptrs) &&
(ptr = bch2_extent_has_ptr(old, p, bkey_i_to_s(insert))) &&
!ptr->cached) {
- bch2_extent_ptr_set_cached(bkey_i_to_s(insert), ptr);
+ bch2_extent_ptr_set_cached(c, &m->op.opts,
+ bkey_i_to_s(insert), ptr);
rewrites_found |= 1U << i;
}
i++;
@@ -284,7 +285,8 @@ restart_drop_extra_replicas:
durability - ptr_durability >= m->op.opts.data_replicas) {
durability -= ptr_durability;
- bch2_extent_ptr_set_cached(bkey_i_to_s(insert), &entry->ptr);
+ bch2_extent_ptr_set_cached(c, &m->op.opts,
+ bkey_i_to_s(insert), &entry->ptr);
goto restart_drop_extra_replicas;
}
}
@@ -295,7 +297,7 @@ restart_drop_extra_replicas:
bch2_extent_ptr_decoded_append(insert, &p);
bch2_bkey_narrow_crcs(insert, (struct bch_extent_crc_unpacked) { 0 });
- bch2_extent_normalize(c, bkey_i_to_s(insert));
+ bch2_extent_normalize_by_opts(c, &m->op.opts, bkey_i_to_s(insert));
ret = bch2_sum_sector_overwrites(trans, &iter, insert,
&should_check_enospc,
@@ -558,7 +560,8 @@ void bch2_data_update_to_text(struct printbuf *out, struct data_update *m)
int bch2_extent_drop_ptrs(struct btree_trans *trans,
struct btree_iter *iter,
struct bkey_s_c k,
- struct data_update_opts data_opts)
+ struct bch_io_opts *io_opts,
+ struct data_update_opts *data_opts)
{
struct bch_fs *c = trans->c;
struct bkey_i *n;
@@ -569,11 +572,11 @@ int bch2_extent_drop_ptrs(struct btree_trans *trans,
if (ret)
return ret;
- while (data_opts.kill_ptrs) {
- unsigned i = 0, drop = __fls(data_opts.kill_ptrs);
+ while (data_opts->kill_ptrs) {
+ unsigned i = 0, drop = __fls(data_opts->kill_ptrs);
bch2_bkey_drop_ptrs_noerror(bkey_i_to_s(n), ptr, i++ == drop);
- data_opts.kill_ptrs ^= 1U << drop;
+ data_opts->kill_ptrs ^= 1U << drop;
}
/*
@@ -581,7 +584,7 @@ int bch2_extent_drop_ptrs(struct btree_trans *trans,
* will do the appropriate thing with it (turning it into a
* KEY_TYPE_error key, or just a discard if it was a cached extent)
*/
- bch2_extent_normalize(c, bkey_i_to_s(n));
+ bch2_extent_normalize_by_opts(c, io_opts, bkey_i_to_s(n));
/*
* Since we're not inserting through an extent iterator
@@ -720,7 +723,7 @@ int bch2_data_update_init(struct btree_trans *trans,
m->data_opts.rewrite_ptrs = 0;
/* if iter == NULL, it's just a promote */
if (iter)
- ret = bch2_extent_drop_ptrs(trans, iter, k, m->data_opts);
+ ret = bch2_extent_drop_ptrs(trans, iter, k, &io_opts, &m->data_opts);
goto out;
}
diff --git a/fs/bcachefs/data_update.h b/fs/bcachefs/data_update.h
index 8d36365bdea8..e4b50723428e 100644
--- a/fs/bcachefs/data_update.h
+++ b/fs/bcachefs/data_update.h
@@ -40,7 +40,8 @@ void bch2_data_update_read_done(struct data_update *,
int bch2_extent_drop_ptrs(struct btree_trans *,
struct btree_iter *,
struct bkey_s_c,
- struct data_update_opts);
+ struct bch_io_opts *,
+ struct data_update_opts *);
void bch2_data_update_exit(struct data_update *);
int bch2_data_update_init(struct btree_trans *, struct btree_iter *,
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index a0aa5bb467d9..749dcf368841 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -1870,6 +1870,10 @@ __bch2_ec_stripe_head_get(struct btree_trans *trans,
}
h = ec_new_stripe_head_alloc(c, disk_label, algo, redundancy, watermark);
+ if (!h) {
+ h = ERR_PTR(-BCH_ERR_ENOMEM_stripe_head_alloc);
+ goto err;
+ }
found:
if (h->rw_devs_change_count != c->rw_devs_change_count)
ec_stripe_head_devs_update(c, h);
diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h
index 649263516ab1..9c4fe5cdbfb7 100644
--- a/fs/bcachefs/errcode.h
+++ b/fs/bcachefs/errcode.h
@@ -83,6 +83,8 @@
x(ENOMEM, ENOMEM_fs_other_alloc) \
x(ENOMEM, ENOMEM_dev_alloc) \
x(ENOMEM, ENOMEM_disk_accounting) \
+ x(ENOMEM, ENOMEM_stripe_head_alloc) \
+ x(ENOMEM, ENOMEM_journal_read_bucket) \
x(ENOSPC, ENOSPC_disk_reservation) \
x(ENOSPC, ENOSPC_bucket_alloc) \
x(ENOSPC, ENOSPC_disk_label_add) \
@@ -222,6 +224,7 @@
x(BCH_ERR_invalid_sb_layout, invalid_sb_layout_type) \
x(BCH_ERR_invalid_sb_layout, invalid_sb_layout_nr_superblocks) \
x(BCH_ERR_invalid_sb_layout, invalid_sb_layout_superblocks_overlap) \
+ x(BCH_ERR_invalid_sb_layout, invalid_sb_layout_sb_max_size_bits) \
x(BCH_ERR_invalid_sb, invalid_sb_members_missing) \
x(BCH_ERR_invalid_sb, invalid_sb_members) \
x(BCH_ERR_invalid_sb, invalid_sb_disk_groups) \
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index cc0d22085aef..37e3d69bec06 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -978,31 +978,54 @@ bch2_extent_has_ptr(struct bkey_s_c k1, struct extent_ptr_decoded p1, struct bke
return NULL;
}
-void bch2_extent_ptr_set_cached(struct bkey_s k, struct bch_extent_ptr *ptr)
+static bool want_cached_ptr(struct bch_fs *c, struct bch_io_opts *opts,
+ struct bch_extent_ptr *ptr)
+{
+ if (!opts->promote_target ||
+ !bch2_dev_in_target(c, ptr->dev, opts->promote_target))
+ return false;
+
+ struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev);
+
+ return ca && bch2_dev_is_readable(ca) && !dev_ptr_stale_rcu(ca, ptr);
+}
+
+void bch2_extent_ptr_set_cached(struct bch_fs *c,
+ struct bch_io_opts *opts,
+ struct bkey_s k,
+ struct bch_extent_ptr *ptr)
{
struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
union bch_extent_entry *entry;
- union bch_extent_entry *ec = NULL;
+ struct extent_ptr_decoded p;
- bkey_extent_entry_for_each(ptrs, entry) {
+ rcu_read_lock();
+ if (!want_cached_ptr(c, opts, ptr)) {
+ bch2_bkey_drop_ptr_noerror(k, ptr);
+ goto out;
+ }
+
+ /*
+ * Stripes can't contain cached data, for - reasons.
+ *
+ * Possibly something we can fix in the future?
+ */
+ bkey_for_each_ptr_decode(k.k, ptrs, p, entry)
if (&entry->ptr == ptr) {
- ptr->cached = true;
- if (ec)
- extent_entry_drop(k, ec);
- return;
+ if (p.has_ec)
+ bch2_bkey_drop_ptr_noerror(k, ptr);
+ else
+ ptr->cached = true;
+ goto out;
}
- if (extent_entry_is_stripe_ptr(entry))
- ec = entry;
- else if (extent_entry_is_ptr(entry))
- ec = NULL;
- }
-
BUG();
+out:
+ rcu_read_unlock();
}
/*
- * bch_extent_normalize - clean up an extent, dropping stale pointers etc.
+ * bch2_extent_normalize - clean up an extent, dropping stale pointers etc.
*
* Returns true if @k should be dropped entirely
*
@@ -1016,8 +1039,39 @@ bool bch2_extent_normalize(struct bch_fs *c, struct bkey_s k)
rcu_read_lock();
bch2_bkey_drop_ptrs(k, ptr,
ptr->cached &&
- (ca = bch2_dev_rcu(c, ptr->dev)) &&
- dev_ptr_stale_rcu(ca, ptr) > 0);
+ (!(ca = bch2_dev_rcu(c, ptr->dev)) ||
+ dev_ptr_stale_rcu(ca, ptr) > 0));
+ rcu_read_unlock();
+
+ return bkey_deleted(k.k);
+}
+
+/*
+ * bch2_extent_normalize_by_opts - clean up an extent, dropping stale pointers etc.
+ *
+ * Like bch2_extent_normalize(), but also only keeps a single cached pointer on
+ * the promote target.
+ */
+bool bch2_extent_normalize_by_opts(struct bch_fs *c,
+ struct bch_io_opts *opts,
+ struct bkey_s k)
+{
+ struct bkey_ptrs ptrs;
+ bool have_cached_ptr;
+
+ rcu_read_lock();
+restart_drop_ptrs:
+ ptrs = bch2_bkey_ptrs(k);
+ have_cached_ptr = false;
+
+ bkey_for_each_ptr(ptrs, ptr)
+ if (ptr->cached) {
+ if (have_cached_ptr || !want_cached_ptr(c, opts, ptr)) {
+ bch2_bkey_drop_ptr(k, ptr);
+ goto restart_drop_ptrs;
+ }
+ have_cached_ptr = true;
+ }
rcu_read_unlock();
return bkey_deleted(k.k);
@@ -1310,7 +1364,7 @@ void bch2_ptr_swab(struct bkey_s k)
for (entry = ptrs.start;
entry < ptrs.end;
entry = extent_entry_next(entry)) {
- switch (extent_entry_type(entry)) {
+ switch (__extent_entry_type(entry)) {
case BCH_EXTENT_ENTRY_ptr:
break;
case BCH_EXTENT_ENTRY_crc32:
@@ -1330,6 +1384,9 @@ void bch2_ptr_swab(struct bkey_s k)
break;
case BCH_EXTENT_ENTRY_rebalance:
break;
+ default:
+ /* Bad entry type: will be caught by validate() */
+ return;
}
}
}
diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h
index 923a5f1849a8..bcffcf60aaaf 100644
--- a/fs/bcachefs/extents.h
+++ b/fs/bcachefs/extents.h
@@ -686,9 +686,12 @@ bool bch2_extents_match(struct bkey_s_c, struct bkey_s_c);
struct bch_extent_ptr *
bch2_extent_has_ptr(struct bkey_s_c, struct extent_ptr_decoded, struct bkey_s);
-void bch2_extent_ptr_set_cached(struct bkey_s, struct bch_extent_ptr *);
+void bch2_extent_ptr_set_cached(struct bch_fs *, struct bch_io_opts *,
+ struct bkey_s, struct bch_extent_ptr *);
+bool bch2_extent_normalize_by_opts(struct bch_fs *, struct bch_io_opts *, struct bkey_s);
bool bch2_extent_normalize(struct bch_fs *, struct bkey_s);
+
void bch2_extent_ptr_to_text(struct printbuf *out, struct bch_fs *, const struct bch_extent_ptr *);
void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c);
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index 15d3f073b824..2456c41b215e 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -587,7 +587,7 @@ static noinline int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
POS(inode->v.i_ino, start_sector),
BTREE_ITER_slots|BTREE_ITER_intent);
- while (!ret && bkey_lt(iter.pos, end_pos)) {
+ while (!ret) {
s64 i_sectors_delta = 0;
struct quota_res quota_res = { 0 };
struct bkey_s_c k;
@@ -598,6 +598,9 @@ static noinline int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
bch2_trans_begin(trans);
+ if (bkey_ge(iter.pos, end_pos))
+ break;
+
ret = bch2_subvolume_get_snapshot(trans,
inode->ei_inum.subvol, &snapshot);
if (ret)
@@ -634,12 +637,15 @@ static noinline int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
if (bch2_clamp_data_hole(&inode->v,
&hole_start,
&hole_end,
- opts.data_replicas, true))
+ opts.data_replicas, true)) {
ret = drop_locks_do(trans,
(bch2_clamp_data_hole(&inode->v,
&hole_start,
&hole_end,
opts.data_replicas, false), 0));
+ if (ret)
+ goto bkey_err;
+ }
bch2_btree_iter_set_pos(&iter, POS(iter.pos.inode, hole_start));
if (ret)
@@ -667,10 +673,13 @@ static noinline int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
bch2_i_sectors_acct(c, inode, &quota_res, i_sectors_delta);
if (bch2_mark_pagecache_reserved(inode, &hole_start,
- iter.pos.offset, true))
- drop_locks_do(trans,
+ iter.pos.offset, true)) {
+ ret = drop_locks_do(trans,
bch2_mark_pagecache_reserved(inode, &hole_start,
iter.pos.offset, false));
+ if (ret)
+ goto bkey_err;
+ }
bkey_err:
bch2_quota_reservation_put(c, inode, &quota_res);
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
diff --git a/fs/bcachefs/io_read.c b/fs/bcachefs/io_read.c
index fc246f342820..b3b934a87c6d 100644
--- a/fs/bcachefs/io_read.c
+++ b/fs/bcachefs/io_read.c
@@ -262,7 +262,8 @@ err:
bio_free_pages(&(*rbio)->bio);
kfree(*rbio);
*rbio = NULL;
- kfree(op);
+ /* We may have added to the rhashtable and thus need rcu freeing: */
+ kfree_rcu(op, rcu);
bch2_write_ref_put(c, BCH_WRITE_REF_promote);
return ERR_PTR(ret);
}
@@ -802,16 +803,15 @@ static noinline void read_from_stale_dirty_pointer(struct btree_trans *trans,
PTR_BUCKET_POS(ca, &ptr),
BTREE_ITER_cached);
- u8 *gen = bucket_gen(ca, iter.pos.offset);
- if (gen) {
-
+ int gen = bucket_gen_get(ca, iter.pos.offset);
+ if (gen >= 0) {
prt_printf(&buf, "Attempting to read from stale dirty pointer:\n");
printbuf_indent_add(&buf, 2);
bch2_bkey_val_to_text(&buf, c, k);
prt_newline(&buf);
- prt_printf(&buf, "memory gen: %u", *gen);
+ prt_printf(&buf, "memory gen: %u", gen);
ret = lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_slot(&iter)));
if (!ret) {
diff --git a/fs/bcachefs/io_write.c b/fs/bcachefs/io_write.c
index 8609e25e450f..96720adcfee0 100644
--- a/fs/bcachefs/io_write.c
+++ b/fs/bcachefs/io_write.c
@@ -1300,11 +1300,8 @@ retry:
bucket_to_u64(i->b),
BUCKET_NOCOW_LOCK_UPDATE);
- rcu_read_lock();
- u8 *gen = bucket_gen(ca, i->b.offset);
- stale = !gen ? -1 : gen_after(*gen, i->gen);
- rcu_read_unlock();
-
+ int gen = bucket_gen_get(ca, i->b.offset);
+ stale = gen < 0 ? gen : gen_after(gen, i->gen);
if (unlikely(stale)) {
stale_at = i;
goto err_bucket_stale;
diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c
index 954f6a96e0f4..fb35dd336331 100644
--- a/fs/bcachefs/journal_io.c
+++ b/fs/bcachefs/journal_io.c
@@ -708,6 +708,9 @@ static void journal_entry_dev_usage_to_text(struct printbuf *out, struct bch_fs
container_of(entry, struct jset_entry_dev_usage, entry);
unsigned i, nr_types = jset_entry_dev_usage_nr_types(u);
+ if (vstruct_bytes(entry) < sizeof(*u))
+ return;
+
prt_printf(out, "dev=%u", le32_to_cpu(u->dev));
printbuf_indent_add(out, 2);
@@ -1012,6 +1015,8 @@ reread:
nr_bvecs = buf_pages(buf->data, sectors_read << 9);
bio = bio_kmalloc(nr_bvecs, GFP_KERNEL);
+ if (!bio)
+ return -BCH_ERR_ENOMEM_journal_read_bucket;
bio_init(bio, ca->disk_sb.bdev, bio->bi_inline_vecs, nr_bvecs, REQ_OP_READ);
bio->bi_iter.bi_sector = offset;
diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c
index 8c456d8b8b99..0ef4a86850bb 100644
--- a/fs/bcachefs/move.c
+++ b/fs/bcachefs/move.c
@@ -266,7 +266,7 @@ int bch2_move_extent(struct moving_context *ctxt,
if (!data_opts.rewrite_ptrs &&
!data_opts.extra_replicas) {
if (data_opts.kill_ptrs)
- return bch2_extent_drop_ptrs(trans, iter, k, data_opts);
+ return bch2_extent_drop_ptrs(trans, iter, k, &io_opts, &data_opts);
return 0;
}
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index 6673cbd8bdb9..0e2ee262fbd4 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -226,7 +226,7 @@ const struct bch_option bch2_opt_table[] = {
#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, \
.min = _min, .max = _max
#define OPT_STR(_choices) .type = BCH_OPT_STR, \
- .min = 0, .max = ARRAY_SIZE(_choices), \
+ .min = 0, .max = ARRAY_SIZE(_choices) - 1, \
.choices = _choices
#define OPT_STR_NOLIMIT(_choices) .type = BCH_OPT_STR, \
.min = 0, .max = U64_MAX, \
@@ -428,7 +428,7 @@ void bch2_opt_to_text(struct printbuf *out,
prt_printf(out, "%lli", v);
break;
case BCH_OPT_STR:
- if (v < opt->min || v >= opt->max - 1)
+ if (v < opt->min || v >= opt->max)
prt_printf(out, "(invalid option %lli)", v);
else if (flags & OPT_SHOW_FULL_LIST)
prt_string_option(out, opt->choices, v);
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index 454b5a32dd7f..3c7f941dde39 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -94,11 +94,10 @@ static void bch2_reconstruct_alloc(struct bch_fs *c)
__set_bit_le64(BCH_FSCK_ERR_accounting_mismatch, ext->errors_silent);
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info);
- bch2_write_super(c);
- mutex_unlock(&c->sb_lock);
-
c->opts.recovery_passes |= bch2_recovery_passes_from_stable(le64_to_cpu(ext->recovery_passes_required[0]));
+ bch2_write_super(c);
+ mutex_unlock(&c->sb_lock);
bch2_shoot_down_journal_keys(c, BTREE_ID_alloc,
0, BTREE_MAX_DEPTH, POS_MIN, SPOS_MAX);
@@ -863,6 +862,13 @@ use_clean:
if (ret)
goto err;
+ /*
+ * Normally set by the appropriate recovery pass: when cleared, this
+ * indicates we're in early recovery and btree updates should be done by
+ * being applied to the journal replay keys. _Must_ be cleared before
+ * multithreaded use:
+ */
+ set_bit(BCH_FS_may_go_rw, &c->flags);
clear_bit(BCH_FS_fsck_running, &c->flags);
/* in case we don't run journal replay, i.e. norecovery mode */
@@ -1002,6 +1008,7 @@ int bch2_fs_initialize(struct bch_fs *c)
struct bch_inode_unpacked root_inode, lostfound_inode;
struct bkey_inode_buf packed_inode;
struct qstr lostfound = QSTR("lost+found");
+ struct bch_member *m;
int ret;
bch_notice(c, "initializing new filesystem");
@@ -1018,6 +1025,14 @@ int bch2_fs_initialize(struct bch_fs *c)
SET_BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb, bcachefs_metadata_version_current);
bch2_write_super(c);
}
+
+ for_each_member_device(c, ca) {
+ m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
+ SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, false);
+ ca->mi = bch2_mi_to_cpu(m);
+ }
+
+ bch2_write_super(c);
mutex_unlock(&c->sb_lock);
c->curr_recovery_pass = BCH_RECOVERY_PASS_NR;
diff --git a/fs/bcachefs/recovery_passes.c b/fs/bcachefs/recovery_passes.c
index 735b8adc8f9d..dff589ddc984 100644
--- a/fs/bcachefs/recovery_passes.c
+++ b/fs/bcachefs/recovery_passes.c
@@ -27,6 +27,12 @@ const char * const bch2_recovery_passes[] = {
NULL
};
+/* Fake recovery pass, so that scan_for_btree_nodes isn't 0: */
+static int bch2_recovery_pass_empty(struct bch_fs *c)
+{
+ return 0;
+}
+
static int bch2_set_may_go_rw(struct bch_fs *c)
{
struct journal_keys *keys = &c->journal_keys;
@@ -221,6 +227,12 @@ int bch2_run_recovery_passes(struct bch_fs *c)
{
int ret = 0;
+ /*
+ * We can't allow set_may_go_rw to be excluded; that would cause us to
+ * use the journal replay keys for updates where it's not expected.
+ */
+ c->opts.recovery_passes_exclude &= ~BCH_RECOVERY_PASS_set_may_go_rw;
+
while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
if (c->opts.recovery_pass_last &&
c->curr_recovery_pass > c->opts.recovery_pass_last)
diff --git a/fs/bcachefs/recovery_passes_types.h b/fs/bcachefs/recovery_passes_types.h
index 9d96c06e365c..94dc20ca2065 100644
--- a/fs/bcachefs/recovery_passes_types.h
+++ b/fs/bcachefs/recovery_passes_types.h
@@ -13,6 +13,7 @@
* must never change:
*/
#define BCH_RECOVERY_PASSES() \
+ x(recovery_pass_empty, 41, PASS_SILENT) \
x(scan_for_btree_nodes, 37, 0) \
x(check_topology, 4, 0) \
x(accounting_read, 39, PASS_ALWAYS) \
diff --git a/fs/bcachefs/sb-downgrade.c b/fs/bcachefs/sb-downgrade.c
index ae715ff658e8..8767c33c2b51 100644
--- a/fs/bcachefs/sb-downgrade.c
+++ b/fs/bcachefs/sb-downgrade.c
@@ -143,6 +143,9 @@ UPGRADE_TABLE()
static int have_stripes(struct bch_fs *c)
{
+ if (IS_ERR_OR_NULL(c->btree_roots_known[BTREE_ID_stripes].b))
+ return 0;
+
return !btree_node_fake(c->btree_roots_known[BTREE_ID_stripes].b);
}
diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h
index 937275d061fe..9feb6739f77a 100644
--- a/fs/bcachefs/sb-errors_format.h
+++ b/fs/bcachefs/sb-errors_format.h
@@ -136,7 +136,9 @@ enum bch_fsck_flags {
x(bucket_gens_nonzero_for_invalid_buckets, 122, FSCK_AUTOFIX) \
x(need_discard_freespace_key_to_invalid_dev_bucket, 123, 0) \
x(need_discard_freespace_key_bad, 124, 0) \
+ x(discarding_bucket_not_in_need_discard_btree, 291, 0) \
x(backpointer_bucket_offset_wrong, 125, 0) \
+ x(backpointer_level_bad, 294, 0) \
x(backpointer_to_missing_device, 126, 0) \
x(backpointer_to_missing_alloc, 127, 0) \
x(backpointer_to_missing_ptr, 128, 0) \
@@ -177,7 +179,9 @@ enum bch_fsck_flags {
x(ptr_stripe_redundant, 163, 0) \
x(reservation_key_nr_replicas_invalid, 164, 0) \
x(reflink_v_refcount_wrong, 165, 0) \
+ x(reflink_v_pos_bad, 292, 0) \
x(reflink_p_to_missing_reflink_v, 166, 0) \
+ x(reflink_refcount_underflow, 293, 0) \
x(stripe_pos_bad, 167, 0) \
x(stripe_val_size_bad, 168, 0) \
x(stripe_csum_granularity_bad, 290, 0) \
@@ -302,7 +306,7 @@ enum bch_fsck_flags {
x(accounting_key_replicas_devs_unsorted, 280, FSCK_AUTOFIX) \
x(accounting_key_version_0, 282, FSCK_AUTOFIX) \
x(logged_op_but_clean, 283, FSCK_AUTOFIX) \
- x(MAX, 291, 0)
+ x(MAX, 295, 0)
enum bch_sb_error_id {
#define x(t, n, ...) BCH_FSCK_ERR_##t = n,
diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c
index fb08dd680dac..116131f95815 100644
--- a/fs/bcachefs/sb-members.c
+++ b/fs/bcachefs/sb-members.c
@@ -163,7 +163,7 @@ static int validate_member(struct printbuf *err,
return -BCH_ERR_invalid_sb_members;
}
- if (m.btree_bitmap_shift >= 64) {
+ if (m.btree_bitmap_shift >= BCH_MI_BTREE_BITMAP_SHIFT_MAX) {
prt_printf(err, "device %u: invalid btree_bitmap_shift %u", i, m.btree_bitmap_shift);
return -BCH_ERR_invalid_sb_members;
}
@@ -450,7 +450,7 @@ static void __bch2_dev_btree_bitmap_mark(struct bch_sb_field_members_v2 *mi, uns
m->btree_bitmap_shift += resize;
}
- BUG_ON(m->btree_bitmap_shift > 57);
+ BUG_ON(m->btree_bitmap_shift >= BCH_MI_BTREE_BITMAP_SHIFT_MAX);
BUG_ON(end > 64ULL << m->btree_bitmap_shift);
for (unsigned bit = start >> m->btree_bitmap_shift;
diff --git a/fs/bcachefs/sb-members_format.h b/fs/bcachefs/sb-members_format.h
index d727d2dfda08..2adf1221a440 100644
--- a/fs/bcachefs/sb-members_format.h
+++ b/fs/bcachefs/sb-members_format.h
@@ -66,6 +66,12 @@ struct bch_member {
};
/*
+ * btree_allocated_bitmap can represent sector addresses of a u64: it itself has
+ * 64 elements, so 64 - ilog2(64)
+ */
+#define BCH_MI_BTREE_BITMAP_SHIFT_MAX 58
+
+/*
* This limit comes from the bucket_gens array - it's a single allocation, and
* kernel allocation are limited to INT_MAX
*/
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index ce7410d72089..7c71594f6a8b 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -287,6 +287,11 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out
return -BCH_ERR_invalid_sb_layout_nr_superblocks;
}
+ if (layout->sb_max_size_bits > BCH_SB_LAYOUT_SIZE_BITS_MAX) {
+ prt_printf(out, "Invalid superblock layout: max_size_bits too high");
+ return -BCH_ERR_invalid_sb_layout_sb_max_size_bits;
+ }
+
max_sectors = 1 << layout->sb_max_size_bits;
prev_offset = le64_to_cpu(layout->sb_offset[0]);
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 657fd3759e7b..a6ed9a0bf1c7 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -272,6 +272,7 @@ static void __bch2_fs_read_only(struct bch_fs *c)
clean_passes++;
if (bch2_btree_interior_updates_flush(c) ||
+ bch2_btree_write_buffer_flush_going_ro(c) ||
bch2_journal_flush_all_pins(&c->journal) ||
bch2_btree_flush_all_writes(c) ||
seq != atomic64_read(&c->journal.seq)) {
diff --git a/fs/bcachefs/tests.c b/fs/bcachefs/tests.c
index 315038a0a92d..fb5c1543e52f 100644
--- a/fs/bcachefs/tests.c
+++ b/fs/bcachefs/tests.c
@@ -809,6 +809,11 @@ int bch2_btree_perf_test(struct bch_fs *c, const char *testname,
unsigned i;
u64 time;
+ if (nr == 0 || nr_threads == 0) {
+ pr_err("nr of iterations or threads is not allowed to be 0");
+ return -EINVAL;
+ }
+
atomic_set(&j.ready, nr_threads);
init_waitqueue_head(&j.ready_wait);
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index fec5c6cde0a7..7e0f9600b80c 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -49,6 +49,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info,
bbio->end_io = end_io;
bbio->private = private;
atomic_set(&bbio->pending_ios, 1);
+ WRITE_ONCE(bbio->status, BLK_STS_OK);
}
/*
@@ -113,41 +114,29 @@ static void __btrfs_bio_end_io(struct btrfs_bio *bbio)
}
}
-static void btrfs_orig_write_end_io(struct bio *bio);
-
-static void btrfs_bbio_propagate_error(struct btrfs_bio *bbio,
- struct btrfs_bio *orig_bbio)
-{
- /*
- * For writes we tolerate nr_mirrors - 1 write failures, so we can't
- * just blindly propagate a write failure here. Instead increment the
- * error count in the original I/O context so that it is guaranteed to
- * be larger than the error tolerance.
- */
- if (bbio->bio.bi_end_io == &btrfs_orig_write_end_io) {
- struct btrfs_io_stripe *orig_stripe = orig_bbio->bio.bi_private;
- struct btrfs_io_context *orig_bioc = orig_stripe->bioc;
-
- atomic_add(orig_bioc->max_errors, &orig_bioc->error);
- } else {
- orig_bbio->bio.bi_status = bbio->bio.bi_status;
- }
-}
-
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
{
bbio->bio.bi_status = status;
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
struct btrfs_bio *orig_bbio = bbio->private;
- if (bbio->bio.bi_status)
- btrfs_bbio_propagate_error(bbio, orig_bbio);
btrfs_cleanup_bio(bbio);
bbio = orig_bbio;
}
- if (atomic_dec_and_test(&bbio->pending_ios))
+ /*
+ * At this point, bbio always points to the original btrfs_bio. Save
+ * the first error in it.
+ */
+ if (status != BLK_STS_OK)
+ cmpxchg(&bbio->status, BLK_STS_OK, status);
+
+ if (atomic_dec_and_test(&bbio->pending_ios)) {
+ /* Load split bio's error which might be set above. */
+ if (status == BLK_STS_OK)
+ bbio->bio.bi_status = READ_ONCE(bbio->status);
__btrfs_bio_end_io(bbio);
+ }
}
static int next_repair_mirror(struct btrfs_failed_bio *fbio, int cur_mirror)
diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h
index e48612340745..e2fe16074ad6 100644
--- a/fs/btrfs/bio.h
+++ b/fs/btrfs/bio.h
@@ -79,6 +79,9 @@ struct btrfs_bio {
/* File system that this I/O operates on. */
struct btrfs_fs_info *fs_info;
+ /* Save the first error status of split bio. */
+ blk_status_t status;
+
/*
* This member must come last, bio_alloc_bioset will allocate enough
* bytes for entire btrfs_bio but relies on bio being last.
diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c
index b95ef44c326b..968dae953948 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -763,12 +763,12 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
* We can get a merged extent, in that case, we need to re-search
* tree to get the original em for defrag.
*
- * If @newer_than is 0 or em::generation < newer_than, we can trust
- * this em, as either we don't care about the generation, or the
- * merged extent map will be rejected anyway.
+ * This is because even if we have adjacent extents that are contiguous
+ * and compatible (same type and flags), we still want to defrag them
+ * so that we use less metadata (extent items in the extent tree and
+ * file extent items in the inode's subvolume tree).
*/
- if (em && (em->flags & EXTENT_FLAG_MERGED) &&
- newer_than && em->generation >= newer_than) {
+ if (em && (em->flags & EXTENT_FLAG_MERGED)) {
free_extent_map(em);
em = NULL;
}
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 115b90d29b1d..65d841d7142c 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -649,7 +649,7 @@ static bool insert_delayed_ref(struct btrfs_trans_handle *trans,
&href->ref_add_list);
else if (ref->action == BTRFS_DROP_DELAYED_REF) {
ASSERT(!list_empty(&exist->add_list));
- list_del(&exist->add_list);
+ list_del_init(&exist->add_list);
} else {
ASSERT(0);
}
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 668c617444a5..1d93e1202c33 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -230,7 +230,12 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
if (extent_map_end(prev) != next->start)
return false;
- if (prev->flags != next->flags)
+ /*
+ * The merged flag is not an on-disk flag, it just indicates we had the
+ * extent maps of 2 (or more) adjacent extents merged, so factor it out.
+ */
+ if ((prev->flags & ~EXTENT_FLAG_MERGED) !=
+ (next->flags & ~EXTENT_FLAG_MERGED))
return false;
if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index da51edbad6a0..1e4ca1e7d2e5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1618,7 +1618,7 @@ out_unlock:
clear_bits |= EXTENT_CLEAR_DATA_RESV;
extent_clear_unlock_delalloc(inode, start, end, locked_folio,
&cached, clear_bits, page_ops);
- btrfs_qgroup_free_data(inode, NULL, start, cur_alloc_size, NULL);
+ btrfs_qgroup_free_data(inode, NULL, start, end - start + 1, NULL);
}
return ret;
}
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 926d7a9ed99d..c64d07134122 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1979,25 +1979,10 @@ error:
* fsconfig(FSCONFIG_SET_FLAG, "ro"). This option is seen by the filesystem
* in fc->sb_flags.
*
- * This disambiguation has rather positive consequences. Mounting a subvolume
- * ro will not also turn the superblock ro. Only the mount for the subvolume
- * will become ro.
- *
- * So, if the superblock creation request comes from the new mount API the
- * caller must have explicitly done:
- *
- * fsconfig(FSCONFIG_SET_FLAG, "ro")
- * fsmount/mount_setattr(MOUNT_ATTR_RDONLY)
- *
- * IOW, at some point the caller must have explicitly turned the whole
- * superblock ro and we shouldn't just undo it like we did for the old mount
- * API. In any case, it lets us avoid the hack in the new mount API.
- *
- * Consequently, the remounting hack must only be used for requests originating
- * from the old mount API and should be marked for full deprecation so it can be
- * turned off in a couple of years.
- *
- * The new mount API has no reason to support this hack.
+ * But, currently the util-linux mount command already utilizes the new mount
+ * API and is still setting fsconfig(FSCONFIG_SET_FLAG, "ro") no matter if it's
+ * btrfs or not, setting the whole super block RO. To make per-subvolume mounting
+ * work with different options work we need to keep backward compatibility.
*/
static struct vfsmount *btrfs_reconfigure_for_mount(struct fs_context *fc)
{
@@ -2019,7 +2004,7 @@ static struct vfsmount *btrfs_reconfigure_for_mount(struct fs_context *fc)
if (IS_ERR(mnt))
return mnt;
- if (!fc->oldapi || !ro2rw)
+ if (!ro2rw)
return mnt;
/* We need to convert to rw, call reconfigure. */
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 8f340ad1d938..eb51b609190f 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1105,6 +1105,7 @@ static void btrfs_close_one_device(struct btrfs_device *device)
if (device->bdev) {
fs_devices->open_devices--;
device->bdev = NULL;
+ device->bdev_file = NULL;
}
clear_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
btrfs_destroy_dev_zone_info(device);
diff --git a/fs/dax.c b/fs/dax.c
index c62acd2812f8..21b47402b3dc 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1262,35 +1262,46 @@ static s64 dax_unshare_iter(struct iomap_iter *iter)
{
struct iomap *iomap = &iter->iomap;
const struct iomap *srcmap = iomap_iter_srcmap(iter);
- loff_t pos = iter->pos;
- loff_t length = iomap_length(iter);
+ loff_t copy_pos = iter->pos;
+ u64 copy_len = iomap_length(iter);
+ u32 mod;
int id = 0;
s64 ret = 0;
void *daddr = NULL, *saddr = NULL;
- /* don't bother with blocks that are not shared to start with */
- if (!(iomap->flags & IOMAP_F_SHARED))
- return length;
+ if (!iomap_want_unshare_iter(iter))
+ return iomap_length(iter);
+
+ /*
+ * Extend the file range to be aligned to fsblock/pagesize, because
+ * we need to copy entire blocks, not just the byte range specified.
+ * Invalidate the mapping because we're about to CoW.
+ */
+ mod = offset_in_page(copy_pos);
+ if (mod) {
+ copy_len += mod;
+ copy_pos -= mod;
+ }
+
+ mod = offset_in_page(copy_pos + copy_len);
+ if (mod)
+ copy_len += PAGE_SIZE - mod;
+
+ invalidate_inode_pages2_range(iter->inode->i_mapping,
+ copy_pos >> PAGE_SHIFT,
+ (copy_pos + copy_len - 1) >> PAGE_SHIFT);
id = dax_read_lock();
- ret = dax_iomap_direct_access(iomap, pos, length, &daddr, NULL);
+ ret = dax_iomap_direct_access(iomap, copy_pos, copy_len, &daddr, NULL);
if (ret < 0)
goto out_unlock;
- /* zero the distance if srcmap is HOLE or UNWRITTEN */
- if (srcmap->flags & IOMAP_F_SHARED || srcmap->type == IOMAP_UNWRITTEN) {
- memset(daddr, 0, length);
- dax_flush(iomap->dax_dev, daddr, length);
- ret = length;
- goto out_unlock;
- }
-
- ret = dax_iomap_direct_access(srcmap, pos, length, &saddr, NULL);
+ ret = dax_iomap_direct_access(srcmap, copy_pos, copy_len, &saddr, NULL);
if (ret < 0)
goto out_unlock;
- if (copy_mc_to_kernel(daddr, saddr, length) == 0)
- ret = length;
+ if (copy_mc_to_kernel(daddr, saddr, copy_len) == 0)
+ ret = iomap_length(iter);
else
ret = -EIO;
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 67299e8b734e..47dc96dfe386 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -100,8 +100,16 @@ int debugfs_file_get(struct dentry *dentry)
if (!fsd)
return -ENOMEM;
- fsd->real_fops = (void *)((unsigned long)d_fsd &
- ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
+ if ((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT) {
+ fsd->real_fops = NULL;
+ fsd->short_fops = (void *)((unsigned long)d_fsd &
+ ~(DEBUGFS_FSDATA_IS_REAL_FOPS_BIT |
+ DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
+ } else {
+ fsd->real_fops = (void *)((unsigned long)d_fsd &
+ ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
+ fsd->short_fops = NULL;
+ }
refcount_set(&fsd->active_users, 1);
init_completion(&fsd->active_users_drained);
INIT_LIST_HEAD(&fsd->cancellations);
@@ -241,9 +249,10 @@ static int debugfs_locked_down(struct inode *inode,
{
if ((inode->i_mode & 07777 & ~0444) == 0 &&
!(filp->f_mode & FMODE_WRITE) &&
- !real_fops->unlocked_ioctl &&
- !real_fops->compat_ioctl &&
- !real_fops->mmap)
+ (!real_fops ||
+ (!real_fops->unlocked_ioctl &&
+ !real_fops->compat_ioctl &&
+ !real_fops->mmap)))
return 0;
if (security_locked_down(LOCKDOWN_DEBUGFS))
@@ -316,19 +325,38 @@ static ret_type full_proxy_ ## name(proto) \
return r; \
}
-FULL_PROXY_FUNC(llseek, loff_t, filp,
- PROTO(struct file *filp, loff_t offset, int whence),
- ARGS(filp, offset, whence));
+#define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args) \
+static ret_type full_proxy_ ## name(proto) \
+{ \
+ struct dentry *dentry = F_DENTRY(filp); \
+ struct debugfs_fsdata *fsd; \
+ ret_type r; \
+ \
+ r = debugfs_file_get(dentry); \
+ if (unlikely(r)) \
+ return r; \
+ fsd = dentry->d_fsdata; \
+ if (fsd->real_fops) \
+ r = fsd->real_fops->name(args); \
+ else \
+ r = fsd->short_fops->name(args); \
+ debugfs_file_put(dentry); \
+ return r; \
+}
+
+FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp,
+ PROTO(struct file *filp, loff_t offset, int whence),
+ ARGS(filp, offset, whence));
-FULL_PROXY_FUNC(read, ssize_t, filp,
- PROTO(struct file *filp, char __user *buf, size_t size,
- loff_t *ppos),
- ARGS(filp, buf, size, ppos));
+FULL_PROXY_FUNC_BOTH(read, ssize_t, filp,
+ PROTO(struct file *filp, char __user *buf, size_t size,
+ loff_t *ppos),
+ ARGS(filp, buf, size, ppos));
-FULL_PROXY_FUNC(write, ssize_t, filp,
- PROTO(struct file *filp, const char __user *buf, size_t size,
- loff_t *ppos),
- ARGS(filp, buf, size, ppos));
+FULL_PROXY_FUNC_BOTH(write, ssize_t, filp,
+ PROTO(struct file *filp, const char __user *buf,
+ size_t size, loff_t *ppos),
+ ARGS(filp, buf, size, ppos));
FULL_PROXY_FUNC(unlocked_ioctl, long, filp,
PROTO(struct file *filp, unsigned int cmd, unsigned long arg),
@@ -363,7 +391,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
* not to leak any resources. Releasers must not assume that
* ->i_private is still being meaningful here.
*/
- if (real_fops->release)
+ if (real_fops && real_fops->release)
r = real_fops->release(inode, filp);
replace_fops(filp, d_inode(dentry)->i_fop);
@@ -373,39 +401,48 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
}
static void __full_proxy_fops_init(struct file_operations *proxy_fops,
- const struct file_operations *real_fops)
+ struct debugfs_fsdata *fsd)
{
proxy_fops->release = full_proxy_release;
- if (real_fops->llseek)
+
+ if ((fsd->real_fops && fsd->real_fops->llseek) ||
+ (fsd->short_fops && fsd->short_fops->llseek))
proxy_fops->llseek = full_proxy_llseek;
- if (real_fops->read)
+
+ if ((fsd->real_fops && fsd->real_fops->read) ||
+ (fsd->short_fops && fsd->short_fops->read))
proxy_fops->read = full_proxy_read;
- if (real_fops->write)
+
+ if ((fsd->real_fops && fsd->real_fops->write) ||
+ (fsd->short_fops && fsd->short_fops->write))
proxy_fops->write = full_proxy_write;
- if (real_fops->poll)
+
+ if (fsd->real_fops && fsd->real_fops->poll)
proxy_fops->poll = full_proxy_poll;
- if (real_fops->unlocked_ioctl)
+
+ if (fsd->real_fops && fsd->real_fops->unlocked_ioctl)
proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
}
static int full_proxy_open(struct inode *inode, struct file *filp)
{
struct dentry *dentry = F_DENTRY(filp);
- const struct file_operations *real_fops = NULL;
+ const struct file_operations *real_fops;
struct file_operations *proxy_fops = NULL;
+ struct debugfs_fsdata *fsd;
int r;
r = debugfs_file_get(dentry);
if (r)
return r == -EIO ? -ENOENT : r;
- real_fops = debugfs_real_fops(filp);
-
+ fsd = dentry->d_fsdata;
+ real_fops = fsd->real_fops;
r = debugfs_locked_down(inode, filp, real_fops);
if (r)
goto out;
- if (!fops_get(real_fops)) {
+ if (real_fops && !fops_get(real_fops)) {
#ifdef CONFIG_MODULES
if (real_fops->owner &&
real_fops->owner->state == MODULE_STATE_GOING) {
@@ -426,11 +463,14 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
r = -ENOMEM;
goto free_proxy;
}
- __full_proxy_fops_init(proxy_fops, real_fops);
+ __full_proxy_fops_init(proxy_fops, fsd);
replace_fops(filp, proxy_fops);
- if (real_fops->open) {
- r = real_fops->open(inode, filp);
+ if (!real_fops || real_fops->open) {
+ if (real_fops)
+ r = real_fops->open(inode, filp);
+ else
+ r = simple_open(inode, filp);
if (r) {
replace_fops(filp, d_inode(dentry)->i_fop);
goto free_proxy;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 66d9b3b4c588..38a9c7eb97e6 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -412,7 +412,7 @@ static struct dentry *end_creating(struct dentry *dentry)
static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *proxy_fops,
- const struct file_operations *real_fops)
+ const void *real_fops)
{
struct dentry *dentry;
struct inode *inode;
@@ -450,49 +450,38 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
return end_creating(dentry);
}
-/**
- * debugfs_create_file - create a file in the debugfs filesystem
- * @name: a pointer to a string containing the name of the file to create.
- * @mode: the permission that the file should have.
- * @parent: a pointer to the parent dentry for this file. This should be a
- * directory dentry if set. If this parameter is NULL, then the
- * file will be created in the root of the debugfs filesystem.
- * @data: a pointer to something that the caller will want to get to later
- * on. The inode.i_private pointer will point to this value on
- * the open() call.
- * @fops: a pointer to a struct file_operations that should be used for
- * this file.
- *
- * This is the basic "create a file" function for debugfs. It allows for a
- * wide range of flexibility in creating a file, or a directory (if you want
- * to create a directory, the debugfs_create_dir() function is
- * recommended to be used instead.)
- *
- * This function will return a pointer to a dentry if it succeeds. This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value -%ENODEV will be
- * returned.
- *
- * NOTE: it's expected that most callers should _ignore_ the errors returned
- * by this function. Other debugfs functions handle the fact that the "dentry"
- * passed to them could be an error and they don't crash in that case.
- * Drivers should generally work fine even if debugfs fails to init anyway.
- */
-struct dentry *debugfs_create_file(const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops)
+struct dentry *debugfs_create_file_full(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops)
{
+ if (WARN_ON((unsigned long)fops &
+ (DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
+ DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
+ return ERR_PTR(-EINVAL);
return __debugfs_create_file(name, mode, parent, data,
fops ? &debugfs_full_proxy_file_operations :
&debugfs_noop_file_operations,
fops);
}
-EXPORT_SYMBOL_GPL(debugfs_create_file);
+EXPORT_SYMBOL_GPL(debugfs_create_file_full);
+
+struct dentry *debugfs_create_file_short(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct debugfs_short_fops *fops)
+{
+ if (WARN_ON((unsigned long)fops &
+ (DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
+ DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
+ return ERR_PTR(-EINVAL);
+
+ return __debugfs_create_file(name, mode, parent, data,
+ fops ? &debugfs_full_proxy_file_operations :
+ &debugfs_noop_file_operations,
+ (const void *)((unsigned long)fops |
+ DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
+}
+EXPORT_SYMBOL_GPL(debugfs_create_file_short);
/**
* debugfs_create_file_unsafe - create a file in the debugfs filesystem
diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h
index dae80c2a469e..a3edfa4f0d8e 100644
--- a/fs/debugfs/internal.h
+++ b/fs/debugfs/internal.h
@@ -18,6 +18,7 @@ extern const struct file_operations debugfs_full_proxy_file_operations;
struct debugfs_fsdata {
const struct file_operations *real_fops;
+ const struct debugfs_short_fops *short_fops;
union {
/* automount_fn is used when real_fops is NULL */
debugfs_automount_t automount;
@@ -39,6 +40,11 @@ struct debugfs_fsdata {
* pointer gets its lowest bit set.
*/
#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0)
+/*
+ * A dentry's ->d_fsdata, when pointing to real fops, is with
+ * short fops instead of full fops.
+ */
+#define DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT BIT(1)
/* Access BITS */
#define DEBUGFS_ALLOW_API BIT(0)
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 320d586c3896..bed3dbe5b7cb 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -709,7 +709,9 @@ static int erofs_fc_get_tree(struct fs_context *fc)
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && sbi->fsid)
return get_tree_nodev(fc, erofs_fc_fill_super);
- ret = get_tree_bdev(fc, erofs_fc_fill_super);
+ ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
+ IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
+ GET_TREE_BDEV_QUIET_LOOKUP : 0);
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
if (ret == -ENOTBLK) {
if (!fc->source)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 1ae4542f0bd8..83bcb559b89f 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -420,7 +420,9 @@ static bool busy_loop_ep_timeout(unsigned long start_time,
static bool ep_busy_loop_on(struct eventpoll *ep)
{
- return !!READ_ONCE(ep->busy_poll_usecs) || net_busy_loop_on();
+ return !!READ_ONCE(ep->busy_poll_usecs) ||
+ READ_ONCE(ep->prefer_busy_poll) ||
+ net_busy_loop_on();
}
static bool ep_busy_loop_end(void *p, unsigned long start_time)
@@ -455,6 +457,8 @@ static bool ep_busy_loop(struct eventpoll *ep, int nonblock)
* it back in when we have moved a socket with a valid NAPI
* ID onto the ready list.
*/
+ if (prefer_busy_poll)
+ napi_resume_irqs(napi_id);
ep->napi_id = 0;
return false;
}
@@ -538,6 +542,22 @@ static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
}
}
+static void ep_suspend_napi_irqs(struct eventpoll *ep)
+{
+ unsigned int napi_id = READ_ONCE(ep->napi_id);
+
+ if (napi_id >= MIN_NAPI_ID && READ_ONCE(ep->prefer_busy_poll))
+ napi_suspend_irqs(napi_id);
+}
+
+static void ep_resume_napi_irqs(struct eventpoll *ep)
+{
+ unsigned int napi_id = READ_ONCE(ep->napi_id);
+
+ if (napi_id >= MIN_NAPI_ID && READ_ONCE(ep->prefer_busy_poll))
+ napi_resume_irqs(napi_id);
+}
+
#else
static inline bool ep_busy_loop(struct eventpoll *ep, int nonblock)
@@ -555,6 +575,14 @@ static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
return -EOPNOTSUPP;
}
+static void ep_suspend_napi_irqs(struct eventpoll *ep)
+{
+}
+
+static void ep_resume_napi_irqs(struct eventpoll *ep)
+{
+}
+
#endif /* CONFIG_NET_RX_BUSY_POLL */
/*
@@ -786,6 +814,7 @@ static bool ep_refcount_dec_and_test(struct eventpoll *ep)
static void ep_free(struct eventpoll *ep)
{
+ ep_resume_napi_irqs(ep);
mutex_destroy(&ep->mtx);
free_uid(ep->user);
wakeup_source_unregister(ep->ws);
@@ -2003,8 +2032,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
* trying again in search of more luck.
*/
res = ep_send_events(ep, events, maxevents);
- if (res)
+ if (res) {
+ if (res > 0)
+ ep_suspend_napi_irqs(ep);
return res;
+ }
}
if (timed_out)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index f33fbce86ae0..dafdf766b1d5 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2288,6 +2288,13 @@ static int fuse_writepages_fill(struct folio *folio,
struct folio *tmp_folio;
int err;
+ if (!data->ff) {
+ err = -EIO;
+ data->ff = fuse_write_file_get(fi);
+ if (!data->ff)
+ goto out_unlock;
+ }
+
if (wpa && fuse_writepage_need_send(fc, &folio->page, ap, data)) {
fuse_writepages_send(data);
data->wpa = NULL;
@@ -2351,13 +2358,13 @@ static int fuse_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
- struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_fill_wb_data data;
int err;
+ err = -EIO;
if (fuse_is_bad(inode))
- return -EIO;
+ goto out;
if (wbc->sync_mode == WB_SYNC_NONE &&
fc->num_background >= fc->congestion_threshold)
@@ -2365,9 +2372,7 @@ static int fuse_writepages(struct address_space *mapping,
data.inode = inode;
data.wpa = NULL;
- data.ff = fuse_write_file_get(fi);
- if (!data.ff)
- return -EIO;
+ data.ff = NULL;
err = -ENOMEM;
data.orig_pages = kcalloc(fc->max_pages,
@@ -2381,10 +2386,11 @@ static int fuse_writepages(struct address_space *mapping,
WARN_ON(!data.wpa->ia.ap.num_pages);
fuse_writepages_send(&data);
}
+ if (data.ff)
+ fuse_file_put(data.ff, false);
kfree(data.orig_pages);
out:
- fuse_file_put(data.ff, false);
return err;
}
diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
index 62aee8289d11..bbac547dfcb3 100644
--- a/fs/fuse/passthrough.c
+++ b/fs/fuse/passthrough.c
@@ -18,11 +18,11 @@ static void fuse_file_accessed(struct file *file)
fuse_invalidate_atime(inode);
}
-static void fuse_file_modified(struct file *file)
+static void fuse_passthrough_end_write(struct file *file, loff_t pos, ssize_t ret)
{
struct inode *inode = file_inode(file);
- fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);
+ fuse_write_update_attr(inode, pos, ret);
}
ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
@@ -63,7 +63,7 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
struct backing_file_ctx ctx = {
.cred = ff->cred,
.user_file = file,
- .end_write = fuse_file_modified,
+ .end_write = fuse_passthrough_end_write,
};
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
@@ -110,7 +110,7 @@ ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
struct backing_file_ctx ctx = {
.cred = ff->cred,
.user_file = out,
- .end_write = fuse_file_modified,
+ .end_write = fuse_passthrough_end_write,
};
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
@@ -234,7 +234,6 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
goto out;
backing_sb = file_inode(file)->i_sb;
- pr_info("%s: %x:%pD %i\n", __func__, backing_sb->s_dev, file, backing_sb->s_stack_depth);
res = -ELOOP;
if (backing_sb->s_stack_depth >= fc->max_stack_depth)
goto out_fput;
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index aa587b2142e2..ef0b68bccbb6 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -1277,22 +1277,7 @@ static loff_t iomap_unshare_iter(struct iomap_iter *iter)
loff_t length = iomap_length(iter);
loff_t written = 0;
- /* Don't bother with blocks that are not shared to start with. */
- if (!(iomap->flags & IOMAP_F_SHARED))
- return length;
-
- /*
- * Don't bother with delalloc reservations, holes or unwritten extents.
- *
- * Note that we use srcmap directly instead of iomap_iter_srcmap as
- * unsharing requires providing a separate source map, and the presence
- * of one is a good indicator that unsharing is needed, unlike
- * IOMAP_F_SHARED which can be set for any data that goes into the COW
- * fork for XFS.
- */
- if (iter->srcmap.type == IOMAP_HOLE ||
- iter->srcmap.type == IOMAP_DELALLOC ||
- iter->srcmap.type == IOMAP_UNWRITTEN)
+ if (!iomap_want_unshare_iter(iter))
return length;
do {
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 114282398716..03ecc7765615 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -181,8 +181,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
seqlock_init(&clp->cl_boot_lock);
ktime_get_real_ts64(&clp->cl_nfssvc_boot);
- clp->cl_uuid.net = NULL;
- clp->cl_uuid.dom = NULL;
+ nfs_uuid_init(&clp->cl_uuid);
spin_lock_init(&clp->cl_localio_lock);
#endif /* CONFIG_NFS_LOCALIO */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 542c7d97b235..596f35170137 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -205,12 +205,15 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
nfs_fscache_invalidate(inode, 0);
flags &= ~NFS_INO_REVAL_FORCED;
- nfsi->cache_validity |= flags;
+ flags |= nfsi->cache_validity;
+ if (inode->i_mapping->nrpages == 0)
+ flags &= ~NFS_INO_INVALID_DATA;
- if (inode->i_mapping->nrpages == 0) {
- nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
- nfs_ooo_clear(nfsi);
- } else if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
+ /* pairs with nfs_clear_invalid_mapping()'s smp_load_acquire() */
+ smp_store_release(&nfsi->cache_validity, flags);
+
+ if (inode->i_mapping->nrpages == 0 ||
+ nfsi->cache_validity & NFS_INO_INVALID_DATA) {
nfs_ooo_clear(nfsi);
}
trace_nfs_set_cache_invalid(inode, 0);
@@ -628,23 +631,35 @@ nfs_fattr_fixup_delegated(struct inode *inode, struct nfs_fattr *fattr)
}
}
+static void nfs_update_timestamps(struct inode *inode, unsigned int ia_valid)
+{
+ enum file_time_flags time_flags = 0;
+ unsigned int cache_flags = 0;
+
+ if (ia_valid & ATTR_MTIME) {
+ time_flags |= S_MTIME | S_CTIME;
+ cache_flags |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
+ }
+ if (ia_valid & ATTR_ATIME) {
+ time_flags |= S_ATIME;
+ cache_flags |= NFS_INO_INVALID_ATIME;
+ }
+ inode_update_timestamps(inode, time_flags);
+ NFS_I(inode)->cache_validity &= ~cache_flags;
+}
+
void nfs_update_delegated_atime(struct inode *inode)
{
spin_lock(&inode->i_lock);
- if (nfs_have_delegated_atime(inode)) {
- inode_update_timestamps(inode, S_ATIME);
- NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ATIME;
- }
+ if (nfs_have_delegated_atime(inode))
+ nfs_update_timestamps(inode, ATTR_ATIME);
spin_unlock(&inode->i_lock);
}
void nfs_update_delegated_mtime_locked(struct inode *inode)
{
- if (nfs_have_delegated_mtime(inode)) {
- inode_update_timestamps(inode, S_CTIME | S_MTIME);
- NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_CTIME |
- NFS_INO_INVALID_MTIME);
- }
+ if (nfs_have_delegated_mtime(inode))
+ nfs_update_timestamps(inode, ATTR_MTIME);
}
void nfs_update_delegated_mtime(struct inode *inode)
@@ -682,15 +697,16 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
attr->ia_valid &= ~ATTR_SIZE;
}
- if (nfs_have_delegated_mtime(inode)) {
- if (attr->ia_valid & ATTR_MTIME) {
- nfs_update_delegated_mtime(inode);
- attr->ia_valid &= ~ATTR_MTIME;
- }
- if (attr->ia_valid & ATTR_ATIME) {
- nfs_update_delegated_atime(inode);
- attr->ia_valid &= ~ATTR_ATIME;
- }
+ if (nfs_have_delegated_mtime(inode) && attr->ia_valid & ATTR_MTIME) {
+ spin_lock(&inode->i_lock);
+ nfs_update_timestamps(inode, attr->ia_valid);
+ spin_unlock(&inode->i_lock);
+ attr->ia_valid &= ~(ATTR_MTIME | ATTR_ATIME);
+ } else if (nfs_have_delegated_atime(inode) &&
+ attr->ia_valid & ATTR_ATIME &&
+ !(attr->ia_valid & ATTR_MTIME)) {
+ nfs_update_delegated_atime(inode);
+ attr->ia_valid &= ~ATTR_ATIME;
}
/* Optimization: if the end result is no change, don't RPC */
@@ -1408,6 +1424,13 @@ int nfs_clear_invalid_mapping(struct address_space *mapping)
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
if (ret)
goto out;
+ smp_rmb(); /* pairs with smp_wmb() below */
+ if (test_bit(NFS_INO_INVALIDATING, bitlock))
+ continue;
+ /* pairs with nfs_set_cache_invalid()'s smp_store_release() */
+ if (!(smp_load_acquire(&nfsi->cache_validity) & NFS_INO_INVALID_DATA))
+ goto out;
+ /* Slow-path that double-checks with spinlock held */
spin_lock(&inode->i_lock);
if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
spin_unlock(&inode->i_lock);
@@ -1633,6 +1656,7 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
fattr->gencount = nfs_inc_attr_generation_counter();
fattr->owner_name = NULL;
fattr->group_name = NULL;
+ fattr->mdsthreshold = NULL;
}
EXPORT_SYMBOL_GPL(nfs_fattr_init);
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index d0aa680ec816..8f0ce82a677e 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -205,7 +205,8 @@ void nfs_local_probe(struct nfs_client *clp)
nfs_local_disable(clp);
}
- nfs_uuid_begin(&clp->cl_uuid);
+ if (!nfs_uuid_begin(&clp->cl_uuid))
+ return;
if (nfs_server_uuid_is_local(clp))
nfs_local_enable(clp);
nfs_uuid_end(&clp->cl_uuid);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cd2fbde2e6d7..9d40319e063d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3452,6 +3452,10 @@ static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
adjust_flags |= NFS_INO_INVALID_MODE;
if (sattr->ia_valid & (ATTR_UID | ATTR_GID))
adjust_flags |= NFS_INO_INVALID_OTHER;
+ if (sattr->ia_valid & ATTR_ATIME)
+ adjust_flags |= NFS_INO_INVALID_ATIME;
+ if (sattr->ia_valid & ATTR_MTIME)
+ adjust_flags |= NFS_INO_INVALID_MTIME;
do {
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 9723b6c53397..ae5c5e39afa0 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -885,7 +885,15 @@ static int nfs_request_mount(struct fs_context *fc,
* Now ask the mount server to map our export path
* to a file handle.
*/
- status = nfs_mount(&request, ctx->timeo, ctx->retrans);
+ if ((request.protocol == XPRT_TRANSPORT_UDP) ==
+ !(ctx->flags & NFS_MOUNT_TCP))
+ /*
+ * NFS protocol and mount protocol are both UDP or neither UDP
+ * so timeouts are compatible. Use NFS timeouts for MOUNT
+ */
+ status = nfs_mount(&request, ctx->timeo, ctx->retrans);
+ else
+ status = nfs_mount(&request, NFS_UNSPEC_TIMEO, NFS_UNSPEC_RETRANS);
if (status != 0) {
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
request.hostname, status);
diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c
index 5c8ce5066c16..09404d142d1a 100644
--- a/fs/nfs_common/nfslocalio.c
+++ b/fs/nfs_common/nfslocalio.c
@@ -5,7 +5,7 @@
*/
#include <linux/module.h>
-#include <linux/rculist.h>
+#include <linux/list.h>
#include <linux/nfslocalio.h>
#include <net/netns/generic.h>
@@ -20,15 +20,27 @@ static DEFINE_SPINLOCK(nfs_uuid_lock);
*/
static LIST_HEAD(nfs_uuids);
-void nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
+void nfs_uuid_init(nfs_uuid_t *nfs_uuid)
{
nfs_uuid->net = NULL;
nfs_uuid->dom = NULL;
- uuid_gen(&nfs_uuid->uuid);
+ INIT_LIST_HEAD(&nfs_uuid->list);
+}
+EXPORT_SYMBOL_GPL(nfs_uuid_init);
+bool nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
+{
spin_lock(&nfs_uuid_lock);
- list_add_tail_rcu(&nfs_uuid->list, &nfs_uuids);
+ /* Is this nfs_uuid already in use? */
+ if (!list_empty(&nfs_uuid->list)) {
+ spin_unlock(&nfs_uuid_lock);
+ return false;
+ }
+ uuid_gen(&nfs_uuid->uuid);
+ list_add_tail(&nfs_uuid->list, &nfs_uuids);
spin_unlock(&nfs_uuid_lock);
+
+ return true;
}
EXPORT_SYMBOL_GPL(nfs_uuid_begin);
@@ -36,7 +48,8 @@ void nfs_uuid_end(nfs_uuid_t *nfs_uuid)
{
if (nfs_uuid->net == NULL) {
spin_lock(&nfs_uuid_lock);
- list_del_init(&nfs_uuid->list);
+ if (nfs_uuid->net == NULL)
+ list_del_init(&nfs_uuid->list);
spin_unlock(&nfs_uuid_lock);
}
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index b5a6bf4f459f..d32f2dfd148f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1841,14 +1841,12 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (!async_copy)
goto out_err;
async_copy->cp_nn = nn;
+ INIT_LIST_HEAD(&async_copy->copies);
+ refcount_set(&async_copy->refcount, 1);
/* Arbitrary cap on number of pending async copy operations */
if (atomic_inc_return(&nn->pending_async_copies) >
- (int)rqstp->rq_pool->sp_nrthreads) {
- atomic_dec(&nn->pending_async_copies);
+ (int)rqstp->rq_pool->sp_nrthreads)
goto out_err;
- }
- INIT_LIST_HEAD(&async_copy->copies);
- refcount_set(&async_copy->refcount, 1);
async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL);
if (!async_copy->cp_src)
goto out_err;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 56b261608af4..551d2958ec29 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1359,21 +1359,47 @@ static void destroy_delegation(struct nfs4_delegation *dp)
destroy_unhashed_deleg(dp);
}
+/**
+ * revoke_delegation - perform nfs4 delegation structure cleanup
+ * @dp: pointer to the delegation
+ *
+ * This function assumes that it's called either from the administrative
+ * interface (nfsd4_revoke_states()) that's revoking a specific delegation
+ * stateid or it's called from a laundromat thread (nfsd4_landromat()) that
+ * determined that this specific state has expired and needs to be revoked
+ * (both mark state with the appropriate stid sc_status mode). It is also
+ * assumed that a reference was taken on the @dp state.
+ *
+ * If this function finds that the @dp state is SC_STATUS_FREED it means
+ * that a FREE_STATEID operation for this stateid has been processed and
+ * we can proceed to removing it from recalled list. However, if @dp state
+ * isn't marked SC_STATUS_FREED, it means we need place it on the cl_revoked
+ * list and wait for the FREE_STATEID to arrive from the client. At the same
+ * time, we need to mark it as SC_STATUS_FREEABLE to indicate to the
+ * nfsd4_free_stateid() function that this stateid has already been added
+ * to the cl_revoked list and that nfsd4_free_stateid() is now responsible
+ * for removing it from the list. Inspection of where the delegation state
+ * in the revocation process is protected by the clp->cl_lock.
+ */
static void revoke_delegation(struct nfs4_delegation *dp)
{
struct nfs4_client *clp = dp->dl_stid.sc_client;
WARN_ON(!list_empty(&dp->dl_recall_lru));
+ WARN_ON_ONCE(!(dp->dl_stid.sc_status &
+ (SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)));
trace_nfsd_stid_revoke(&dp->dl_stid);
- if (dp->dl_stid.sc_status &
- (SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)) {
- spin_lock(&clp->cl_lock);
- refcount_inc(&dp->dl_stid.sc_count);
- list_add(&dp->dl_recall_lru, &clp->cl_revoked);
- spin_unlock(&clp->cl_lock);
+ spin_lock(&clp->cl_lock);
+ if (dp->dl_stid.sc_status & SC_STATUS_FREED) {
+ list_del_init(&dp->dl_recall_lru);
+ goto out;
}
+ list_add(&dp->dl_recall_lru, &clp->cl_revoked);
+ dp->dl_stid.sc_status |= SC_STATUS_FREEABLE;
+out:
+ spin_unlock(&clp->cl_lock);
destroy_unhashed_deleg(dp);
}
@@ -1780,6 +1806,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb)
mutex_unlock(&stp->st_mutex);
break;
case SC_TYPE_DELEG:
+ refcount_inc(&stid->sc_count);
dp = delegstateid(stid);
spin_lock(&state_lock);
if (!unhash_delegation_locked(
@@ -6545,6 +6572,7 @@ nfs4_laundromat(struct nfsd_net *nn)
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
if (!state_expired(&lt, dp->dl_time))
break;
+ refcount_inc(&dp->dl_stid.sc_count);
unhash_delegation_locked(dp, SC_STATUS_REVOKED);
list_add(&dp->dl_recall_lru, &reaplist);
}
@@ -7157,7 +7185,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
s->sc_status |= SC_STATUS_CLOSED;
spin_unlock(&s->sc_lock);
dp = delegstateid(s);
- list_del_init(&dp->dl_recall_lru);
+ if (s->sc_status & SC_STATUS_FREEABLE)
+ list_del_init(&dp->dl_recall_lru);
+ s->sc_status |= SC_STATUS_FREED;
spin_unlock(&cl->cl_lock);
nfs4_put_stid(s);
ret = nfs_ok;
@@ -7487,7 +7517,9 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
return status;
- status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG, 0, &s, nn);
+ status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG,
+ SC_STATUS_REVOKED | SC_STATUS_FREEABLE,
+ &s, nn);
if (status)
goto out;
dp = delegstateid(s);
@@ -8684,7 +8716,7 @@ nfs4_state_shutdown_net(struct net *net)
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
shrinker_free(nn->nfsd_client_shrinker);
- cancel_work(&nn->nfsd_shrinker_work);
+ cancel_work_sync(&nn->nfsd_shrinker_work);
cancel_delayed_work_sync(&nn->laundromat_work);
locks_end_grace(&nn->nfsd4_manager);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 79c743c01a47..35b3564c065f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -114,6 +114,8 @@ struct nfs4_stid {
/* For a deleg stateid kept around only to process free_stateid's: */
#define SC_STATUS_REVOKED BIT(1)
#define SC_STATUS_ADMIN_REVOKED BIT(2)
+#define SC_STATUS_FREEABLE BIT(3)
+#define SC_STATUS_FREED BIT(4)
unsigned short sc_status;
struct list_head sc_cp_list;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 22325b590e17..d6d4f2a0e898 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -903,11 +903,6 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
goto out;
}
- if (may_flags & NFSD_MAY_64BIT_COOKIE)
- file->f_mode |= FMODE_64BITHASH;
- else
- file->f_mode |= FMODE_32BITHASH;
-
*filp = file;
out:
return host_err;
@@ -2174,13 +2169,15 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
loff_t offset = *offsetp;
int may_flags = NFSD_MAY_READ;
- if (fhp->fh_64bit_cookies)
- may_flags |= NFSD_MAY_64BIT_COOKIE;
-
err = nfsd_open(rqstp, fhp, S_IFDIR, may_flags, &file);
if (err)
goto out;
+ if (fhp->fh_64bit_cookies)
+ file->f_mode |= FMODE_64BITHASH;
+ else
+ file->f_mode |= FMODE_32BITHASH;
+
offset = vfs_llseek(file, offset, SEEK_SET);
if (offset < 0) {
err = nfserrno((int)offset);
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
index 57b4af5ad646..501ad7be5174 100644
--- a/fs/nilfs2/btnode.c
+++ b/fs/nilfs2/btnode.c
@@ -68,7 +68,6 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
goto failed;
}
memset(bh->b_data, 0, i_blocksize(inode));
- bh->b_bdev = inode->i_sb->s_bdev;
bh->b_blocknr = blocknr;
set_buffer_mapped(bh);
set_buffer_uptodate(bh);
@@ -133,7 +132,6 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
goto found;
}
set_buffer_mapped(bh);
- bh->b_bdev = inode->i_sb->s_bdev;
bh->b_blocknr = pblocknr; /* set block address for read */
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c
index 1c9ae36a03ab..ace22253fed0 100644
--- a/fs/nilfs2/gcinode.c
+++ b/fs/nilfs2/gcinode.c
@@ -83,10 +83,8 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff,
goto out;
}
- if (!buffer_mapped(bh)) {
- bh->b_bdev = inode->i_sb->s_bdev;
+ if (!buffer_mapped(bh))
set_buffer_mapped(bh);
- }
bh->b_blocknr = pbn;
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index ceb7dc0b5bad..2db6350b5ac2 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -89,7 +89,6 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block,
if (buffer_uptodate(bh))
goto failed_bh;
- bh->b_bdev = sb->s_bdev;
err = nilfs_mdt_insert_new_block(inode, block, bh, init_block);
if (likely(!err)) {
get_bh(bh);
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 4905063790c5..9b108052d9f7 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -157,6 +157,9 @@ static int nilfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
/* slow symlink */
inode->i_op = &nilfs_symlink_inode_operations;
inode_nohighmem(inode);
+ mapping_set_gfp_mask(inode->i_mapping,
+ mapping_gfp_constraint(inode->i_mapping,
+ ~__GFP_FS));
inode->i_mapping->a_ops = &nilfs_aops;
err = page_symlink(inode, symname, l);
if (err)
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index 5436eb0424bd..6dd8b854cd1f 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -39,7 +39,6 @@ static struct buffer_head *__nilfs_get_folio_block(struct folio *folio,
first_block = (unsigned long)index << (PAGE_SHIFT - blkbits);
bh = get_nth_bh(bh, block - first_block);
- touch_buffer(bh);
wait_on_buffer(bh);
return bh;
}
@@ -64,6 +63,7 @@ struct buffer_head *nilfs_grab_buffer(struct inode *inode,
folio_put(folio);
return NULL;
}
+ bh->b_bdev = inode->i_sb->s_bdev;
return bh;
}
@@ -401,6 +401,7 @@ void nilfs_clear_folio_dirty(struct folio *folio)
folio_clear_uptodate(folio);
folio_clear_mappedtodisk(folio);
+ folio_clear_checked(folio);
head = folio_buffers(folio);
if (head) {
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 58887456e3c5..06af21982c16 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1787,6 +1787,14 @@ int ocfs2_remove_inode_range(struct inode *inode,
return 0;
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ int id_count = ocfs2_max_inline_data_with_xattr(inode->i_sb, di);
+
+ if (byte_start > id_count || byte_start + byte_len > id_count) {
+ ret = -EINVAL;
+ mlog_errno(ret);
+ goto out;
+ }
+
ret = ocfs2_truncate_inline(inode, di_bh, byte_start,
byte_start + byte_len, 0);
if (ret) {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 3d404624bb96..c79b4291777f 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -2319,6 +2319,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
struct ocfs2_blockcheck_stats *stats)
{
int status = -EAGAIN;
+ u32 blksz_bits;
if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE,
strlen(OCFS2_SUPER_BLOCK_SIGNATURE)) == 0) {
@@ -2333,11 +2334,15 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
goto out;
}
status = -EINVAL;
- if ((1 << le32_to_cpu(di->id2.i_super.s_blocksize_bits)) != blksz) {
+ /* Acceptable block sizes are 512 bytes, 1K, 2K and 4K. */
+ blksz_bits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
+ if (blksz_bits < 9 || blksz_bits > 12) {
mlog(ML_ERROR, "found superblock with incorrect block "
- "size: found %u, should be %u\n",
- 1 << le32_to_cpu(di->id2.i_super.s_blocksize_bits),
- blksz);
+ "size bits: found %u, should be 9, 10, 11, or 12\n",
+ blksz_bits);
+ } else if ((1 << le32_to_cpu(blksz_bits)) != blksz) {
+ mlog(ML_ERROR, "found superblock with incorrect block "
+ "size: found %u, should be %u\n", 1 << blksz_bits, blksz);
} else if (le16_to_cpu(di->id2.i_super.s_major_rev_level) !=
OCFS2_MAJOR_REV_LEVEL ||
le16_to_cpu(di->id2.i_super.s_minor_rev_level) !=
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index dd0a05365e79..73a6f6fd8a8e 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -2036,8 +2036,7 @@ static int ocfs2_xa_remove(struct ocfs2_xa_loc *loc,
rc = 0;
ocfs2_xa_cleanup_value_truncate(loc, "removing",
orig_clusters);
- if (rc)
- goto out;
+ goto out;
}
}
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 4504493b20be..4444c78e2e0c 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -231,6 +231,11 @@ static void ovl_file_modified(struct file *file)
ovl_copyattr(file_inode(file));
}
+static void ovl_file_end_write(struct file *file, loff_t pos, ssize_t ret)
+{
+ ovl_file_modified(file);
+}
+
static void ovl_file_accessed(struct file *file)
{
struct inode *inode, *upperinode;
@@ -294,7 +299,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
struct backing_file_ctx ctx = {
.cred = ovl_creds(inode->i_sb),
.user_file = file,
- .end_write = ovl_file_modified,
+ .end_write = ovl_file_end_write,
};
if (!iov_iter_count(iter))
@@ -364,7 +369,7 @@ static ssize_t ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
struct backing_file_ctx ctx = {
.cred = ovl_creds(inode->i_sb),
.user_file = out,
- .end_write = ovl_file_modified,
+ .end_write = ovl_file_end_write,
};
inode_lock(inode);
diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c
index f4616083faef..04bb29721419 100644
--- a/fs/proc/softirqs.c
+++ b/fs/proc/softirqs.c
@@ -20,7 +20,7 @@ static int show_softirqs(struct seq_file *p, void *v)
for (i = 0; i < NR_SOFTIRQS; i++) {
seq_printf(p, "%12s:", softirq_to_name[i]);
for_each_possible_cpu(j)
- seq_printf(p, " %10u", kstat_softirqs_cpu(i, j));
+ seq_put_decimal_ull_width(p, " ", kstat_softirqs_cpu(i, j), 10);
seq_putc(p, '\n');
}
return 0;
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index b52d85f8ad59..b4521b096058 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -457,10 +457,6 @@ static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
#endif
}
-static const struct vm_operations_struct vmcore_mmap_ops = {
- .fault = mmap_vmcore_fault,
-};
-
/**
* vmcore_alloc_buf - allocate buffer in vmalloc memory
* @size: size of buffer
@@ -488,6 +484,11 @@ static inline char *vmcore_alloc_buf(size_t size)
* virtually contiguous user-space in ELF layout.
*/
#ifdef CONFIG_MMU
+
+static const struct vm_operations_struct vmcore_mmap_ops = {
+ .fault = mmap_vmcore_fault,
+};
+
/*
* remap_oldmem_pfn_checked - do remap_oldmem_pfn_range replacing all pages
* reported as not being ram with the zero page.
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 000e1ef3beea..20cafdff5081 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1780,7 +1780,7 @@ static int cifs_init_netfs(void)
nomem_subreqpool:
kmem_cache_destroy(cifs_io_subrequest_cachep);
nomem_subreq:
- mempool_destroy(&cifs_io_request_pool);
+ mempool_exit(&cifs_io_request_pool);
nomem_reqpool:
kmem_cache_destroy(cifs_io_request_cachep);
nomem_req:
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 15d94ac4095e..0ce2d704b1f3 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -1037,6 +1037,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
*/
}
+ put_net(cifs_net_ns(server));
kfree(server->leaf_fullpath);
kfree(server);
@@ -1635,8 +1636,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
/* srv_count can never go negative */
WARN_ON(server->srv_count < 0);
- put_net(cifs_net_ns(server));
-
list_del_init(&server->tcp_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
@@ -3070,13 +3069,22 @@ generic_ip_connect(struct TCP_Server_Info *server)
if (server->ssocket) {
socket = server->ssocket;
} else {
- rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
+ struct net *net = cifs_net_ns(server);
+ struct sock *sk;
+
+ rc = __sock_create(net, sfamily, SOCK_STREAM,
IPPROTO_TCP, &server->ssocket, 1);
if (rc < 0) {
cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
return rc;
}
+ sk = server->ssocket->sk;
+ __netns_tracker_free(net, &sk->ns_tracker, false);
+ sk->sk_net_refcnt = 1;
+ get_net_track(net, &sk->ns_tracker, GFP_KERNEL);
+ sock_inuse_add(net, 1);
+
/* BB other socket options to set KEEPALIVE, NODELAY? */
cifs_dbg(FYI, "Socket created\n");
socket = server->ssocket;
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 28c4e576d460..5c5a52019efa 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -920,8 +920,15 @@ static int smb3_reconfigure(struct fs_context *fc)
else {
kfree_sensitive(ses->password);
ses->password = kstrdup(ctx->password, GFP_KERNEL);
+ if (!ses->password)
+ return -ENOMEM;
kfree_sensitive(ses->password2);
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
+ if (!ses->password2) {
+ kfree_sensitive(ses->password);
+ ses->password = NULL;
+ return -ENOMEM;
+ }
}
STEAL_STRING(cifs_sb, ctx, domainname);
STEAL_STRING(cifs_sb, ctx, nodename);
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index aa2a37a7ce84..e6a72f75ab94 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -70,6 +70,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
atomic_set(&conn->req_running, 0);
atomic_set(&conn->r_count, 0);
atomic_set(&conn->refcnt, 1);
+ atomic_set(&conn->mux_smb_requests, 0);
conn->total_credits = 1;
conn->outstanding_credits = 0;
diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
index b379ae4fdcdf..8ddd5a3c7baf 100644
--- a/fs/smb/server/connection.h
+++ b/fs/smb/server/connection.h
@@ -107,6 +107,7 @@ struct ksmbd_conn {
__le16 signing_algorithm;
bool binding;
atomic_t refcnt;
+ atomic_t mux_smb_requests;
};
struct ksmbd_conn_ops {
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 1e4624e9d434..ad02fe555fda 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -90,7 +90,7 @@ static int __rpc_method(char *rpc_name)
int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
{
- struct ksmbd_session_rpc *entry;
+ struct ksmbd_session_rpc *entry, *old;
struct ksmbd_rpc_command *resp;
int method;
@@ -106,16 +106,19 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
entry->id = ksmbd_ipc_id_alloc();
if (entry->id < 0)
goto free_entry;
- xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
+ old = xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
+ if (xa_is_err(old))
+ goto free_id;
resp = ksmbd_rpc_open(sess, entry->id);
if (!resp)
- goto free_id;
+ goto erase_xa;
kvfree(resp);
return entry->id;
-free_id:
+erase_xa:
xa_erase(&sess->rpc_handle_list, entry->id);
+free_id:
ksmbd_rpc_id_free(entry->id);
free_entry:
kfree(entry);
@@ -175,6 +178,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
unsigned long id;
struct ksmbd_session *sess;
+ down_write(&sessions_table_lock);
down_write(&conn->session_lock);
xa_for_each(&conn->sessions, id, sess) {
if (atomic_read(&sess->refcnt) == 0 &&
@@ -188,6 +192,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
}
}
up_write(&conn->session_lock);
+ up_write(&sessions_table_lock);
}
int ksmbd_session_register(struct ksmbd_conn *conn,
@@ -229,7 +234,6 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
}
}
}
- up_write(&sessions_table_lock);
down_write(&conn->session_lock);
xa_for_each(&conn->sessions, id, sess) {
@@ -249,6 +253,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
}
}
up_write(&conn->session_lock);
+ up_write(&sessions_table_lock);
}
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index 9670c97f14b3..e6cfedba9992 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -238,11 +238,11 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
} while (is_chained == true);
send:
- if (work->sess)
- ksmbd_user_session_put(work->sess);
if (work->tcon)
ksmbd_tree_connect_put(work->tcon);
smb3_preauth_hash_rsp(work);
+ if (work->sess)
+ ksmbd_user_session_put(work->sess);
if (work->sess && work->sess->enc && work->encrypted &&
conn->ops->encrypt_resp) {
rc = conn->ops->encrypt_resp(work);
@@ -270,6 +270,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
ksmbd_conn_try_dequeue_request(work);
ksmbd_free_work_struct(work);
+ atomic_dec(&conn->mux_smb_requests);
/*
* Checking waitqueue to dropping pending requests on
* disconnection. waitqueue_active is safe because it
@@ -291,6 +292,15 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
struct ksmbd_work *work;
int err;
+ err = ksmbd_init_smb_server(conn);
+ if (err)
+ return 0;
+
+ if (atomic_inc_return(&conn->mux_smb_requests) >= conn->vals->max_credits) {
+ atomic_dec_return(&conn->mux_smb_requests);
+ return -ENOSPC;
+ }
+
work = ksmbd_alloc_work_struct();
if (!work) {
pr_err("allocation for work failed\n");
@@ -301,12 +311,6 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
work->request_buf = conn->request_buf;
conn->request_buf = NULL;
- err = ksmbd_init_smb_server(work);
- if (err) {
- ksmbd_free_work_struct(work);
- return 0;
- }
-
ksmbd_conn_enqueue_request(work);
atomic_inc(&conn->r_count);
/* update activity on connection */
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index a2ebbe604c8c..75b4eb856d32 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -388,6 +388,10 @@ static struct smb_version_ops smb1_server_ops = {
.set_rsp_status = set_smb1_rsp_status,
};
+static struct smb_version_values smb1_server_values = {
+ .max_credits = SMB2_MAX_CREDITS,
+};
+
static int smb1_negotiate(struct ksmbd_work *work)
{
return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
@@ -399,18 +403,18 @@ static struct smb_version_cmds smb1_server_cmds[1] = {
static int init_smb1_server(struct ksmbd_conn *conn)
{
+ conn->vals = &smb1_server_values;
conn->ops = &smb1_server_ops;
conn->cmds = smb1_server_cmds;
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
return 0;
}
-int ksmbd_init_smb_server(struct ksmbd_work *work)
+int ksmbd_init_smb_server(struct ksmbd_conn *conn)
{
- struct ksmbd_conn *conn = work->conn;
__le32 proto;
- proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
+ proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
if (conn->need_neg == false) {
if (proto == SMB1_PROTO_NUMBER)
return -EINVAL;
diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h
index cc1d6dfe29d5..a3d8a905b07e 100644
--- a/fs/smb/server/smb_common.h
+++ b/fs/smb/server/smb_common.h
@@ -427,7 +427,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
-int ksmbd_init_smb_server(struct ksmbd_work *work);
+int ksmbd_init_smb_server(struct ksmbd_conn *conn);
struct ksmbd_kstat;
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work,
diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c
index 22251743fadf..d19d4db74af8 100644
--- a/fs/squashfs/file_direct.c
+++ b/fs/squashfs/file_direct.c
@@ -30,7 +30,8 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
loff_t start_index = folio->index & ~mask;
loff_t end_index = start_index | mask;
- int i, n, pages, bytes, res = -ENOMEM;
+ loff_t index;
+ int i, pages, bytes, res = -ENOMEM;
struct page **page, *last_page;
struct squashfs_page_actor *actor;
void *pageaddr;
@@ -45,9 +46,9 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
return res;
/* Try to grab all the pages covered by the Squashfs block */
- for (i = 0, n = start_index; n <= end_index; n++) {
- page[i] = (n == folio->index) ? target_page :
- grab_cache_page_nowait(target_page->mapping, n);
+ for (i = 0, index = start_index; index <= end_index; index++) {
+ page[i] = (index == folio->index) ? target_page :
+ grab_cache_page_nowait(target_page->mapping, index);
if (page[i] == NULL)
continue;
diff --git a/fs/super.c b/fs/super.c
index 1db230432960..c9c7223bc2a2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1596,13 +1596,14 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
EXPORT_SYMBOL_GPL(setup_bdev_super);
/**
- * get_tree_bdev - Get a superblock based on a single block device
+ * get_tree_bdev_flags - Get a superblock based on a single block device
* @fc: The filesystem context holding the parameters
* @fill_super: Helper to initialise a new superblock
+ * @flags: GET_TREE_BDEV_* flags
*/
-int get_tree_bdev(struct fs_context *fc,
- int (*fill_super)(struct super_block *,
- struct fs_context *))
+int get_tree_bdev_flags(struct fs_context *fc,
+ int (*fill_super)(struct super_block *sb,
+ struct fs_context *fc), unsigned int flags)
{
struct super_block *s;
int error = 0;
@@ -1613,10 +1614,10 @@ int get_tree_bdev(struct fs_context *fc,
error = lookup_bdev(fc->source, &dev);
if (error) {
- errorf(fc, "%s: Can't lookup blockdev", fc->source);
+ if (!(flags & GET_TREE_BDEV_QUIET_LOOKUP))
+ errorf(fc, "%s: Can't lookup blockdev", fc->source);
return error;
}
-
fc->sb_flags |= SB_NOSEC;
s = sget_dev(fc, dev);
if (IS_ERR(s))
@@ -1644,6 +1645,19 @@ int get_tree_bdev(struct fs_context *fc,
fc->root = dget(s->s_root);
return 0;
}
+EXPORT_SYMBOL_GPL(get_tree_bdev_flags);
+
+/**
+ * get_tree_bdev - Get a superblock based on a single block device
+ * @fc: The filesystem context holding the parameters
+ * @fill_super: Helper to initialise a new superblock
+ */
+int get_tree_bdev(struct fs_context *fc,
+ int (*fill_super)(struct super_block *,
+ struct fs_context *))
+{
+ return get_tree_bdev_flags(fc, fill_super, 0);
+}
EXPORT_SYMBOL(get_tree_bdev);
static int test_bdev_super(struct super_block *s, void *data)
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 1748dff58c3b..cfc614c638da 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -392,6 +392,9 @@ static int tracefs_reconfigure(struct fs_context *fc)
struct tracefs_fs_info *sb_opts = sb->s_fs_info;
struct tracefs_fs_info *new_opts = fc->s_fs_info;
+ if (!new_opts)
+ return 0;
+
sync_filesystem(sb);
/* structure copy of new mount options to sb */
*sb_opts = *new_opts;
@@ -478,14 +481,17 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_op = &tracefs_super_operations;
sb->s_d_op = &tracefs_dentry_operations;
- tracefs_apply_options(sb, false);
-
return 0;
}
static int tracefs_get_tree(struct fs_context *fc)
{
- return get_tree_single(fc, tracefs_fill_super);
+ int err = get_tree_single(fc, tracefs_fill_super);
+
+ if (err)
+ return err;
+
+ return tracefs_reconfigure(fc);
}
static void tracefs_free_fc(struct fs_context *fc)
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 68cdd89c97a3..7c0bd0b55f88 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -692,6 +692,34 @@ void dup_userfaultfd_complete(struct list_head *fcs)
}
}
+void dup_userfaultfd_fail(struct list_head *fcs)
+{
+ struct userfaultfd_fork_ctx *fctx, *n;
+
+ /*
+ * An error has occurred on fork, we will tear memory down, but have
+ * allocated memory for fctx's and raised reference counts for both the
+ * original and child contexts (and on the mm for each as a result).
+ *
+ * These would ordinarily be taken care of by a user handling the event,
+ * but we are no longer doing so, so manually clean up here.
+ *
+ * mm tear down will take care of cleaning up VMA contexts.
+ */
+ list_for_each_entry_safe(fctx, n, fcs, list) {
+ struct userfaultfd_ctx *octx = fctx->orig;
+ struct userfaultfd_ctx *ctx = fctx->new;
+
+ atomic_dec(&octx->mmap_changing);
+ VM_BUG_ON(atomic_read(&octx->mmap_changing) < 0);
+ userfaultfd_ctx_put(octx);
+ userfaultfd_ctx_put(ctx);
+
+ list_del(&fctx->list);
+ kfree(fctx);
+ }
+}
+
void mremap_userfaultfd_prep(struct vm_area_struct *vma,
struct vm_userfaultfd_ctx *vm_ctx)
{
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index 5f0494702e0b..5ca8d0106827 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -185,17 +185,20 @@ out:
}
/*
- * Free up the per-ag resources associated with the mount structure.
+ * Free up the per-ag resources within the specified AG range.
*/
void
-xfs_free_perag(
- struct xfs_mount *mp)
+xfs_free_perag_range(
+ struct xfs_mount *mp,
+ xfs_agnumber_t first_agno,
+ xfs_agnumber_t end_agno)
+
{
- struct xfs_perag *pag;
xfs_agnumber_t agno;
- for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
- pag = xa_erase(&mp->m_perags, agno);
+ for (agno = first_agno; agno < end_agno; agno++) {
+ struct xfs_perag *pag = xa_erase(&mp->m_perags, agno);
+
ASSERT(pag);
XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
xfs_defer_drain_free(&pag->pag_intents_drain);
@@ -270,54 +273,37 @@ xfs_agino_range(
return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
}
-/*
- * Free perag within the specified AG range, it is only used to free unused
- * perags under the error handling path.
- */
-void
-xfs_free_unused_perag_range(
+int
+xfs_update_last_ag_size(
struct xfs_mount *mp,
- xfs_agnumber_t agstart,
- xfs_agnumber_t agend)
+ xfs_agnumber_t prev_agcount)
{
- struct xfs_perag *pag;
- xfs_agnumber_t index;
+ struct xfs_perag *pag = xfs_perag_grab(mp, prev_agcount - 1);
- for (index = agstart; index < agend; index++) {
- pag = xa_erase(&mp->m_perags, index);
- if (!pag)
- break;
- xfs_buf_cache_destroy(&pag->pag_bcache);
- xfs_defer_drain_free(&pag->pag_intents_drain);
- kfree(pag);
- }
+ if (!pag)
+ return -EFSCORRUPTED;
+ pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1,
+ mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks);
+ __xfs_agino_range(mp, pag->block_count, &pag->agino_min,
+ &pag->agino_max);
+ xfs_perag_rele(pag);
+ return 0;
}
int
xfs_initialize_perag(
struct xfs_mount *mp,
- xfs_agnumber_t agcount,
+ xfs_agnumber_t old_agcount,
+ xfs_agnumber_t new_agcount,
xfs_rfsblock_t dblocks,
xfs_agnumber_t *maxagi)
{
struct xfs_perag *pag;
xfs_agnumber_t index;
- xfs_agnumber_t first_initialised = NULLAGNUMBER;
int error;
- /*
- * Walk the current per-ag tree so we don't try to initialise AGs
- * that already exist (growfs case). Allocate and insert all the
- * AGs we don't find ready for initialisation.
- */
- for (index = 0; index < agcount; index++) {
- pag = xfs_perag_get(mp, index);
- if (pag) {
- xfs_perag_put(pag);
- continue;
- }
-
- pag = kzalloc(sizeof(*pag), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
+ for (index = old_agcount; index < new_agcount; index++) {
+ pag = kzalloc(sizeof(*pag), GFP_KERNEL);
if (!pag) {
error = -ENOMEM;
goto out_unwind_new_pags;
@@ -353,21 +339,17 @@ xfs_initialize_perag(
/* Active ref owned by mount indicates AG is online. */
atomic_set(&pag->pag_active_ref, 1);
- /* first new pag is fully initialized */
- if (first_initialised == NULLAGNUMBER)
- first_initialised = index;
-
/*
* Pre-calculated geometry
*/
- pag->block_count = __xfs_ag_block_count(mp, index, agcount,
+ pag->block_count = __xfs_ag_block_count(mp, index, new_agcount,
dblocks);
pag->min_block = XFS_AGFL_BLOCK(mp);
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
&pag->agino_max);
}
- index = xfs_set_inode_alloc(mp, agcount);
+ index = xfs_set_inode_alloc(mp, new_agcount);
if (maxagi)
*maxagi = index;
@@ -381,8 +363,7 @@ out_remove_pag:
out_free_pag:
kfree(pag);
out_unwind_new_pags:
- /* unwind any prior newly initialized pags */
- xfs_free_unused_perag_range(mp, first_initialised, agcount);
+ xfs_free_perag_range(mp, old_agcount, index);
return error;
}
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index d9cccd093b60..9edfe0e96439 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -144,12 +144,13 @@ __XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
-void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
- xfs_agnumber_t agend);
-int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
- xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
+int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
+ xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
+ xfs_agnumber_t *maxagi);
+void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
+ xfs_agnumber_t end_agno);
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
-void xfs_free_perag(struct xfs_mount *mp);
+int xfs_update_last_ag_size(struct xfs_mount *mp, xfs_agnumber_t prev_agcount);
/* Passive AG references */
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 04f64cf9777e..22bdbb3e9980 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -1923,7 +1923,7 @@ restart:
error = -EFSCORRUPTED;
goto error0;
}
- if (flen < bestrlen)
+ if (flen <= bestrlen)
break;
busy = xfs_alloc_compute_aligned(args, fbno, flen,
&rbno, &rlen, &busy_gen);
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 67478294f11a..155bbaaa496e 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -1084,9 +1084,11 @@ xrep_metadata_inode_forks(
return error;
/* Make sure the attr fork looks ok before we delete it. */
- error = xrep_metadata_inode_subtype(sc, XFS_SCRUB_TYPE_BMBTA);
- if (error)
- return error;
+ if (xfs_inode_hasattr(sc->ip)) {
+ error = xrep_metadata_inode_subtype(sc, XFS_SCRUB_TYPE_BMBTA);
+ if (error)
+ return error;
+ }
/* Clear the reflink flag since metadata never shares. */
if (xfs_is_reflink_inode(sc->ip)) {
diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
index 09e893cf563c..5180cbf5a90b 100644
--- a/fs/xfs/xfs_buf_item_recover.c
+++ b/fs/xfs/xfs_buf_item_recover.c
@@ -22,6 +22,9 @@
#include "xfs_inode.h"
#include "xfs_dir2.h"
#include "xfs_quota.h"
+#include "xfs_alloc.h"
+#include "xfs_ag.h"
+#include "xfs_sb.h"
/*
* This is the number of entries in the l_buf_cancel_table used during
@@ -685,6 +688,67 @@ xlog_recover_do_inode_buffer(
}
/*
+ * Update the in-memory superblock and perag structures from the primary SB
+ * buffer.
+ *
+ * This is required because transactions running after growfs may require the
+ * updated values to be set in a previous fully commit transaction.
+ */
+static int
+xlog_recover_do_primary_sb_buffer(
+ struct xfs_mount *mp,
+ struct xlog_recover_item *item,
+ struct xfs_buf *bp,
+ struct xfs_buf_log_format *buf_f,
+ xfs_lsn_t current_lsn)
+{
+ struct xfs_dsb *dsb = bp->b_addr;
+ xfs_agnumber_t orig_agcount = mp->m_sb.sb_agcount;
+ int error;
+
+ xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+
+ if (orig_agcount == 0) {
+ xfs_alert(mp, "Trying to grow file system without AGs");
+ return -EFSCORRUPTED;
+ }
+
+ /*
+ * Update the in-core super block from the freshly recovered on-disk one.
+ */
+ xfs_sb_from_disk(&mp->m_sb, dsb);
+
+ if (mp->m_sb.sb_agcount < orig_agcount) {
+ xfs_alert(mp, "Shrinking AG count in log recovery not supported");
+ return -EFSCORRUPTED;
+ }
+
+ /*
+ * Growfs can also grow the last existing AG. In this case we also need
+ * to update the length in the in-core perag structure and values
+ * depending on it.
+ */
+ error = xfs_update_last_ag_size(mp, orig_agcount);
+ if (error)
+ return error;
+
+ /*
+ * Initialize the new perags, and also update various block and inode
+ * allocator setting based off the number of AGs or total blocks.
+ * Because of the latter this also needs to happen if the agcount did
+ * not change.
+ */
+ error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount,
+ mp->m_sb.sb_dblocks, &mp->m_maxagi);
+ if (error) {
+ xfs_warn(mp, "Failed recovery per-ag init: %d", error);
+ return error;
+ }
+ mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
+ return 0;
+}
+
+/*
* V5 filesystems know the age of the buffer on disk being recovered. We can
* have newer objects on disk than we are replaying, and so for these cases we
* don't want to replay the current change as that will make the buffer contents
@@ -967,6 +1031,12 @@ xlog_recover_buf_commit_pass2(
dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
if (!dirty)
goto out_release;
+ } else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) &&
+ xfs_buf_daddr(bp) == 0) {
+ error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
+ current_lsn);
+ if (error)
+ goto out_release;
} else {
xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
}
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index e3aaa0555597..290ba8887d29 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -64,25 +64,31 @@ xfs_filestream_pick_ag(
struct xfs_perag *pag;
struct xfs_perag *max_pag = NULL;
xfs_extlen_t minlen = *longest;
- xfs_extlen_t free = 0, minfree, maxfree = 0;
+ xfs_extlen_t minfree, maxfree = 0;
xfs_agnumber_t agno;
bool first_pass = true;
- int err;
/* 2% of an AG's blocks must be free for it to be chosen. */
minfree = mp->m_sb.sb_agblocks / 50;
restart:
for_each_perag_wrap(mp, start_agno, agno, pag) {
+ int err;
+
trace_xfs_filestream_scan(pag, pino);
+
*longest = 0;
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
if (err) {
- if (err != -EAGAIN)
- break;
- /* Couldn't lock the AGF, skip this AG. */
- err = 0;
- continue;
+ if (err == -EAGAIN) {
+ /* Couldn't lock the AGF, skip this AG. */
+ err = 0;
+ continue;
+ }
+ xfs_perag_rele(pag);
+ if (max_pag)
+ xfs_perag_rele(max_pag);
+ return err;
}
/* Keep track of the AG with the most free blocks. */
@@ -107,8 +113,9 @@ restart:
!(flags & XFS_PICK_USERDATA) ||
(flags & XFS_PICK_LOWSPACE))) {
/* Break out, retaining the reference on the AG. */
- free = pag->pagf_freeblks;
- break;
+ if (max_pag)
+ xfs_perag_rele(max_pag);
+ goto done;
}
}
@@ -116,57 +123,47 @@ restart:
atomic_dec(&pag->pagf_fstrms);
}
- if (err) {
- xfs_perag_rele(pag);
- if (max_pag)
- xfs_perag_rele(max_pag);
- return err;
+ /*
+ * Allow a second pass to give xfs_bmap_longest_free_extent() another
+ * attempt at locking AGFs that it might have skipped over before we
+ * fail.
+ */
+ if (first_pass) {
+ first_pass = false;
+ goto restart;
}
- if (!pag) {
- /*
- * Allow a second pass to give xfs_bmap_longest_free_extent()
- * another attempt at locking AGFs that it might have skipped
- * over before we fail.
- */
- if (first_pass) {
- first_pass = false;
- goto restart;
- }
+ /*
+ * We must be low on data space, so run a final lowspace optimised
+ * selection pass if we haven't already.
+ */
+ if (!(flags & XFS_PICK_LOWSPACE)) {
+ flags |= XFS_PICK_LOWSPACE;
+ goto restart;
+ }
- /*
- * We must be low on data space, so run a final lowspace
- * optimised selection pass if we haven't already.
- */
- if (!(flags & XFS_PICK_LOWSPACE)) {
- flags |= XFS_PICK_LOWSPACE;
- goto restart;
+ /*
+ * No unassociated AGs are available, so select the AG with the most
+ * free space, regardless of whether it's already in use by another
+ * filestream. It none suit, just use whatever AG we can grab.
+ */
+ if (!max_pag) {
+ for_each_perag_wrap(args->mp, 0, start_agno, pag) {
+ max_pag = pag;
+ break;
}
- /*
- * No unassociated AGs are available, so select the AG with the
- * most free space, regardless of whether it's already in use by
- * another filestream. It none suit, just use whatever AG we can
- * grab.
- */
- if (!max_pag) {
- for_each_perag_wrap(args->mp, 0, start_agno, args->pag)
- break;
- atomic_inc(&args->pag->pagf_fstrms);
- *longest = 0;
- } else {
- pag = max_pag;
- free = maxfree;
- atomic_inc(&pag->pagf_fstrms);
- }
- } else if (max_pag) {
- xfs_perag_rele(max_pag);
+ /* Bail if there are no AGs at all to select from. */
+ if (!max_pag)
+ return -ENOSPC;
}
- trace_xfs_filestream_pick(pag, pino, free);
+ pag = max_pag;
+ atomic_inc(&pag->pagf_fstrms);
+done:
+ trace_xfs_filestream_pick(pag, pino);
args->pag = pag;
return 0;
-
}
static struct xfs_inode *
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 3643cc843f62..b247d895c276 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -87,6 +87,7 @@ xfs_growfs_data_private(
struct xfs_mount *mp, /* mount point for filesystem */
struct xfs_growfs_data *in) /* growfs data input struct */
{
+ xfs_agnumber_t oagcount = mp->m_sb.sb_agcount;
struct xfs_buf *bp;
int error;
xfs_agnumber_t nagcount;
@@ -94,7 +95,6 @@ xfs_growfs_data_private(
xfs_rfsblock_t nb, nb_div, nb_mod;
int64_t delta;
bool lastag_extended = false;
- xfs_agnumber_t oagcount;
struct xfs_trans *tp;
struct aghdr_init_data id = {};
struct xfs_perag *last_pag;
@@ -138,16 +138,14 @@ xfs_growfs_data_private(
if (delta == 0)
return 0;
- oagcount = mp->m_sb.sb_agcount;
- /* allocate the new per-ag structures */
- if (nagcount > oagcount) {
- error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
- if (error)
- return error;
- } else if (nagcount < oagcount) {
- /* TODO: shrinking the entire AGs hasn't yet completed */
+ /* TODO: shrinking the entire AGs hasn't yet completed */
+ if (nagcount < oagcount)
return -EINVAL;
- }
+
+ /* allocate the new per-ag structures */
+ error = xfs_initialize_perag(mp, oagcount, nagcount, nb, &nagimax);
+ if (error)
+ return error;
if (delta > 0)
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
@@ -231,7 +229,7 @@ out_trans_cancel:
xfs_trans_cancel(tp);
out_free_unused_perag:
if (nagcount > oagcount)
- xfs_free_unused_perag_range(mp, oagcount, nagcount);
+ xfs_free_perag_range(mp, oagcount, nagcount);
return error;
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index bcc277fc0a83..19dcb569a3e7 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1409,7 +1409,7 @@ xfs_inactive(
if (S_ISREG(VFS_I(ip)->i_mode) &&
(ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
- ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
+ xfs_inode_has_filedata(ip)))
truncate = 1;
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 97ed912306fd..03944b6c5fba 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -292,6 +292,11 @@ static inline bool xfs_is_cow_inode(struct xfs_inode *ip)
return xfs_is_reflink_inode(ip) || xfs_is_always_cow_inode(ip);
}
+static inline bool xfs_inode_has_filedata(const struct xfs_inode *ip)
+{
+ return ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0;
+}
+
/*
* Check if an inode has any data in the COW fork. This might be often false
* even for inodes with the reflink flag when there is no pending COW operation.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index a20d426ef021..2567fd2a0994 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -481,7 +481,7 @@ xfs_ioctl_setattr_xflags(
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
/* Can't change realtime flag if any extents are allocated. */
- if (ip->i_df.if_nextents || ip->i_delayed_blks)
+ if (xfs_inode_has_filedata(ip))
return -EINVAL;
/*
@@ -602,7 +602,7 @@ xfs_ioctl_setattr_check_extsize(
if (!fa->fsx_valid)
return 0;
- if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
+ if (S_ISREG(VFS_I(ip)->i_mode) && xfs_inode_has_filedata(ip) &&
XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
return -EINVAL;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 916531d9f83c..86da16f54be9 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -707,7 +707,7 @@ imap_needs_cow(
return false;
/* when zeroing we don't have to COW holes or unwritten extents */
- if (flags & IOMAP_ZERO) {
+ if (flags & (IOMAP_UNSHARE | IOMAP_ZERO)) {
if (!nimaps ||
imap->br_startblock == HOLESTARTBLOCK ||
imap->br_state == XFS_EXT_UNWRITTEN)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index a13bf53fea49..704aaadb61cf 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3393,13 +3393,6 @@ xlog_do_recover(
/* re-initialise in-core superblock and geometry structures */
mp->m_features |= xfs_sb_version_to_features(sbp);
xfs_reinit_percpu_counters(mp);
- error = xfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
- &mp->m_maxagi);
- if (error) {
- xfs_warn(mp, "Failed post-recovery per-ag init: %d", error);
- return error;
- }
- mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
/* Normal transactions can now occur */
clear_bit(XLOG_ACTIVE_RECOVERY, &log->l_opstate);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 1fdd79c5bfa0..25bbcc3f4ee0 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -810,8 +810,8 @@ xfs_mountfs(
/*
* Allocate and initialize the per-ag data.
*/
- error = xfs_initialize_perag(mp, sbp->sb_agcount, mp->m_sb.sb_dblocks,
- &mp->m_maxagi);
+ error = xfs_initialize_perag(mp, 0, sbp->sb_agcount,
+ mp->m_sb.sb_dblocks, &mp->m_maxagi);
if (error) {
xfs_warn(mp, "Failed per-ag init: %d", error);
goto out_free_dir;
@@ -1048,7 +1048,7 @@ xfs_mountfs(
xfs_buftarg_drain(mp->m_logdev_targp);
xfs_buftarg_drain(mp->m_ddev_targp);
out_free_perag:
- xfs_free_perag(mp);
+ xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount);
out_free_dir:
xfs_da_unmount(mp);
out_remove_uuid:
@@ -1129,8 +1129,7 @@ xfs_unmountfs(
xfs_errortag_clearall(mp);
#endif
shrinker_free(mp->m_inodegc_shrinker);
- xfs_free_perag(mp);
-
+ xfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount);
xfs_errortag_del(mp);
xfs_error_sysfs_del(mp);
xchk_stats_unregister(mp->m_scrub_stats);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index ee9f0b1f548d..fcb2bad4f76e 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -691,8 +691,8 @@ DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
TRACE_EVENT(xfs_filestream_pick,
- TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino, xfs_extlen_t free),
- TP_ARGS(pag, ino, free),
+ TP_PROTO(struct xfs_perag *pag, xfs_ino_t ino),
+ TP_ARGS(pag, ino),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
@@ -703,14 +703,9 @@ TRACE_EVENT(xfs_filestream_pick,
TP_fast_assign(
__entry->dev = pag->pag_mount->m_super->s_dev;
__entry->ino = ino;
- if (pag) {
- __entry->agno = pag->pag_agno;
- __entry->streams = atomic_read(&pag->pagf_fstrms);
- } else {
- __entry->agno = NULLAGNUMBER;
- __entry->streams = 0;
- }
- __entry->free = free;
+ __entry->agno = pag->pag_agno;
+ __entry->streams = atomic_read(&pag->pagf_fstrms);
+ __entry->free = pag->pagf_freeblks;
),
TP_printk("dev %d:%d ino 0x%llx agno 0x%x streams %d free %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 76e44e102780..62d368bcd9ec 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -65,7 +65,7 @@ struct cpc_desc {
int write_cmd_status;
int write_cmd_id;
/* Lock used for RMW operations in cpc_write() */
- spinlock_t rmw_lock;
+ raw_spinlock_t rmw_lock;
struct cpc_register_resource cpc_regs[MAX_CPC_REG_ENT];
struct acpi_psd_package domain_info;
struct kobject kobj;
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index e6f6074eadbf..a17e97e634a6 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -465,4 +465,6 @@ extern int acpi_processor_ffh_lpi_probe(unsigned int cpu);
extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi);
#endif
+void acpi_processor_init_invariance_cppc(void);
+
#endif
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index e7cc17ee4934..afdd46ef04f7 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -120,4 +120,8 @@ drm_kunit_helper_create_crtc(struct kunit *test,
const struct drm_crtc_funcs *funcs,
const struct drm_crtc_helper_funcs *helper_funcs);
+struct drm_display_mode *
+drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev,
+ u8 video_code);
+
#endif // DRM_KUNIT_HELPERS_H_
diff --git a/include/linux/alloc_tag.h b/include/linux/alloc_tag.h
index 1f0a9ff23a2c..941deffc590d 100644
--- a/include/linux/alloc_tag.h
+++ b/include/linux/alloc_tag.h
@@ -135,18 +135,21 @@ static inline void alloc_tag_sub_check(union codetag_ref *ref) {}
#endif
/* Caller should verify both ref and tag to be valid */
-static inline void __alloc_tag_ref_set(union codetag_ref *ref, struct alloc_tag *tag)
+static inline bool __alloc_tag_ref_set(union codetag_ref *ref, struct alloc_tag *tag)
{
alloc_tag_add_check(ref, tag);
if (!ref || !tag)
- return;
+ return false;
ref->ct = &tag->ct;
+ return true;
}
-static inline void alloc_tag_ref_set(union codetag_ref *ref, struct alloc_tag *tag)
+static inline bool alloc_tag_ref_set(union codetag_ref *ref, struct alloc_tag *tag)
{
- __alloc_tag_ref_set(ref, tag);
+ if (unlikely(!__alloc_tag_ref_set(ref, tag)))
+ return false;
+
/*
* We need in increment the call counter every time we have a new
* allocation or when we split a large allocation into smaller ones.
@@ -154,12 +157,13 @@ static inline void alloc_tag_ref_set(union codetag_ref *ref, struct alloc_tag *t
* counter because when we free each part the counter will be decremented.
*/
this_cpu_inc(tag->counters->calls);
+ return true;
}
static inline void alloc_tag_add(union codetag_ref *ref, struct alloc_tag *tag, size_t bytes)
{
- alloc_tag_ref_set(ref, tag);
- this_cpu_add(tag->counters->bytes, bytes);
+ if (likely(alloc_tag_ref_set(ref, tag)))
+ this_cpu_add(tag->counters->bytes, bytes);
}
static inline void alloc_tag_sub(union codetag_ref *ref, size_t bytes)
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
index b721f360d759..4a952c4885ed 100644
--- a/include/linux/arch_topology.h
+++ b/include/linux/arch_topology.h
@@ -11,10 +11,6 @@
void topology_normalize_cpu_scale(void);
int topology_update_cpu_topology(void);
-#ifdef CONFIG_ACPI_CPPC_LIB
-void topology_init_cpu_capacity_cppc(void);
-#endif
-
struct device_node;
bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index f59099a213d0..67f6fdf2e7cd 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -315,8 +315,6 @@ u32 arm_smccc_get_version(void);
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);
-extern u64 smccc_has_sve_hint;
-
/**
* arm_smccc_get_soc_id_version()
*
@@ -415,15 +413,6 @@ struct arm_smccc_quirk {
};
/**
- * __arm_smccc_sve_check() - Set the SVE hint bit when doing SMC calls
- *
- * Sets the SMCCC hint bit to indicate if there is live state in the SVE
- * registers, this modifies x0 in place and should never be called from C
- * code.
- */
-asmlinkage unsigned long __arm_smccc_sve_check(unsigned long x0);
-
-/**
* __arm_smccc_smc() - make SMC calls
* @a0-a7: arguments passed in registers 0 to 7
* @res: result values from registers 0 to 3
@@ -490,20 +479,6 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
#endif
-/* nVHE hypervisor doesn't have a current thread so needs separate checks */
-#if defined(CONFIG_ARM64_SVE) && !defined(__KVM_NVHE_HYPERVISOR__)
-
-#define SMCCC_SVE_CHECK ALTERNATIVE("nop \n", "bl __arm_smccc_sve_check \n", \
- ARM64_SVE)
-#define smccc_sve_clobbers "x16", "x30", "cc",
-
-#else
-
-#define SMCCC_SVE_CHECK
-#define smccc_sve_clobbers
-
-#endif
-
#define __constraint_read_2 "r" (arg0)
#define __constraint_read_3 __constraint_read_2, "r" (arg1)
#define __constraint_read_4 __constraint_read_3, "r" (arg2)
@@ -574,12 +549,11 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
register unsigned long r3 asm("r3"); \
CONCATENATE(__declare_arg_, \
COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__); \
- asm volatile(SMCCC_SVE_CHECK \
- inst "\n" : \
+ asm volatile(inst "\n" : \
"=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \
: CONCATENATE(__constraint_read_, \
COUNT_ARGS(__VA_ARGS__)) \
- : smccc_sve_clobbers "memory"); \
+ : "memory"); \
if (___res) \
*___res = (typeof(*___res)){r0, r1, r2, r3}; \
} while (0)
@@ -628,7 +602,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
asm ("" : \
: CONCATENATE(__constraint_read_, \
COUNT_ARGS(__VA_ARGS__)) \
- : smccc_sve_clobbers "memory"); \
+ : "memory"); \
if (___res) \
___res->a0 = SMCCC_RET_NOT_SUPPORTED; \
} while (0)
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
deleted file mode 100644
index 76860a461ed2..000000000000
--- a/include/linux/ath9k_platform.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2008 Atheros Communications Inc.
- * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _LINUX_ATH9K_PLATFORM_H
-#define _LINUX_ATH9K_PLATFORM_H
-
-#define ATH9K_PLAT_EEP_MAX_WORDS 2048
-
-struct ath9k_platform_data {
- const char *eeprom_name;
-
- u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
- u8 *macaddr;
-
- int led_pin;
- u32 gpio_mask;
- u32 gpio_val;
-
- u32 bt_active_pin;
- u32 bt_priority_pin;
- u32 wlan_active_pin;
-
- bool endian_check;
- bool is_clk_25mhz;
- bool tx_gain_buffalo;
- bool disable_2ghz;
- bool disable_5ghz;
- bool led_active_high;
-
- int (*get_mac_revision)(void);
- int (*external_reset)(void);
-
- bool use_eeprom;
-};
-
-#endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/include/linux/backing-file.h b/include/linux/backing-file.h
index 4b61b0e57720..2eed0ffb5e8f 100644
--- a/include/linux/backing-file.h
+++ b/include/linux/backing-file.h
@@ -16,7 +16,7 @@ struct backing_file_ctx {
const struct cred *cred;
struct file *user_file;
void (*accessed)(struct file *);
- void (*end_write)(struct file *);
+ void (*end_write)(struct file *, loff_t, ssize_t);
};
struct file *backing_file_open(const struct path *user_path, int flags,
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 19d8ca8ac960..bdadb0bb6cec 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -635,6 +635,7 @@ enum bpf_type_flag {
*/
PTR_UNTRUSTED = BIT(6 + BPF_BASE_TYPE_BITS),
+ /* MEM can be uninitialized. */
MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS),
/* DYNPTR points to memory local to the bpf program. */
@@ -700,6 +701,13 @@ enum bpf_type_flag {
*/
MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS),
+ /* MEM is being written to, often combined with MEM_UNINIT. Non-presence
+ * of MEM_WRITE means that MEM is only being read. MEM_WRITE without the
+ * MEM_UNINIT means that memory needs to be initialized since it is also
+ * read.
+ */
+ MEM_WRITE = BIT(18 + BPF_BASE_TYPE_BITS),
+
__BPF_TYPE_FLAG_MAX,
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
};
@@ -758,10 +766,10 @@ enum bpf_arg_type {
ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
ARG_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID,
- /* pointer to memory does not need to be initialized, helper function must fill
- * all bytes or clear them in error case.
+ /* Pointer to memory does not need to be initialized, since helper function
+ * fills all bytes or clears them in error case.
*/
- ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | ARG_PTR_TO_MEM,
+ ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | MEM_WRITE | ARG_PTR_TO_MEM,
/* Pointer to valid memory of size known at compile time. */
ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
diff --git a/include/linux/bpf_mem_alloc.h b/include/linux/bpf_mem_alloc.h
index aaf004d94322..e45162ef59bb 100644
--- a/include/linux/bpf_mem_alloc.h
+++ b/include/linux/bpf_mem_alloc.h
@@ -33,6 +33,9 @@ int bpf_mem_alloc_percpu_init(struct bpf_mem_alloc *ma, struct obj_cgroup *objcg
int bpf_mem_alloc_percpu_unit_init(struct bpf_mem_alloc *ma, int size);
void bpf_mem_alloc_destroy(struct bpf_mem_alloc *ma);
+/* Check the allocation size for kmalloc equivalent allocator */
+int bpf_mem_alloc_check_size(bool percpu, size_t size);
+
/* kmalloc/kfree equivalent: */
void *bpf_mem_alloc(struct bpf_mem_alloc *ma, size_t size);
void bpf_mem_free(struct bpf_mem_alloc *ma, void *ptr);
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index 9f2a6b83b49e..fa78f49d4a9a 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -146,6 +146,7 @@ BPF_LINK_TYPE(BPF_LINK_TYPE_XDP, xdp)
BPF_LINK_TYPE(BPF_LINK_TYPE_NETFILTER, netfilter)
BPF_LINK_TYPE(BPF_LINK_TYPE_TCX, tcx)
BPF_LINK_TYPE(BPF_LINK_TYPE_NETKIT, netkit)
+BPF_LINK_TYPE(BPF_LINK_TYPE_SOCKMAP, sockmap)
#endif
#ifdef CONFIG_PERF_EVENTS
BPF_LINK_TYPE(BPF_LINK_TYPE_PERF_EVENT, perf)
diff --git a/include/linux/clocksource_ids.h b/include/linux/clocksource_ids.h
index 2bb4d8c2f1b0..c4ef4ae2eded 100644
--- a/include/linux/clocksource_ids.h
+++ b/include/linux/clocksource_ids.h
@@ -6,6 +6,7 @@
enum clocksource_ids {
CSID_GENERIC = 0,
CSID_ARM_ARCH_COUNTER,
+ CSID_S390_TOD,
CSID_X86_TSC_EARLY,
CSID_X86_TSC,
CSID_X86_KVM_CLK,
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index f805adaa316e..cd6f9aae311f 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -80,7 +80,11 @@
#define __noscs __attribute__((__no_sanitize__("shadow-call-stack")))
#endif
+#ifdef __SANITIZE_HWADDRESS__
+#define __no_sanitize_address __attribute__((__no_sanitize__("hwaddress")))
+#else
#define __no_sanitize_address __attribute__((__no_sanitize_address__))
+#endif
#if defined(__SANITIZE_THREAD__)
#define __no_sanitize_thread __attribute__((__no_sanitize_thread__))
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index 1a957ea2f4fe..0c8b9601e603 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -266,6 +266,12 @@ struct ftrace_likely_data {
#define noinline_for_stack noinline
/*
+ * Use noinline_for_tracing for functions that should not be inlined.
+ * For tracing reasons.
+ */
+#define noinline_for_tracing noinline
+
+/*
* Sanitizer helper attributes: Because using __always_inline and
* __no_sanitize_* conflict, provide helper attributes that will either expand
* to __no_sanitize_* in compilation units where instrumentation is enabled
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 0928a6c8ae1e..59444b495d49 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -71,9 +71,63 @@ typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *);
struct dentry *debugfs_lookup(const char *name, struct dentry *parent);
-struct dentry *debugfs_create_file(const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops);
+struct debugfs_short_fops {
+ ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
+ loff_t (*llseek) (struct file *, loff_t, int);
+};
+
+struct dentry *debugfs_create_file_full(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+struct dentry *debugfs_create_file_short(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct debugfs_short_fops *fops);
+
+/**
+ * debugfs_create_file - create a file in the debugfs filesystem
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have.
+ * @parent: a pointer to the parent dentry for this file. This should be a
+ * directory dentry if set. If this parameter is NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+ * on. The inode.i_private pointer will point to this value on
+ * the open() call.
+ * @fops: a pointer to a struct file_operations or struct debugfs_short_fops that
+ * should be used for this file.
+ *
+ * This is the basic "create a file" function for debugfs. It allows for a
+ * wide range of flexibility in creating a file, or a directory (if you want
+ * to create a directory, the debugfs_create_dir() function is
+ * recommended to be used instead.)
+ *
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be
+ * returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned.
+ *
+ * If fops points to a struct debugfs_short_fops, then simple_open() will be
+ * used for the open, and only read/write/llseek are supported and are proxied,
+ * so no module reference or release are needed.
+ *
+ * NOTE: it's expected that most callers should _ignore_ the errors returned
+ * by this function. Other debugfs functions handle the fact that the "dentry"
+ * passed to them could be an error and they don't crash in that case.
+ * Drivers should generally work fine even if debugfs fails to init anyway.
+ */
+#define debugfs_create_file(name, mode, parent, data, fops) \
+ _Generic(fops, \
+ const struct file_operations *: debugfs_create_file_full, \
+ const struct debugfs_short_fops *: debugfs_create_file_short, \
+ struct file_operations *: debugfs_create_file_full, \
+ struct debugfs_short_fops *: debugfs_create_file_short) \
+ (name, mode, parent, data, fops)
+
struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops);
@@ -207,7 +261,7 @@ static inline struct dentry *debugfs_lookup(const char *name,
static inline struct dentry *debugfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
- const struct file_operations *fops)
+ const void *fops)
{
return ERR_PTR(-ENODEV);
}
diff --git a/include/linux/device.h b/include/linux/device.h
index b4bde8d22697..667cb6db9019 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1078,6 +1078,9 @@ int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
int device_for_each_child_reverse(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
+int device_for_each_child_reverse_from(struct device *parent,
+ struct device *from, const void *data,
+ int (*fn)(struct device *, const void *));
struct device *device_find_child(struct device *dev, void *data,
int (*match)(struct device *dev, void *data));
struct device *device_find_child_by_name(struct device *parent,
diff --git a/include/linux/dim.h b/include/linux/dim.h
index 1b581ff25a15..06543fd40fcc 100644
--- a/include/linux/dim.h
+++ b/include/linux/dim.h
@@ -351,7 +351,8 @@ void dim_park_tired(struct dim *dim);
* Takes into consideration counter wrap-around.
* Returned boolean indicates whether curr_stats are reliable.
*/
-bool dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
+bool dim_calc_stats(const struct dim_sample *start,
+ const struct dim_sample *end,
struct dim_stats *curr_stats);
/**
@@ -424,7 +425,7 @@ struct dim_cq_moder net_dim_get_def_tx_moderation(u8 cq_period_mode);
* This is the main logic of the algorithm, where data is processed in order
* to decide on next required action.
*/
-void net_dim(struct dim *dim, struct dim_sample end_sample);
+void net_dim(struct dim *dim, const struct dim_sample *end_sample);
/* RDMA DIM */
diff --git a/include/linux/dpll.h b/include/linux/dpll.h
index 81f7b623d0ba..5e4f9ab1cf75 100644
--- a/include/linux/dpll.h
+++ b/include/linux/dpll.h
@@ -26,6 +26,10 @@ struct dpll_device_ops {
struct netlink_ext_ack *extack);
int (*temp_get)(const struct dpll_device *dpll, void *dpll_priv,
s32 *temp, struct netlink_ext_ack *extack);
+ int (*clock_quality_level_get)(const struct dpll_device *dpll,
+ void *dpll_priv,
+ unsigned long *qls,
+ struct netlink_ext_ack *extack);
};
struct dpll_pin_ops {
diff --git a/include/linux/dynamic_queue_limits.h b/include/linux/dynamic_queue_limits.h
index 281298e77a15..808b1a5102e7 100644
--- a/include/linux/dynamic_queue_limits.h
+++ b/include/linux/dynamic_queue_limits.h
@@ -127,7 +127,7 @@ static inline void dql_queued(struct dql *dql, unsigned int count)
if (WARN_ON_ONCE(count > DQL_MAX_OBJECT))
return;
- dql->last_obj_cnt = count;
+ WRITE_ONCE(dql->last_obj_cnt, count);
/* We want to force a write first, so that cpu do not attempt
* to get cache line containing last_obj_cnt, num_queued, adj_limit
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 12f6dc567598..299280c94d07 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -211,7 +211,7 @@ void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id);
* fields, but they are allowed to overwrite them (will be ignored).
*/
struct ethtool_link_ksettings {
- struct ethtool_link_settings base;
+ struct ethtool_link_settings_hdr base;
struct {
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
@@ -734,6 +734,9 @@ struct kernel_ethtool_ts_info {
* @rxfh_per_ctx_key: device supports setting different RSS key for each
* additional context. Netlink API should report hfunc, key, and input_xfrm
* for every context, not just context 0.
+ * @cap_rss_rxnfc_adds: device supports nonzero ring_cookie in filters with
+ * %FLOW_RSS flag; the queue ID from the filter is added to the value from
+ * the indirection table to determine the delivery queue.
* @rxfh_indir_space: max size of RSS indirection tables, if indirection table
* size as returned by @get_rxfh_indir_size may change during lifetime
* of the device. Leave as 0 if the table size is constant.
@@ -956,6 +959,7 @@ struct ethtool_ops {
u32 cap_rss_ctx_supported:1;
u32 cap_rss_sym_xor_supported:1;
u32 rxfh_per_ctx_key:1;
+ u32 cap_rss_rxnfc_adds:1;
u32 rxfh_indir_space;
u16 rxfh_key_space;
u16 rxfh_priv_size;
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index c13e99cbbf81..4b4bfef6f053 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -160,6 +160,12 @@ extern int get_tree_keyed(struct fs_context *fc,
int setup_bdev_super(struct super_block *sb, int sb_flags,
struct fs_context *fc);
+
+#define GET_TREE_BDEV_QUIET_LOOKUP 0x0001
+int get_tree_bdev_flags(struct fs_context *fc,
+ int (*fill_super)(struct super_block *sb,
+ struct fs_context *fc), unsigned int flags);
+
extern int get_tree_bdev(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc));
diff --git a/include/linux/fsl/netc_global.h b/include/linux/fsl/netc_global.h
new file mode 100644
index 000000000000..fdecca8c90f0
--- /dev/null
+++ b/include/linux/fsl/netc_global.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2024 NXP
+ */
+#ifndef __NETC_GLOBAL_H
+#define __NETC_GLOBAL_H
+
+#include <linux/io.h>
+
+static inline u32 netc_read(void __iomem *reg)
+{
+ return ioread32(reg);
+}
+
+static inline void netc_write(void __iomem *reg, u32 val)
+{
+ iowrite32(val, reg);
+}
+
+#endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index a951de920e20..a0a6d25f883f 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -371,28 +371,6 @@ __meminit void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mas
extern void __free_pages(struct page *page, unsigned int order);
extern void free_pages(unsigned long addr, unsigned int order);
-struct page_frag_cache;
-void page_frag_cache_drain(struct page_frag_cache *nc);
-extern void __page_frag_cache_drain(struct page *page, unsigned int count);
-void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz,
- gfp_t gfp_mask, unsigned int align_mask);
-
-static inline void *page_frag_alloc_align(struct page_frag_cache *nc,
- unsigned int fragsz, gfp_t gfp_mask,
- unsigned int align)
-{
- WARN_ON_ONCE(!is_power_of_2(align));
- return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align);
-}
-
-static inline void *page_frag_alloc(struct page_frag_cache *nc,
- unsigned int fragsz, gfp_t gfp_mask)
-{
- return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u);
-}
-
-extern void page_frag_free(void *addr);
-
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 456bca45ff05..05dedc45505c 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1445,6 +1445,8 @@ struct ieee80211_mgmt {
__le16 status;
__le16 capab;
__le16 timeout;
+ /* followed by BA Extension */
+ u8 variable[];
} __packed addba_resp;
struct{
u8 action_code;
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index d9c690c8c80b..5730ba6b1cfa 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -226,6 +226,10 @@ static __inline__ bool bad_mask(__be32 mask, __be32 addr)
for (ifa = rtnl_dereference((in_dev)->ifa_list); ifa; \
ifa = rtnl_dereference(ifa->ifa_next))
+#define in_dev_for_each_ifa_rtnl_net(net, ifa, in_dev) \
+ for (ifa = rtnl_net_dereference(net, (in_dev)->ifa_list); ifa; \
+ ifa = rtnl_net_dereference(net, ifa->ifa_next))
+
#define in_dev_for_each_ifa_rcu(ifa, in_dev) \
for (ifa = rcu_dereference((in_dev)->ifa_list); ifa; \
ifa = rcu_dereference(ifa->ifa_next))
@@ -252,6 +256,11 @@ static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
return rtnl_dereference(dev->ip_ptr);
}
+static inline struct in_device *__in_dev_get_rtnl_net(const struct net_device *dev)
+{
+ return rtnl_net_dereference(dev_net(dev), dev->ip_ptr);
+}
+
/* called with rcu_read_lock or rtnl held */
static inline bool ip_ignore_linkdown(const struct net_device *dev)
{
diff --git a/include/linux/input.h b/include/linux/input.h
index 89a0be6ee0e2..cd866b020a01 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -339,12 +339,16 @@ struct input_handler {
* @name: name given to the handle by handler that created it
* @dev: input device the handle is attached to
* @handler: handler that works with the device through this handle
+ * @handle_events: event sequence handler. It is set up by the input core
+ * according to event handling method specified in the @handler. See
+ * input_handle_setup_event_handler().
+ * This method is being called by the input core with interrupts disabled
+ * and dev->event_lock spinlock held and so it may not sleep.
* @d_node: used to put the handle on device's list of attached handles
* @h_node: used to put the handle on handler's list of handles from which
* it gets events
*/
struct input_handle {
-
void *private;
int open;
@@ -353,6 +357,10 @@ struct input_handle {
struct input_dev *dev;
struct input_handler *handler;
+ unsigned int (*handle_events)(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count);
+
struct list_head d_node;
struct list_head h_node;
};
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index d0420e962ffd..f61407e3b121 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -270,6 +270,25 @@ static inline loff_t iomap_last_written_block(struct inode *inode, loff_t pos,
return round_up(pos + written, i_blocksize(inode));
}
+/*
+ * Check if the range needs to be unshared for a FALLOC_FL_UNSHARE_RANGE
+ * operation.
+ *
+ * Don't bother with blocks that are not shared to start with; or mappings that
+ * cannot be shared, such as inline data, delalloc reservations, holes or
+ * unwritten extents.
+ *
+ * Note that we use srcmap directly instead of iomap_iter_srcmap as unsharing
+ * requires providing a separate source map, and the presence of one is a good
+ * indicator that unsharing is needed, unlike IOMAP_F_SHARED which can be set
+ * for any data that goes into the COW fork for XFS.
+ */
+static inline bool iomap_want_unshare_iter(const struct iomap_iter *iter)
+{
+ return (iter->iomap.flags & IOMAP_F_SHARED) &&
+ iter->srcmap.type == IOMAP_MAPPED;
+}
+
ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
const struct iomap_ops *ops, void *private);
int iomap_read_folio(struct folio *folio, const struct iomap_ops *ops);
diff --git a/include/linux/ksm.h b/include/linux/ksm.h
index 11690dacd986..ec9c05044d4f 100644
--- a/include/linux/ksm.h
+++ b/include/linux/ksm.h
@@ -54,12 +54,11 @@ static inline long mm_ksm_zero_pages(struct mm_struct *mm)
return atomic_long_read(&mm->ksm_zero_pages);
}
-static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
+static inline void ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
{
+ /* Adding mm to ksm is best effort on fork. */
if (test_bit(MMF_VM_MERGEABLE, &oldmm->flags))
- return __ksm_enter(mm);
-
- return 0;
+ __ksm_enter(mm);
}
static inline int ksm_execve(struct mm_struct *mm)
@@ -107,9 +106,8 @@ static inline int ksm_disable(struct mm_struct *mm)
return 0;
}
-static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
+static inline void ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
{
- return 0;
}
static inline int ksm_execve(struct mm_struct *mm)
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index efeca5bd7600..3c3deac57894 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -165,31 +165,12 @@ extern int mdio_set_flag(const struct mdio_if_info *mdio,
bool sense);
extern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds);
extern int mdio45_nway_restart(const struct mdio_if_info *mdio);
-extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
- struct ethtool_cmd *ecmd,
- u32 npage_adv, u32 npage_lpa);
extern void
mdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio,
struct ethtool_link_ksettings *cmd,
u32 npage_adv, u32 npage_lpa);
/**
- * mdio45_ethtool_gset - get settings for ETHTOOL_GSET
- * @mdio: MDIO interface
- * @ecmd: Ethtool request structure
- *
- * Since the CSRs for auto-negotiation using next pages are not fully
- * standardised, this function does not attempt to decode them. Use
- * mdio45_ethtool_gset_npage() to specify advertisement bits from next
- * pages.
- */
-static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
- struct ethtool_cmd *ecmd)
-{
- mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0);
-}
-
-/**
* mdio45_ethtool_ksettings_get - get settings for ETHTOOL_GLINKSETTINGS
* @mdio: MDIO interface
* @cmd: Ethtool request structure
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 34d2da05f2f1..e1b41554a5fb 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -1760,8 +1760,9 @@ static inline int memcg_kmem_id(struct mem_cgroup *memcg)
struct mem_cgroup *mem_cgroup_from_slab_obj(void *p);
-static inline void count_objcg_event(struct obj_cgroup *objcg,
- enum vm_event_item idx)
+static inline void count_objcg_events(struct obj_cgroup *objcg,
+ enum vm_event_item idx,
+ unsigned long count)
{
struct mem_cgroup *memcg;
@@ -1770,7 +1771,7 @@ static inline void count_objcg_event(struct obj_cgroup *objcg,
rcu_read_lock();
memcg = obj_cgroup_memcg(objcg);
- count_memcg_events(memcg, idx, 1);
+ count_memcg_events(memcg, idx, count);
rcu_read_unlock();
}
@@ -1825,8 +1826,9 @@ static inline struct mem_cgroup *mem_cgroup_from_slab_obj(void *p)
return NULL;
}
-static inline void count_objcg_event(struct obj_cgroup *objcg,
- enum vm_event_item idx)
+static inline void count_objcg_events(struct obj_cgroup *objcg,
+ enum vm_event_item idx,
+ unsigned long count)
{
}
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6e3bdf8e38bc..92314ef2d978 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -521,9 +521,6 @@ static_assert(sizeof(struct ptdesc) <= sizeof(struct page));
*/
#define STRUCT_PAGE_MAX_SHIFT (order_base_2(sizeof(struct page)))
-#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK)
-#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE)
-
/*
* page_private can be used on tail pages. However, PagePrivate is only
* checked by the VM on the head page. So page_private on the tail pages
@@ -542,21 +539,6 @@ static inline void *folio_get_private(struct folio *folio)
return folio->private;
}
-struct page_frag_cache {
- void * va;
-#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
- __u16 offset;
- __u16 size;
-#else
- __u32 offset;
-#endif
- /* we maintain a pagecount bias, so that we dont dirty cache line
- * containing page->_refcount every time we allocate a fragment.
- */
- unsigned int pagecnt_bias;
- bool pfmemalloc;
-};
-
typedef unsigned long vm_flags_t;
/*
diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h
index bff5706b76e1..a82aa80c0ba4 100644
--- a/include/linux/mm_types_task.h
+++ b/include/linux/mm_types_task.h
@@ -8,6 +8,7 @@
* (These are defined separately to decouple sched.h from mm_types.h as much as possible.)
*/
+#include <linux/align.h>
#include <linux/types.h>
#include <asm/page.h>
@@ -43,6 +44,26 @@ struct page_frag {
#endif
};
+#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK)
+#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE)
+struct page_frag_cache {
+ /* encoded_page consists of the virtual address, pfmemalloc bit and
+ * order of a page.
+ */
+ unsigned long encoded_page;
+
+ /* we maintain a pagecount bias, so that we dont dirty cache line
+ * containing page->_refcount every time we allocate a fragment.
+ */
+#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) && (BITS_PER_LONG <= 32)
+ __u16 offset;
+ __u16 pagecnt_bias;
+#else
+ __u32 offset;
+ __u32 pagecnt_bias;
+#endif
+};
+
/* Track pages that require TLB flushes */
struct tlbflush_unmap_batch {
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
diff --git a/include/linux/mman.h b/include/linux/mman.h
index bcb201ab7a41..a842783ffa62 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MMAN_H
#define _LINUX_MMAN_H
+#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/percpu_counter.h>
@@ -94,7 +95,7 @@ static inline void vm_unacct_memory(long pages)
#endif
#ifndef arch_calc_vm_flag_bits
-#define arch_calc_vm_flag_bits(flags) 0
+#define arch_calc_vm_flag_bits(file, flags) 0
#endif
#ifndef arch_validate_prot
@@ -151,13 +152,13 @@ calc_vm_prot_bits(unsigned long prot, unsigned long pkey)
* Combine the mmap "flags" argument into "vm_flags" used internally.
*/
static inline unsigned long
-calc_vm_flag_bits(unsigned long flags)
+calc_vm_flag_bits(struct file *file, unsigned long flags)
{
return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) |
_calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ) |
_calc_vm_trans(flags, MAP_SYNC, VM_SYNC ) |
_calc_vm_trans(flags, MAP_STACK, VM_NOHUGEPAGE) |
- arch_calc_vm_flag_bits(flags);
+ arch_calc_vm_flag_bits(file, flags);
}
unsigned long vm_commit_limit(void);
@@ -188,16 +189,31 @@ static inline bool arch_memory_deny_write_exec_supported(void)
*
* d) mmap(PROT_READ | PROT_EXEC)
* mmap(PROT_READ | PROT_EXEC | PROT_BTI)
+ *
+ * This is only applicable if the user has set the Memory-Deny-Write-Execute
+ * (MDWE) protection mask for the current process.
+ *
+ * @old specifies the VMA flags the VMA originally possessed, and @new the ones
+ * we propose to set.
+ *
+ * Return: false if proposed change is OK, true if not ok and should be denied.
*/
-static inline bool map_deny_write_exec(struct vm_area_struct *vma, unsigned long vm_flags)
+static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
{
+ /* If MDWE is disabled, we have nothing to deny. */
if (!test_bit(MMF_HAS_MDWE, &current->mm->flags))
return false;
- if ((vm_flags & VM_EXEC) && (vm_flags & VM_WRITE))
+ /* If the new VMA is not executable, we have nothing to deny. */
+ if (!(new & VM_EXEC))
+ return false;
+
+ /* Under MDWE we do not accept newly writably executable VMAs... */
+ if (new & VM_WRITE)
return true;
- if (!(vma->vm_flags & VM_EXEC) && (vm_flags & VM_EXEC))
+ /* ...nor previously non-executable VMAs becoming executable. */
+ if (!(old & VM_EXEC))
return true;
return false;
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 17506e4a2835..80bc5640bb60 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -458,9 +458,7 @@ struct lru_gen_folio {
enum {
MM_LEAF_TOTAL, /* total leaf entries */
- MM_LEAF_OLD, /* old leaf entries */
MM_LEAF_YOUNG, /* young leaf entries */
- MM_NONLEAF_TOTAL, /* total non-leaf entries */
MM_NONLEAF_FOUND, /* non-leaf entries found in Bloom filters */
MM_NONLEAF_ADDED, /* non-leaf entries added to Bloom filters */
NR_MM_STATS
@@ -557,7 +555,7 @@ struct lru_gen_memcg {
void lru_gen_init_pgdat(struct pglist_data *pgdat);
void lru_gen_init_lruvec(struct lruvec *lruvec);
-void lru_gen_look_around(struct page_vma_mapped_walk *pvmw);
+bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw);
void lru_gen_init_memcg(struct mem_cgroup *memcg);
void lru_gen_exit_memcg(struct mem_cgroup *memcg);
@@ -576,8 +574,9 @@ static inline void lru_gen_init_lruvec(struct lruvec *lruvec)
{
}
-static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
+static inline bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
{
+ return false;
}
static inline void lru_gen_init_memcg(struct mem_cgroup *memcg)
@@ -824,6 +823,7 @@ struct zone {
unsigned long watermark_boost;
unsigned long nr_reserved_highatomic;
+ unsigned long nr_free_highatomic;
/*
* We don't know if the memory that we're going to allocate will be
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 389f92e4d980..ecc686409161 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -52,6 +52,7 @@
#include <net/net_trackers.h>
#include <net/net_debug.h>
#include <net/dropreason-core.h>
+#include <net/neighbour_tables.h>
struct netpoll_info;
struct device;
@@ -347,6 +348,7 @@ struct gro_list {
*/
struct napi_config {
u64 gro_flush_timeout;
+ u64 irq_suspend_timeout;
u32 defer_hard_irqs;
unsigned int napi_id;
};
@@ -383,6 +385,7 @@ struct napi_struct {
struct hrtimer timer;
struct task_struct *thread;
unsigned long gro_flush_timeout;
+ unsigned long irq_suspend_timeout;
u32 defer_hard_irqs;
/* control-path-only fields follow */
struct list_head dev_list;
@@ -1245,12 +1248,17 @@ struct netdev_net_notifier {
* int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[],
* struct net_device *dev,
* const unsigned char *addr, u16 vid, u16 flags,
- * struct netlink_ext_ack *extack);
+ * bool *notified, struct netlink_ext_ack *extack);
* Adds an FDB entry to dev for addr.
+ * Callee shall set *notified to true if it sent any appropriate
+ * notification(s). Otherwise core will send a generic one.
* int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[],
* struct net_device *dev,
- * const unsigned char *addr, u16 vid)
+ * const unsigned char *addr, u16 vid
+ * bool *notified, struct netlink_ext_ack *extack);
* Deletes the FDB entry from dev corresponding to addr.
+ * Callee shall set *notified to true if it sent any appropriate
+ * notification(s). Otherwise core will send a generic one.
* int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh, struct net_device *dev,
* struct netlink_ext_ack *extack);
* int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
@@ -1522,12 +1530,15 @@ struct net_device_ops {
const unsigned char *addr,
u16 vid,
u16 flags,
+ bool *notified,
struct netlink_ext_ack *extack);
int (*ndo_fdb_del)(struct ndmsg *ndm,
struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr,
- u16 vid, struct netlink_ext_ack *extack);
+ u16 vid,
+ bool *notified,
+ struct netlink_ext_ack *extack);
int (*ndo_fdb_del_bulk)(struct nlmsghdr *nlh,
struct net_device *dev,
struct netlink_ext_ack *extack);
@@ -1793,7 +1804,6 @@ enum netdev_reg_state {
* @wireless_handlers: List of functions to handle Wireless Extensions,
* instead of ioctl,
* see <net/iw_handler.h> for details.
- * @wireless_data: Instance data managed by the core of wireless extensions
*
* @netdev_ops: Includes several pointers to callbacks,
* if one wants to override the ndo_*() functions
@@ -2033,6 +2043,9 @@ enum netdev_reg_state {
* @napi_defer_hard_irqs: If not zero, provides a counter that would
* allow to avoid NIC hard IRQ, on busy queues.
*
+ * @neighbours: List heads pointing to this device's neighbours'
+ * dev_list, one per address-family.
+ *
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
*/
@@ -2172,7 +2185,6 @@ struct net_device {
#ifdef CONFIG_WIRELESS_EXT
const struct iw_handler_def *wireless_handlers;
- struct iw_public_data *wireless_data;
#endif
const struct ethtool_ops *ethtool_ops;
#ifdef CONFIG_NET_L3_MASTER_DEV
@@ -2442,6 +2454,9 @@ struct net_device {
*/
struct net_shaper_hierarchy *net_shaper_hierarchy;
#endif
+
+ struct hlist_head neighbours[NEIGH_NR_TABLES];
+
u8 priv[] ____cacheline_aligned
__counted_by(priv_len);
} ____cacheline_aligned;
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index cd4e28db0cbd..77635b885c18 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -32,6 +32,7 @@ struct netpoll {
bool ipv6;
u16 local_port, remote_port;
u8 remote_mac[ETH_ALEN];
+ struct sk_buff_head skb_pool;
};
struct netpoll_info {
diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h
index b0dd9b1eef4f..3982fea79919 100644
--- a/include/linux/nfslocalio.h
+++ b/include/linux/nfslocalio.h
@@ -32,7 +32,8 @@ typedef struct {
struct auth_domain *dom; /* auth_domain for localio */
} nfs_uuid_t;
-void nfs_uuid_begin(nfs_uuid_t *);
+void nfs_uuid_init(nfs_uuid_t *);
+bool nfs_uuid_begin(nfs_uuid_t *);
void nfs_uuid_end(nfs_uuid_t *);
void nfs_uuid_is_local(const uuid_t *, struct list_head *,
struct net *, struct auth_domain *, struct module *);
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 1b3a76710487..cc839e4365c1 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -975,12 +975,16 @@ static __always_inline bool folio_test_##fname(const struct folio *folio) \
} \
static __always_inline void __folio_set_##fname(struct folio *folio) \
{ \
+ if (folio_test_##fname(folio)) \
+ return; \
VM_BUG_ON_FOLIO(data_race(folio->page.page_type) != UINT_MAX, \
folio); \
folio->page.page_type = (unsigned int)PGTY_##lname << 24; \
} \
static __always_inline void __folio_clear_##fname(struct folio *folio) \
{ \
+ if (folio->page.page_type == UINT_MAX) \
+ return; \
VM_BUG_ON_FOLIO(!folio_test_##fname(folio), folio); \
folio->page.page_type = UINT_MAX; \
}
@@ -993,11 +997,15 @@ static __always_inline int Page##uname(const struct page *page) \
} \
static __always_inline void __SetPage##uname(struct page *page) \
{ \
+ if (Page##uname(page)) \
+ return; \
VM_BUG_ON_PAGE(data_race(page->page_type) != UINT_MAX, page); \
page->page_type = (unsigned int)PGTY_##lname << 24; \
} \
static __always_inline void __ClearPage##uname(struct page *page) \
{ \
+ if (page->page_type == UINT_MAX) \
+ return; \
VM_BUG_ON_PAGE(!Page##uname(page), page); \
page->page_type = UINT_MAX; \
}
diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h
new file mode 100644
index 000000000000..41a91df82631
--- /dev/null
+++ b/include/linux/page_frag_cache.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_PAGE_FRAG_CACHE_H
+#define _LINUX_PAGE_FRAG_CACHE_H
+
+#include <linux/bits.h>
+#include <linux/log2.h>
+#include <linux/mm_types_task.h>
+#include <linux/types.h>
+
+#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
+/* Use a full byte here to enable assembler optimization as the shift
+ * operation is usually expecting a byte.
+ */
+#define PAGE_FRAG_CACHE_ORDER_MASK GENMASK(7, 0)
+#else
+/* Compiler should be able to figure out we don't read things as any value
+ * ANDed with 0 is 0.
+ */
+#define PAGE_FRAG_CACHE_ORDER_MASK 0
+#endif
+
+#define PAGE_FRAG_CACHE_PFMEMALLOC_BIT (PAGE_FRAG_CACHE_ORDER_MASK + 1)
+
+static inline bool encoded_page_decode_pfmemalloc(unsigned long encoded_page)
+{
+ return !!(encoded_page & PAGE_FRAG_CACHE_PFMEMALLOC_BIT);
+}
+
+static inline void page_frag_cache_init(struct page_frag_cache *nc)
+{
+ nc->encoded_page = 0;
+}
+
+static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc)
+{
+ return encoded_page_decode_pfmemalloc(nc->encoded_page);
+}
+
+void page_frag_cache_drain(struct page_frag_cache *nc);
+void __page_frag_cache_drain(struct page *page, unsigned int count);
+void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz,
+ gfp_t gfp_mask, unsigned int align_mask);
+
+static inline void *page_frag_alloc_align(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask,
+ unsigned int align)
+{
+ WARN_ON_ONCE(!is_power_of_2(align));
+ return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align);
+}
+
+static inline void *page_frag_alloc(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask)
+{
+ return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u);
+}
+
+void page_frag_free(void *addr);
+
+#endif
diff --git a/include/linux/phy.h b/include/linux/phy.h
index bf0eb4e5d35c..b8346db42727 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -721,16 +721,15 @@ struct phy_device {
/* used for eee validation and configuration*/
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_eee);
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising_eee);
+ /* Energy efficient ethernet modes which should be prohibited */
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(eee_broken_modes);
bool eee_enabled;
+ bool enable_tx_lpi;
+ struct eee_config eee_cfg;
/* Host supported PHY interface types. Should be ignored if empty. */
DECLARE_PHY_INTERFACE_MASK(host_interfaces);
- /* Energy efficient ethernet modes which should be prohibited */
- u32 eee_broken_modes;
- bool enable_tx_lpi;
- struct eee_config eee_cfg;
-
#ifdef CONFIG_LED_TRIGGER_PHY
struct phy_led_trigger *phy_led_triggers;
unsigned int phy_num_led_triggers;
@@ -1265,6 +1264,16 @@ void of_set_phy_timing_role(struct phy_device *phydev);
int phy_speed_down_core(struct phy_device *phydev);
/**
+ * phy_set_eee_broken - Mark an EEE mode as broken so that it isn't advertised.
+ * @phydev: The phy_device struct
+ * @link_mode: The broken EEE mode
+ */
+static inline void phy_set_eee_broken(struct phy_device *phydev, u32 link_mode)
+{
+ linkmode_set_bit(link_mode, phydev->eee_broken_modes);
+}
+
+/**
* phy_is_started - Convenience function to check whether PHY is started
* @phydev: The phy_device struct
*/
@@ -1885,7 +1894,6 @@ int genphy_read_abilities(struct phy_device *phydev);
int genphy_setup_forced(struct phy_device *phydev);
int genphy_restart_aneg(struct phy_device *phydev);
int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart);
-int genphy_config_eee_advert(struct phy_device *phydev);
int __genphy_config_aneg(struct phy_device *phydev, bool changed);
int genphy_aneg_done(struct phy_device *phydev);
int genphy_update_link(struct phy_device *phydev);
@@ -1953,7 +1961,6 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev,
struct ethtool_keee *data);
int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_keee *data);
-int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv);
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev);
int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv);
diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h
index 2ee1a679e592..0e0e8fe6975f 100644
--- a/include/linux/platform_data/microchip-ksz.h
+++ b/include/linux/platform_data/microchip-ksz.h
@@ -42,6 +42,7 @@ enum ksz_chip_id {
LAN9372_CHIP_ID = 0x00937200,
LAN9373_CHIP_ID = 0x00937300,
LAN9374_CHIP_ID = 0x00937400,
+ LAN9646_CHIP_ID = 0x00964600,
};
struct ksz_platform_data {
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 8468a4ce8510..14b88f551920 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -101,6 +101,7 @@ void __rtnl_net_lock(struct net *net);
void __rtnl_net_unlock(struct net *net);
void rtnl_net_lock(struct net *net);
void rtnl_net_unlock(struct net *net);
+int rtnl_net_trylock(struct net *net);
int rtnl_net_lock_cmp_fn(const struct lockdep_map *a, const struct lockdep_map *b);
bool rtnl_net_is_locked(struct net *net);
@@ -132,26 +133,22 @@ static inline void rtnl_net_unlock(struct net *net)
rtnl_unlock();
}
-static inline void ASSERT_RTNL_NET(struct net *net)
-{
- ASSERT_RTNL();
-}
-
-static inline void *rcu_dereference_rtnl_net(struct net *net, void *p)
+static inline int rtnl_net_trylock(struct net *net)
{
- return rcu_dereference_rtnl(p);
+ return rtnl_trylock();
}
-static inline void *rtnl_net_dereference(struct net *net, void *p)
+static inline void ASSERT_RTNL_NET(struct net *net)
{
- return rtnl_dereference(p);
+ ASSERT_RTNL();
}
-static inline void *rcu_replace_pointer_rtnl_net(struct net *net,
- void *rp, void *p)
-{
- return rcu_replace_pointer_rtnl(rp, p);
-}
+#define rcu_dereference_rtnl_net(net, p) \
+ rcu_dereference_rtnl(p)
+#define rtnl_net_dereference(net, p) \
+ rtnl_dereference(p)
+#define rcu_replace_pointer_rtnl_net(net, rp, p) \
+ rcu_replace_pointer_rtnl(rp, p)
#endif
static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 48f1e0fa2a13..58009fa66102 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -31,6 +31,7 @@
#include <linux/in6.h>
#include <linux/if_packet.h>
#include <linux/llist.h>
+#include <linux/page_frag_cache.h>
#include <net/flow.h>
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <linux/netfilter/nf_conntrack_common.h>
@@ -2681,6 +2682,12 @@ static inline void skb_assert_len(struct sk_buff *skb)
#endif /* CONFIG_DEBUG_NET */
}
+#if defined(CONFIG_FAIL_SKB_REALLOC)
+void skb_might_realloc(struct sk_buff *skb);
+#else
+static inline void skb_might_realloc(struct sk_buff *skb) {}
+#endif
+
/*
* Add data to an sk_buff
*/
@@ -2781,6 +2788,7 @@ static inline enum skb_drop_reason
pskb_may_pull_reason(struct sk_buff *skb, unsigned int len)
{
DEBUG_NET_WARN_ON_ONCE(len > INT_MAX);
+ skb_might_realloc(skb);
if (likely(len <= skb_headlen(skb)))
return SKB_NOT_DROPPED_YET;
@@ -2909,9 +2917,19 @@ static inline void skb_reset_inner_headers(struct sk_buff *skb)
skb->inner_transport_header = skb->transport_header;
}
+static inline int skb_mac_header_was_set(const struct sk_buff *skb)
+{
+ return skb->mac_header != (typeof(skb->mac_header))~0U;
+}
+
static inline void skb_reset_mac_len(struct sk_buff *skb)
{
- skb->mac_len = skb->network_header - skb->mac_header;
+ if (!skb_mac_header_was_set(skb)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ skb->mac_len = 0;
+ } else {
+ skb->mac_len = skb->network_header - skb->mac_header;
+ }
}
static inline unsigned char *skb_inner_transport_header(const struct sk_buff
@@ -2927,7 +2945,10 @@ static inline int skb_inner_transport_offset(const struct sk_buff *skb)
static inline void skb_reset_inner_transport_header(struct sk_buff *skb)
{
- skb->inner_transport_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->inner_transport_header))offset);
+ skb->inner_transport_header = offset;
}
static inline void skb_set_inner_transport_header(struct sk_buff *skb,
@@ -2944,7 +2965,10 @@ static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb)
static inline void skb_reset_inner_network_header(struct sk_buff *skb)
{
- skb->inner_network_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->inner_network_header))offset);
+ skb->inner_network_header = offset;
}
static inline void skb_set_inner_network_header(struct sk_buff *skb,
@@ -2966,7 +2990,10 @@ static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb)
static inline void skb_reset_inner_mac_header(struct sk_buff *skb)
{
- skb->inner_mac_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->inner_mac_header))offset);
+ skb->inner_mac_header = offset;
}
static inline void skb_set_inner_mac_header(struct sk_buff *skb,
@@ -2988,7 +3015,10 @@ static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
static inline void skb_reset_transport_header(struct sk_buff *skb)
{
- skb->transport_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->transport_header))offset);
+ skb->transport_header = offset;
}
static inline void skb_set_transport_header(struct sk_buff *skb,
@@ -3005,7 +3035,10 @@ static inline unsigned char *skb_network_header(const struct sk_buff *skb)
static inline void skb_reset_network_header(struct sk_buff *skb)
{
- skb->network_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->network_header))offset);
+ skb->network_header = offset;
}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
@@ -3014,11 +3047,6 @@ static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
skb->network_header += offset;
}
-static inline int skb_mac_header_was_set(const struct sk_buff *skb)
-{
- return skb->mac_header != (typeof(skb->mac_header))~0U;
-}
-
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
{
DEBUG_NET_WARN_ON_ONCE(!skb_mac_header_was_set(skb));
@@ -3043,7 +3071,10 @@ static inline void skb_unset_mac_header(struct sk_buff *skb)
static inline void skb_reset_mac_header(struct sk_buff *skb)
{
- skb->mac_header = skb->data - skb->head;
+ long offset = skb->data - skb->head;
+
+ DEBUG_NET_WARN_ON_ONCE(offset != (typeof(skb->mac_header))offset);
+ skb->mac_header = offset;
}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
@@ -3216,6 +3247,7 @@ static inline int __pskb_trim(struct sk_buff *skb, unsigned int len)
static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
{
+ skb_might_realloc(skb);
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
@@ -3970,6 +4002,7 @@ int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len);
static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
{
+ skb_might_realloc(skb);
if (likely(len >= skb->len))
return 0;
return pskb_trim_rcsum_slow(skb, len);
diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h
index 9e9f528b1370..2f20281d4ad4 100644
--- a/include/linux/soc/qcom/llcc-qcom.h
+++ b/include/linux/soc/qcom/llcc-qcom.h
@@ -125,6 +125,7 @@ struct llcc_edac_reg_offset {
* @num_banks: Number of llcc banks
* @bitmap: Bit map to track the active slice ids
* @ecc_irq: interrupt for llcc cache error detection and reporting
+ * @ecc_irq_configured: 'True' if firmware has already configured the irq propagation
* @version: Indicates the LLCC version
*/
struct llcc_drv_data {
@@ -139,6 +140,7 @@ struct llcc_drv_data {
u32 num_banks;
unsigned long *bitmap;
int ecc_irq;
+ bool ecc_irq_configured;
u32 version;
};
diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h
index fc5a206c4043..195debe2b1db 100644
--- a/include/linux/sockptr.h
+++ b/include/linux/sockptr.h
@@ -77,7 +77,9 @@ static inline int copy_safe_from_sockptr(void *dst, size_t ksize,
{
if (optlen < ksize)
return -EINVAL;
- return copy_from_sockptr(dst, optval, ksize);
+ if (copy_from_sockptr(dst, optval, ksize))
+ return -EFAULT;
+ return 0;
}
static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
diff --git a/include/linux/swap.h b/include/linux/swap.h
index ca533b478c21..f3e0ac20c2e8 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -335,6 +335,7 @@ struct swap_info_struct {
* list.
*/
struct work_struct discard_work; /* discard worker */
+ struct work_struct reclaim_work; /* reclaim worker */
struct list_head discard_clusters; /* discard clusters list */
struct plist_node avail_lists[]; /*
* entries in swap_avail_heads, one
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 6a5e08b937b3..f88daaa76d83 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -200,7 +200,6 @@ struct tcp_sock {
/* TX read-mostly hotpath cache lines */
__cacheline_group_begin(tcp_sock_read_tx);
- /* timestamp of last sent data packet (for restart window) */
u32 max_window; /* Maximal window ever seen from peer */
u32 rcv_ssthresh; /* Current window clamp */
u32 reordering; /* Packet reordering metric. */
@@ -263,7 +262,7 @@ struct tcp_sock {
u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */
u32 write_seq; /* Tail(+1) of data held in tcp send buffer */
u32 pushed_seq; /* Last pushed seq, required to talk to windows */
- u32 lsndtime;
+ u32 lsndtime; /* timestamp of last sent data packet (for restart window) */
u32 mdev_us; /* medium deviation */
u32 rtt_seq; /* sequence number to update rttvar */
u64 tcp_wstamp_ns; /* departure time for next sent data packet */
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 72744638c5b0..99c9c5a7252a 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -251,12 +251,19 @@ static inline void tick_dep_set_task(struct task_struct *tsk,
if (tick_nohz_full_enabled())
tick_nohz_dep_set_task(tsk, bit);
}
+
static inline void tick_dep_clear_task(struct task_struct *tsk,
enum tick_dep_bits bit)
{
if (tick_nohz_full_enabled())
tick_nohz_dep_clear_task(tsk, bit);
}
+
+static inline void tick_dep_init_task(struct task_struct *tsk)
+{
+ atomic_set(&tsk->tick_dep_mask, 0);
+}
+
static inline void tick_dep_set_signal(struct task_struct *tsk,
enum tick_dep_bits bit)
{
@@ -290,6 +297,7 @@ static inline void tick_dep_set_task(struct task_struct *tsk,
enum tick_dep_bits bit) { }
static inline void tick_dep_clear_task(struct task_struct *tsk,
enum tick_dep_bits bit) { }
+static inline void tick_dep_init_task(struct task_struct *tsk) { }
static inline void tick_dep_set_signal(struct task_struct *tsk,
enum tick_dep_bits bit) { }
static inline void tick_dep_clear_signal(struct signal_struct *signal,
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 587b96b4418e..20a40ade8030 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -421,6 +421,7 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
+void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle);
/*
* Check if TPM device is in the firmware upgrade mode.
@@ -505,6 +506,8 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
u8 attributes, u8 *passphrase,
int passphraselen);
+void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
+ u8 attributes, u8 *passphrase, int passphraselen);
static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
struct tpm_buf *buf,
u8 attributes,
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 39c7cf82b0c2..43844510d5d0 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -38,6 +38,7 @@
#else
#define can_do_masked_user_access() 0
#define masked_user_access_begin(src) NULL
+ #define mask_user_address(src) (src)
#endif
/*
@@ -159,19 +160,27 @@ _inline_copy_from_user(void *to, const void __user *from, unsigned long n)
{
unsigned long res = n;
might_fault();
- if (!should_fail_usercopy() && likely(access_ok(from, n))) {
+ if (should_fail_usercopy())
+ goto fail;
+ if (can_do_masked_user_access())
+ from = mask_user_address(from);
+ else {
+ if (!access_ok(from, n))
+ goto fail;
/*
* Ensure that bad access_ok() speculation will not
* lead to nasty side effects *after* the copy is
* finished:
*/
barrier_nospec();
- instrument_copy_from_user_before(to, from, n);
- res = raw_copy_from_user(to, from, n);
- instrument_copy_from_user_after(to, from, n, res);
}
- if (unlikely(res))
- memset(to + (n - res), 0, res);
+ instrument_copy_from_user_before(to, from, n);
+ res = raw_copy_from_user(to, from, n);
+ instrument_copy_from_user_after(to, from, n, res);
+ if (likely(!res))
+ return 0;
+fail:
+ memset(to + (n - res), 0, res);
return res;
}
extern __must_check unsigned long
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 3625096d5f85..7183e5aca282 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -141,7 +141,8 @@ static inline long get_rlimit_value(struct ucounts *ucounts, enum rlimit_type ty
long inc_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v);
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum rlimit_type type, long v);
-long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type);
+long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type,
+ bool override_rlimit);
void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum rlimit_type type);
bool is_rlimit_overlimit(struct ucounts *ucounts, enum rlimit_type type, unsigned long max);
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 9fc6ce15c499..cb40f1a1d081 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -249,6 +249,7 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma,
extern int dup_userfaultfd(struct vm_area_struct *, struct list_head *);
extern void dup_userfaultfd_complete(struct list_head *);
+void dup_userfaultfd_fail(struct list_head *);
extern void mremap_userfaultfd_prep(struct vm_area_struct *,
struct vm_userfaultfd_ctx *);
@@ -351,6 +352,10 @@ static inline void dup_userfaultfd_complete(struct list_head *l)
{
}
+static inline void dup_userfaultfd_fail(struct list_head *l)
+{
+}
+
static inline void mremap_userfaultfd_prep(struct vm_area_struct *vma,
struct vm_userfaultfd_ctx *ctx)
{
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 306137a15d07..338e0f5efb4b 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -56,6 +56,17 @@ int virtqueue_add_inbuf_ctx(struct virtqueue *vq,
void *ctx,
gfp_t gfp);
+int virtqueue_add_inbuf_premapped(struct virtqueue *vq,
+ struct scatterlist *sg, unsigned int num,
+ void *data,
+ void *ctx,
+ gfp_t gfp);
+
+int virtqueue_add_outbuf_premapped(struct virtqueue *vq,
+ struct scatterlist *sg, unsigned int num,
+ void *data,
+ gfp_t gfp);
+
int virtqueue_add_sgs(struct virtqueue *vq,
struct scatterlist *sgs[],
unsigned int out_sgs,
@@ -82,8 +93,6 @@ bool virtqueue_enable_cb(struct virtqueue *vq);
unsigned virtqueue_enable_cb_prepare(struct virtqueue *vq);
-int virtqueue_set_dma_premapped(struct virtqueue *_vq);
-
bool virtqueue_poll(struct virtqueue *vq, unsigned);
bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index aed952d04132..f70d0958095c 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -134,6 +134,8 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
#ifdef CONFIG_SWAP
SWAP_RA,
SWAP_RA_HIT,
+ SWPIN_ZERO,
+ SWPOUT_ZERO,
#ifdef CONFIG_KSM
KSM_SWPIN_COPY,
#endif
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index e6e34d74dda0..03e5d3fe226d 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -21,8 +21,7 @@ struct compat_iw_point {
__u16 length;
__u16 flags;
};
-#endif
-#ifdef CONFIG_COMPAT
+
struct __compat_iw_event {
__u16 len; /* Real length of this stuff */
__u16 cmd; /* Wireless IOCTL */
@@ -49,5 +48,5 @@ struct __compat_iw_event {
#define IW_EV_COMPAT_POINT_LEN \
(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
IW_EV_COMPAT_POINT_OFF)
-#endif
+#endif /* CONFIG_COMPAT */
#endif /* _LINUX_WIRELESS_H */
diff --git a/include/linux/wwan.h b/include/linux/wwan.h
index 170fdee6339c..79c781875c09 100644
--- a/include/linux/wwan.h
+++ b/include/linux/wwan.h
@@ -17,6 +17,8 @@
* @WWAN_PORT_FIREHOSE: XML based command protocol
* @WWAN_PORT_XMMRPC: Control protocol for Intel XMM modems
* @WWAN_PORT_FASTBOOT: Fastboot protocol control
+ * @WWAN_PORT_ADB: ADB protocol control
+ * @WWAN_PORT_MIPC: MTK MIPC diagnostic interface
*
* @WWAN_PORT_MAX: Highest supported port types
* @WWAN_PORT_UNKNOWN: Special value to indicate an unknown port type
@@ -30,6 +32,8 @@ enum wwan_port_type {
WWAN_PORT_FIREHOSE,
WWAN_PORT_XMMRPC,
WWAN_PORT_FASTBOOT,
+ WWAN_PORT_ADB,
+ WWAN_PORT_MIPC,
/* Add new port types above this line */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index bab1e3d7452a..6203bd8663b7 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,7 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
- Copyright 2023 NXP
+ Copyright 2023-2024 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -29,6 +29,7 @@
#define HCI_MAX_ACL_SIZE 1024
#define HCI_MAX_SCO_SIZE 255
#define HCI_MAX_ISO_SIZE 251
+#define HCI_MAX_ISO_BIS 31
#define HCI_MAX_EVENT_SIZE 260
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
@@ -67,6 +68,7 @@
#define HCI_I2C 8
#define HCI_SMD 9
#define HCI_VIRTIO 10
+#define HCI_IPC 11
/* HCI device quirks */
enum {
@@ -300,6 +302,20 @@ enum {
*/
HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT,
+ /*
+ * When this quirk is set, the HCI_OP_LE_EXT_CREATE_CONN command is
+ * disabled. This is required for the Actions Semiconductor ATS2851
+ * based controllers, which erroneously claims to support it.
+ */
+ HCI_QUIRK_BROKEN_EXT_CREATE_CONN,
+
+ /*
+ * When this quirk is set, the command WRITE_AUTH_PAYLOAD_TIMEOUT is
+ * skipped. This is required for the Actions Semiconductor ATS2851
+ * based controllers, due to a race condition in pairing process.
+ */
+ HCI_QUIRK_BROKEN_WRITE_AUTH_PAYLOAD_TIMEOUT,
+
/* When this quirk is set, MSFT extension monitor tracking by
* address filter is supported. Since tracking quantity of each
* pattern is limited, this feature supports tracking multiple
@@ -683,6 +699,7 @@ enum {
#define HCI_RSSI_INVALID 127
#define HCI_SYNC_HANDLE_INVALID 0xffff
+#define HCI_SID_INVALID 0xff
#define HCI_ROLE_MASTER 0x00
#define HCI_ROLE_SLAVE 0x01
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 88265d37aa72..ea798f07c5a2 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -668,6 +668,7 @@ struct hci_conn {
__u8 adv_instance;
__u16 handle;
__u16 sync_handle;
+ __u8 sid;
__u16 state;
__u16 mtu;
__u8 mode;
@@ -710,6 +711,9 @@ struct hci_conn {
__s8 tx_power;
__s8 max_tx_power;
struct bt_iso_qos iso_qos;
+ __u8 num_bis;
+ __u8 bis[HCI_MAX_ISO_BIS];
+
unsigned long flags;
enum conn_reasons conn_reason;
@@ -945,8 +949,10 @@ enum {
HCI_CONN_PER_ADV,
HCI_CONN_BIG_CREATED,
HCI_CONN_CREATE_CIS,
+ HCI_CONN_CREATE_BIG_SYNC,
HCI_CONN_BIG_SYNC,
HCI_CONN_BIG_SYNC_FAILED,
+ HCI_CONN_CREATE_PA_SYNC,
HCI_CONN_PA_SYNC,
HCI_CONN_PA_SYNC_FAILED,
};
@@ -1099,6 +1105,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
return NULL;
}
+static inline struct hci_conn *hci_conn_hash_lookup_sid(struct hci_dev *hdev,
+ __u8 sid,
+ bdaddr_t *dst,
+ __u8 dst_type)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_conn *c;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+ if (c->type != ISO_LINK || bacmp(&c->dst, dst) ||
+ c->dst_type != dst_type || c->sid != sid)
+ continue;
+
+ rcu_read_unlock();
+ return c;
+ }
+
+ rcu_read_unlock();
+
+ return NULL;
+}
+
static inline struct hci_conn *
hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev,
bdaddr_t *ba,
@@ -1255,7 +1285,17 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
- if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK)
+ if (c->type != ISO_LINK)
+ continue;
+
+ /* An ISO_LINK hcon with BDADDR_ANY as destination
+ * address is a Broadcast connection. A Broadcast
+ * slave connection is associated with a PA train,
+ * so the sync_handle can be used to differentiate
+ * from unicast.
+ */
+ if (bacmp(&c->dst, BDADDR_ANY) &&
+ c->sync_handle == HCI_SYNC_HANDLE_INVALID)
continue;
if (handle == c->iso_qos.bcast.big) {
@@ -1270,6 +1310,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
}
static inline struct hci_conn *
+hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
+ __u8 handle, __u8 num_bis)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_conn *c;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+ if (c->type != ISO_LINK)
+ continue;
+
+ if (handle == c->iso_qos.bcast.big && num_bis == c->num_bis) {
+ rcu_read_unlock();
+ return c;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return NULL;
+}
+
+static inline struct hci_conn *
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
{
struct hci_conn_hash *h = &hdev->conn_hash;
@@ -1328,6 +1392,13 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
if (c->type != ISO_LINK)
continue;
+ /* Ignore the listen hcon, we are looking
+ * for the child hcon that was created as
+ * a result of the PA sync established event.
+ */
+ if (c->state == BT_LISTEN)
+ continue;
+
if (c->sync_handle == sync_handle) {
rcu_read_unlock();
return c;
@@ -1445,6 +1516,8 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
bool hci_iso_setup_path(struct hci_conn *conn);
int hci_le_create_cis_pending(struct hci_dev *hdev);
+int hci_pa_create_sync_pending(struct hci_dev *hdev);
+int hci_le_big_create_sync_pending(struct hci_dev *hdev);
int hci_conn_check_create_cis(struct hci_conn *conn);
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -1871,8 +1944,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
!test_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &(dev)->quirks))
/* Use ext create connection if command is supported */
-#define use_ext_conn(dev) ((dev)->commands[37] & 0x80)
-
+#define use_ext_conn(dev) (((dev)->commands[37] & 0x80) && \
+ !test_bit(HCI_QUIRK_BROKEN_EXT_CREATE_CONN, &(dev)->quirks))
/* Extended advertising support */
#define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))
@@ -1885,8 +1958,10 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
* C24: Mandatory if the LE Controller supports Connection State and either
* LE Feature (LL Privacy) or LE Feature (Extended Advertising) is supported
*/
-#define use_enhanced_conn_complete(dev) (ll_privacy_capable(dev) || \
- ext_adv_capable(dev))
+#define use_enhanced_conn_complete(dev) ((ll_privacy_capable(dev) || \
+ ext_adv_capable(dev)) && \
+ !test_bit(HCI_QUIRK_BROKEN_EXT_CREATE_CONN, \
+ &(dev)->quirks))
/* Periodic advertising support */
#define per_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_PERIODIC_ADV))
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index d382679efd2b..affac861efdc 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -878,6 +878,16 @@ struct mgmt_cp_mesh_send_cancel {
} __packed;
#define MGMT_MESH_SEND_CANCEL_SIZE 1
+#define MGMT_OP_HCI_CMD_SYNC 0x005B
+struct mgmt_cp_hci_cmd_sync {
+ __le16 opcode;
+ __u8 event;
+ __u8 timeout;
+ __le16 params_len;
+ __u8 params[];
+} __packed;
+#define MGMT_HCI_CMD_SYNC_SIZE 6
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index 473a0147769e..18687ccf0638 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -161,5 +161,7 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond);
#if IS_ENABLED(CONFIG_IPV6)
void bond_option_ns_ip6_targets_clear(struct bonding *bond);
#endif
+void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave);
+void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave);
#endif /* _NET_BOND_OPTIONS_H */
diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h
index f03040baaefd..c858270141bc 100644
--- a/include/net/busy_poll.h
+++ b/include/net/busy_poll.h
@@ -52,6 +52,9 @@ void napi_busy_loop_rcu(unsigned int napi_id,
bool (*loop_end)(void *, unsigned long),
void *loop_end_arg, bool prefer_busy_poll, u16 budget);
+void napi_suspend_irqs(unsigned int napi_id);
+void napi_resume_irqs(unsigned int napi_id);
+
#else /* CONFIG_NET_RX_BUSY_POLL */
static inline unsigned long net_busy_loop_on(void)
{
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 69ec1eb41a09..27acf1292a5c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1460,7 +1460,6 @@ struct cfg80211_unsol_bcast_probe_resp {
* @crypto: crypto settings
* @privacy: the BSS uses privacy
* @auth_type: Authentication type (algorithm)
- * @smps_mode: SMPS mode
* @inactivity_timeout: time in seconds to determine station's inactivity.
* @p2p_ctwindow: P2P CT Window
* @p2p_opp_ps: P2P opportunistic PS
@@ -1498,7 +1497,6 @@ struct cfg80211_ap_settings {
struct cfg80211_crypto_settings crypto;
bool privacy;
enum nl80211_auth_type auth_type;
- enum nl80211_smps_mode smps_mode;
int inactivity_timeout;
u8 p2p_ctwindow;
bool p2p_opp_ps;
@@ -2269,6 +2267,7 @@ static inline int cfg80211_get_station(struct net_device *dev,
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
+ * @MONITOR_FLAG_SKIP_TX: do not pass locally transmitted frames
*/
enum monitor_flags {
MONITOR_FLAG_CHANGED = BIT(__NL80211_MNTR_FLAG_INVALID),
@@ -2278,6 +2277,7 @@ enum monitor_flags {
MONITOR_FLAG_OTHER_BSS = BIT(NL80211_MNTR_FLAG_OTHER_BSS),
MONITOR_FLAG_COOK_FRAMES = BIT(NL80211_MNTR_FLAG_COOK_FRAMES),
MONITOR_FLAG_ACTIVE = BIT(NL80211_MNTR_FLAG_ACTIVE),
+ MONITOR_FLAG_SKIP_TX = BIT(NL80211_MNTR_FLAG_SKIP_TX),
};
/**
@@ -4696,6 +4696,7 @@ struct cfg80211_ops {
struct ieee80211_channel *chan);
int (*set_monitor_channel)(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef);
int (*scan)(struct wiphy *wiphy,
@@ -5436,6 +5437,8 @@ struct wiphy_radio_freq_range {
* @iface_combinations: Valid interface combinations array, should not
* list single interface types.
* @n_iface_combinations: number of entries in @iface_combinations array.
+ *
+ * @antenna_mask: bitmask of antennas connected to this radio.
*/
struct wiphy_radio {
const struct wiphy_radio_freq_range *freq_range;
@@ -5443,6 +5446,8 @@ struct wiphy_radio {
const struct ieee80211_iface_combination *iface_combinations;
int n_iface_combinations;
+
+ u32 antenna_mask;
};
#define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
@@ -6130,6 +6135,50 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork);
/**
+ * wiphy_delayed_work_pending - Find out whether a wiphy delayable
+ * work item is currently pending.
+ *
+ * @wiphy: the wiphy, for debug purposes
+ * @dwork: the delayed work in question
+ *
+ * Return: true if timer is pending, false otherwise
+ *
+ * How wiphy_delayed_work_queue() works is by setting a timer which
+ * when it expires calls wiphy_work_queue() to queue the wiphy work.
+ * Because wiphy_delayed_work_queue() uses mod_timer(), if it is
+ * called twice and the second call happens before the first call
+ * deadline, the work will rescheduled for the second deadline and
+ * won't run before that.
+ *
+ * wiphy_delayed_work_pending() can be used to detect if calling
+ * wiphy_work_delayed_work_queue() would start a new work schedule
+ * or delayed a previous one. As seen below it cannot be used to
+ * detect precisely if the work has finished to execute nor if it
+ * is currently executing.
+ *
+ * CPU0 CPU1
+ * wiphy_delayed_work_queue(wk)
+ * mod_timer(wk->timer)
+ * wiphy_delayed_work_pending(wk) -> true
+ *
+ * [...]
+ * expire_timers(wk->timer)
+ * detach_timer(wk->timer)
+ * wiphy_delayed_work_pending(wk) -> false
+ * wk->timer->function() |
+ * wiphy_work_queue(wk) | delayed work pending
+ * list_add_tail() | returns false but
+ * queue_work(cfg80211_wiphy_work) | wk->func() has not
+ * | been run yet
+ * [...] |
+ * cfg80211_wiphy_work() |
+ * wk->func() V
+ *
+ */
+bool wiphy_delayed_work_pending(struct wiphy *wiphy,
+ struct wiphy_delayed_work *dwork);
+
+/**
* enum ieee80211_ap_reg_power - regulatory power for an Access Point
*
* @IEEE80211_REG_UNSET_AP: Access Point has no regulatory power mode
@@ -6223,6 +6272,7 @@ enum ieee80211_ap_reg_power {
* entered.
* @links.cac_time_ms: CAC time in ms
* @valid_links: bitmap describing what elements of @links are valid
+ * @radio_mask: Bitmask of radios that this interface is allowed to operate on.
*/
struct wireless_dev {
struct wiphy *wiphy;
@@ -6335,6 +6385,8 @@ struct wireless_dev {
unsigned int cac_time_ms;
} links[IEEE80211_MLD_MAX_NUM_LINKS];
u16 valid_links;
+
+ u32 radio_mask;
};
static inline const u8 *wdev_address(struct wireless_dev *wdev)
@@ -6521,6 +6573,17 @@ bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
const struct cfg80211_chan_def *chandef);
/**
+ * cfg80211_wdev_channel_allowed - Check if the wdev may use the channel
+ *
+ * @wdev: the wireless device
+ * @chan: channel to check
+ *
+ * Return: whether or not the wdev may use the channel
+ */
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
+ struct ieee80211_channel *chan);
+
+/**
* ieee80211_get_response_rate - get basic rate for a given rate
*
* @sband: the band to look for rates in
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 1338cb92c8e7..243f972267b8 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -151,6 +151,12 @@ static inline void csum_replace(__wsum *csum, __wsum old, __wsum new)
*csum = csum_add(csum_sub(*csum, old), new);
}
+static inline unsigned short csum_from32to16(unsigned int sum)
+{
+ sum += (sum >> 16) | (sum << 16);
+ return (unsigned short)(sum >> 16);
+}
+
struct sk_buff;
void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
__be32 from, __be32 to, bool pseudohdr);
diff --git a/include/net/devlink.h b/include/net/devlink.h
index db5eff6cb60f..fbb9a2668e24 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1779,12 +1779,6 @@ int devl_resource_register(struct devlink *devlink,
u64 resource_id,
u64 parent_resource_id,
const struct devlink_resource_size_params *size_params);
-int devlink_resource_register(struct devlink *devlink,
- const char *resource_name,
- u64 resource_size,
- u64 resource_id,
- u64 parent_resource_id,
- const struct devlink_resource_size_params *size_params);
void devl_resources_unregister(struct devlink *devlink);
void devlink_resources_unregister(struct devlink *devlink);
int devl_resource_size_get(struct devlink *devlink,
@@ -1797,15 +1791,8 @@ void devl_resource_occ_get_register(struct devlink *devlink,
u64 resource_id,
devlink_resource_occ_get_t *occ_get,
void *occ_get_priv);
-void devlink_resource_occ_get_register(struct devlink *devlink,
- u64 resource_id,
- devlink_resource_occ_get_t *occ_get,
- void *occ_get_priv);
void devl_resource_occ_get_unregister(struct devlink *devlink,
u64 resource_id);
-
-void devlink_resource_occ_get_unregister(struct devlink *devlink,
- u64 resource_id);
int devl_params_register(struct devlink *devlink,
const struct devlink_param *params,
size_t params_count);
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index d59bb96c5a02..6c5a1ea209a2 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -76,6 +76,10 @@
FN(INVALID_PROTO) \
FN(IP_INADDRERRORS) \
FN(IP_INNOROUTES) \
+ FN(IP_LOCAL_SOURCE) \
+ FN(IP_INVALID_SOURCE) \
+ FN(IP_LOCALNET) \
+ FN(IP_INVALID_DEST) \
FN(PKT_TOO_BIG) \
FN(DUP_FRAG) \
FN(FRAG_REASM_TIMEOUT) \
@@ -100,6 +104,7 @@
FN(IP_TUNNEL_ECN) \
FN(TUNNEL_TXINFO) \
FN(LOCAL_MAC) \
+ FN(ARP_PVLAN_DISABLE) \
FNe(MAX)
/**
@@ -373,6 +378,21 @@ enum skb_drop_reason {
* IPSTATS_MIB_INADDRERRORS
*/
SKB_DROP_REASON_IP_INNOROUTES,
+ /** @SKB_DROP_REASON_IP_LOCAL_SOURCE: the source ip is local */
+ SKB_DROP_REASON_IP_LOCAL_SOURCE,
+ /**
+ * @SKB_DROP_REASON_IP_INVALID_SOURCE: the source ip is invalid:
+ * 1) source ip is multicast or limited broadcast
+ * 2) source ip is zero and not IGMP
+ */
+ SKB_DROP_REASON_IP_INVALID_SOURCE,
+ /** @SKB_DROP_REASON_IP_LOCALNET: source or dest ip is local net */
+ SKB_DROP_REASON_IP_LOCALNET,
+ /**
+ * @SKB_DROP_REASON_IP_INVALID_DEST: the dest ip is invalid:
+ * 1) dest ip is 0
+ */
+ SKB_DROP_REASON_IP_INVALID_DEST,
/**
* @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the
* MTU)
@@ -459,6 +479,12 @@ enum skb_drop_reason {
*/
SKB_DROP_REASON_LOCAL_MAC,
/**
+ * @SKB_DROP_REASON_ARP_PVLAN_DISABLE: packet which is not IP is
+ * forwarded to the in_dev, and the proxy_arp_pvlan is not
+ * enabled.
+ */
+ SKB_DROP_REASON_ARP_PVLAN_DISABLE,
+ /**
* @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
* shouldn't be used as a real 'reason' - only for tracing code gen
*/
diff --git a/include/net/eee.h b/include/net/eee.h
index 84837aba3cd9..cfab1b8bc46a 100644
--- a/include/net/eee.h
+++ b/include/net/eee.h
@@ -13,10 +13,7 @@ struct eee_config {
static inline bool eeecfg_mac_can_tx_lpi(const struct eee_config *eeecfg)
{
/* eee_enabled is the master on/off */
- if (!eeecfg->eee_enabled || !eeecfg->tx_lpi_enabled)
- return false;
-
- return true;
+ return eeecfg->eee_enabled && eeecfg->tx_lpi_enabled;
}
static inline void eeecfg_to_eee(struct ethtool_keee *eee,
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 292cd8f4b762..596ab9791e4d 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -685,6 +685,7 @@ struct flow_cls_common_offload {
u32 chain_index;
__be16 protocol;
u32 prio;
+ bool skip_sw;
struct netlink_ext_ack *extack;
};
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 02fbc036f34e..813e163ce27c 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -24,25 +24,27 @@
* struct ieee80211_radiotap_header - base radiotap header
*/
struct ieee80211_radiotap_header {
- /**
- * @it_version: radiotap version, always 0
- */
- uint8_t it_version;
-
- /**
- * @it_pad: padding (or alignment)
- */
- uint8_t it_pad;
-
- /**
- * @it_len: overall radiotap header length
- */
- __le16 it_len;
-
- /**
- * @it_present: (first) present word
- */
- __le32 it_present;
+ __struct_group(ieee80211_radiotap_header_fixed, hdr, __packed,
+ /**
+ * @it_version: radiotap version, always 0
+ */
+ uint8_t it_version;
+
+ /**
+ * @it_pad: padding (or alignment)
+ */
+ uint8_t it_pad;
+
+ /**
+ * @it_len: overall radiotap header length
+ */
+ __le16 it_len;
+
+ /**
+ * @it_present: (first) present word
+ */
+ __le32 it_present;
+ );
/**
* @it_optional: all remaining presence bitmaps
@@ -50,6 +52,9 @@ struct ieee80211_radiotap_header {
__le32 it_optional[];
} __packed;
+static_assert(offsetof(struct ieee80211_radiotap_header, it_optional) == sizeof(struct ieee80211_radiotap_header_fixed),
+ "struct member likely outside of __struct_group()");
+
/* version is always 0 */
#define PKTHDR_RADIOTAP_VERSION 0
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index b6e44f4eaa4c..a113c11ab56b 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -452,6 +452,18 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
dscp_t dscp, int oif, struct net_device *dev,
struct in_device *idev, u32 *itag);
+static inline enum skb_drop_reason
+fib_validate_source_reason(struct sk_buff *skb, __be32 src, __be32 dst,
+ dscp_t dscp, int oif, struct net_device *dev,
+ struct in_device *idev, u32 *itag)
+{
+ int err = fib_validate_source(skb, src, dst, dscp, oif, dev, idev,
+ itag);
+ if (err < 0)
+ return -err;
+ return SKB_NOT_DROPPED_YET;
+}
+
#ifdef CONFIG_IP_ROUTE_CLASSID
static inline int fib_num_tclassid_users(struct net *net)
{
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 4e4f9e24c9c1..1aa31bdb2b31 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -354,7 +354,7 @@ static inline void ip_tunnel_init_flow(struct flowi4 *fl4,
memset(fl4, 0, sizeof(*fl4));
if (oif) {
- fl4->flowi4_l3mdev = l3mdev_master_upper_ifindex_by_index_rcu(net, oif);
+ fl4->flowi4_l3mdev = l3mdev_master_upper_ifindex_by_index(net, oif);
/* Legacy VRF/l3mdev use case */
fl4->flowi4_oif = fl4->flowi4_l3mdev ? 0 : oif;
}
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index 7af1082ea9a0..b80e474cb0aa 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -279,8 +279,6 @@
#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
/* SET : Omit payload from generated iwevent */
#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
-/* Driver level flags */
-#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
/****************************** TYPES ******************************/
@@ -373,11 +371,10 @@ struct iw_handler_def {
*/
struct iw_ioctl_description {
__u8 header_type; /* NULL, iw_point or other */
- __u8 token_type; /* Future */
+ __u8 flags; /* Special handling of the request */
__u16 token_size; /* Granularity of payload */
__u16 min_tokens; /* Min acceptable token number */
__u16 max_tokens; /* Max acceptable token number */
- __u32 flags; /* Special handling of the request */
};
/* Need to think of short header translation table. Later. */
@@ -404,26 +401,6 @@ struct iw_spy_data {
u_char spy_thr_under[IW_MAX_SPY];
};
-/* --------------------- DEVICE WIRELESS DATA --------------------- */
-/*
- * This is all the wireless data specific to a device instance that
- * is managed by the core of Wireless Extensions or the 802.11 layer.
- * We only keep pointer to those structures, so that a driver is free
- * to share them between instances.
- * This structure should be initialised before registering the device.
- * Access to this data follow the same rules as any other struct net_device
- * data (i.e. valid as long as struct net_device exist, same locking rules).
- */
-/* Forward declaration */
-struct libipw_device;
-/* The struct */
-struct iw_public_data {
- /* Driver enhanced spy support */
- struct iw_spy_data * spy_data;
- /* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */
- struct libipw_device * libipw;
-};
-
/**************************** PROTOTYPES ****************************/
/*
* Functions part of the Wireless Extensions (defined in net/wireless/wext-core.c).
@@ -443,22 +420,6 @@ static inline void wireless_nlevent_flush(void) {}
/* We may need a function to send a stream of events to user space.
* More on that later... */
-/* Standard handler for SIOCSIWSPY */
-int iw_handler_set_spy(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCGIWSPY */
-int iw_handler_get_spy(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCSIWTHRSPY */
-int iw_handler_set_thrspy(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCGIWTHRSPY */
-int iw_handler_get_thrspy(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-/* Driver call to update spy records */
-void wireless_spy_update(struct net_device *dev, unsigned char *address,
- struct iw_quality *wstats);
-
/************************* INLINE FUNCTIONS *************************/
/*
* Function that are so simple that it's more efficient inlining them
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
deleted file mode 100644
index fd0f15d87d80..000000000000
--- a/include/net/lib80211.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * lib80211.h -- common bits for IEEE802.11 wireless drivers
- *
- * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com>
- *
- * Some bits copied from old ieee80211 component, w/ original copyright
- * notices below:
- *
- * Original code based on 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-2003, Jouni Malinen <j@w1.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno@linux.intel.com>
- *
- * Copyright (c) 2004, Intel Corporation
- *
- */
-
-#ifndef LIB80211_H
-#define LIB80211_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/atomic.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/ieee80211.h>
-#include <linux/timer.h>
-#include <linux/seq_file.h>
-
-#define NUM_WEP_KEYS 4
-
-enum {
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0),
-};
-
-struct module;
-
-struct lib80211_crypto_ops {
- const char *name;
- struct list_head list;
-
- /* init new crypto context (e.g., allocate private data space,
- * select IV, etc.); returns NULL on failure or pointer to allocated
- * private data on success */
- void *(*init) (int keyidx);
-
- /* deinitialize crypto context and free allocated private data */
- void (*deinit) (void *priv);
-
- /* encrypt/decrypt return < 0 on error or >= 0 on success. The return
- * value from decrypt_mpdu is passed as the keyidx value for
- * decrypt_msdu. skb must have enough head and tail room for the
- * encryption; if not, error will be returned; these functions are
- * called for all MPDUs (i.e., fragments).
- */
- int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
- int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv);
-
- /* These functions are called for full MSDUs, i.e. full frames.
- * These can be NULL if full MSDU operations are not needed. */
- int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv);
- int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len,
- void *priv);
-
- int (*set_key) (void *key, int len, u8 * seq, void *priv);
- int (*get_key) (void *key, int len, u8 * seq, void *priv);
-
- /* procfs handler for printing out key information and possible
- * statistics */
- void (*print_stats) (struct seq_file *m, void *priv);
-
- /* Crypto specific flag get/set for configuration settings */
- unsigned long (*get_flags) (void *priv);
- unsigned long (*set_flags) (unsigned long flags, void *priv);
-
- /* maximum number of bytes added by encryption; encrypt buf is
- * allocated with extra_prefix_len bytes, copy of in_buf, and
- * extra_postfix_len; encrypt need not use all this space, but
- * the result must start at the beginning of the buffer and correct
- * length must be returned */
- int extra_mpdu_prefix_len, extra_mpdu_postfix_len;
- int extra_msdu_prefix_len, extra_msdu_postfix_len;
-
- struct module *owner;
-};
-
-struct lib80211_crypt_data {
- struct list_head list; /* delayed deletion list */
- const struct lib80211_crypto_ops *ops;
- void *priv;
- atomic_t refcnt;
-};
-
-struct lib80211_crypt_info {
- char *name;
- /* Most clients will already have a lock,
- so just point to that. */
- spinlock_t *lock;
-
- struct lib80211_crypt_data *crypt[NUM_WEP_KEYS];
- int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
- struct list_head crypt_deinit_list;
- struct timer_list crypt_deinit_timer;
- int crypt_quiesced;
-};
-
-int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
- spinlock_t *lock);
-void lib80211_crypt_info_free(struct lib80211_crypt_info *info);
-int lib80211_register_crypto_ops(const struct lib80211_crypto_ops *ops);
-int lib80211_unregister_crypto_ops(const struct lib80211_crypto_ops *ops);
-const struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name);
-void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
- struct lib80211_crypt_data **crypt);
-
-#endif /* LIB80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 333e0fae6796..a97c9f85ae9a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -213,7 +213,7 @@ struct ieee80211_low_level_stats {
* @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
* @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
* this is used only with channel switching with CSA
- * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed
+ * @IEEE80211_CHANCTX_CHANGE_MIN_DEF: The min chandef changed
* @IEEE80211_CHANCTX_CHANGE_AP: The AP channel definition changed, so (wider
* bandwidth) OFDMA settings need to be changed
* @IEEE80211_CHANCTX_CHANGE_PUNCTURING: The punctured channel(s) bitmap
@@ -224,7 +224,7 @@ enum ieee80211_chanctx_change {
IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),
IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2),
IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3),
- IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4),
+ IEEE80211_CHANCTX_CHANGE_MIN_DEF = BIT(4),
IEEE80211_CHANCTX_CHANGE_AP = BIT(5),
IEEE80211_CHANCTX_CHANGE_PUNCTURING = BIT(6),
};
@@ -740,6 +740,19 @@ struct ieee80211_parsed_tpe {
* @eht_80mhz_full_bw_ul_mumimo: in AP-mode, does this BSS support the
* reception of an EHT TB PPDU on an RU that spans the entire PPDU
* bandwidth
+ * @bss_param_ch_cnt: in BSS-mode, the BSS params change count. This
+ * information is the latest known value. It can come from this link's
+ * beacon or from a beacon sent by another link.
+ * @bss_param_ch_cnt_link_id: in BSS-mode, the link_id to which the beacon
+ * that updated &bss_param_ch_cnt belongs. E.g. if link 1 doesn't hear
+ * its beacons, and link 2 sent a beacon with an RNR element that updated
+ * link 1's BSS params change count, then, link 1's
+ * bss_param_ch_cnt_link_id will be 2. That means that link 1 knows that
+ * link 2 was the link that updated its bss_param_ch_cnt value.
+ * In case link 1 hears its beacon again, bss_param_ch_cnt_link_id will
+ * be updated to 1, even if bss_param_ch_cnt didn't change. This allows
+ * the link to know that it heard the latest value from its own beacon
+ * (as opposed to hearing its value from another link's beacon).
*/
struct ieee80211_bss_conf {
struct ieee80211_vif *vif;
@@ -834,6 +847,8 @@ struct ieee80211_bss_conf {
bool eht_su_beamformee;
bool eht_mu_beamformer;
bool eht_80mhz_full_bw_ul_mumimo;
+ u8 bss_param_ch_cnt;
+ u8 bss_param_ch_cnt_link_id;
};
/**
@@ -1448,8 +1463,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU
* @RX_FLAG_AMPDU_DELIM_CRC_ERROR: A delimiter CRC error has been detected
* on this subframe
- * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
- * is stored in the @ampdu_delimiter_crc field)
* @RX_FLAG_MIC_STRIPPED: The mic was stripped of this packet. Decryption was
* done by the hardware
* @RX_FLAG_ONLY_MONITOR: Report frame only to monitor interfaces without
@@ -1521,7 +1534,7 @@ enum mac80211_rx_flags {
RX_FLAG_AMPDU_LAST_KNOWN = BIT(12),
RX_FLAG_AMPDU_IS_LAST = BIT(13),
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(14),
- RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(15),
+ /* one free bit at 15 */
RX_FLAG_MACTIME = BIT(16) | BIT(17),
RX_FLAG_MACTIME_PLCP_START = 1 << 16,
RX_FLAG_MACTIME_START = 2 << 16,
@@ -1618,7 +1631,6 @@ enum mac80211_rx_encoding {
* @rx_flags: internal RX flags for mac80211
* @ampdu_reference: A-MPDU reference number, must be a different value for
* each A-MPDU but the same for each subframe within one A-MPDU
- * @ampdu_delimiter_crc: A-MPDU delimiter CRC
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
* @link_valid: if the link which is identified by @link_id is valid. This flag
* is set only when connection is MLO.
@@ -1656,7 +1668,6 @@ struct ieee80211_rx_status {
s8 signal;
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
- u8 ampdu_delimiter_crc;
u8 zero_length_psdu_type;
u8 link_valid:1, link_id:4;
};
@@ -2683,6 +2694,11 @@ struct ieee80211_txq {
* a virtual monitor interface when monitor interfaces are the only
* active interfaces.
*
+ * @IEEE80211_HW_NO_VIRTUAL_MONITOR: The driver would like to be informed
+ * of any monitor interface, as well as their configured channel.
+ * This is useful for supporting multiple monitor interfaces on different
+ * channels.
+ *
* @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
* be created. It is expected user-space will create vifs as
* desired (and thus have them named as desired).
@@ -2842,6 +2858,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_DYNAMIC_PS,
IEEE80211_HW_MFP_CAPABLE,
IEEE80211_HW_WANT_MONITOR_VIF,
+ IEEE80211_HW_NO_VIRTUAL_MONITOR,
IEEE80211_HW_NO_AUTO_VIF,
IEEE80211_HW_SW_CRYPTO_CONTROL,
IEEE80211_HW_SUPPORT_FAST_XMIT,
@@ -4075,8 +4092,8 @@ struct ieee80211_prep_tx_info {
* in @sta_state.
* The callback can sleep.
*
- * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
- * used to transmit to the station. The changes are advertised with bits
+ * @link_sta_rc_update: Notifies the driver of changes to the bitrates that can
+ * be used to transmit to the station. The changes are advertised with bits
* from &enum ieee80211_rate_control_changed and the values are reflected
* in the station data. This callback should only be used when the driver
* uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
@@ -4444,6 +4461,12 @@ struct ieee80211_prep_tx_info {
* if the requested TID-To-Link mapping can be accepted or not.
* If it's not accepted the driver may suggest a preferred mapping and
* modify @ttlm parameter with the suggested TID-to-Link mapping.
+ * @prep_add_interface: prepare for interface addition. This can be used by
+ * drivers to prepare for the addition of a new interface, e.g., allocate
+ * the needed resources etc. This callback doesn't guarantee that an
+ * interface with the specified type would be added, and thus drivers that
+ * implement this callback need to handle such cases. The type is the full
+ * &enum nl80211_iftype.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4560,10 +4583,10 @@ struct ieee80211_ops {
void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
- void (*sta_rc_update)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 changed);
+ void (*link_sta_rc_update)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_link_sta *link_sta,
+ u32 changed);
void (*sta_rate_tbl_update)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@@ -4828,6 +4851,8 @@ struct ieee80211_ops {
enum ieee80211_neg_ttlm_res
(*can_neg_ttlm)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_neg_ttlm *ttlm);
+ void (*prep_add_interface)(struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
};
/**
@@ -7647,12 +7672,12 @@ static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
*
* - change_vif_links(0x11)
* - unassign_vif_chanctx(link_id=0)
+ * - assign_vif_chanctx(link_id=4)
* - change_sta_links(0x11) for each affected STA (the AP)
* (TDLS connections on now inactive links should be torn down)
* - remove group keys on the old link (link_id 0)
* - add new group keys (GTK/IGTK/BIGTK) on the new link (link_id 4)
* - change_sta_links(0x10) for each affected STA (the AP)
- * - assign_vif_chanctx(link_id=4)
* - change_vif_links(0x10)
*
* Return: 0 on success. An error code otherwise.
@@ -7681,6 +7706,33 @@ void ieee80211_set_active_links_async(struct ieee80211_vif *vif,
*/
void ieee80211_send_teardown_neg_ttlm(struct ieee80211_vif *vif);
+/**
+ * ieee80211_chan_width_to_rx_bw - convert channel width to STA RX bandwidth
+ * @width: the channel width value to convert
+ * Return: the STA RX bandwidth value for the channel width
+ */
+static inline enum ieee80211_sta_rx_bandwidth
+ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
+{
+ switch (width) {
+ default:
+ WARN_ON_ONCE(1);
+ fallthrough;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ return IEEE80211_STA_RX_BW_20;
+ case NL80211_CHAN_WIDTH_40:
+ return IEEE80211_STA_RX_BW_40;
+ case NL80211_CHAN_WIDTH_80:
+ return IEEE80211_STA_RX_BW_80;
+ case NL80211_CHAN_WIDTH_160:
+ case NL80211_CHAN_WIDTH_80P80:
+ return IEEE80211_STA_RX_BW_160;
+ case NL80211_CHAN_WIDTH_320:
+ return IEEE80211_STA_RX_BW_320;
+ }
+}
+
/* for older drivers - let's not document these ... */
int ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
diff --git a/include/net/mctp.h b/include/net/mctp.h
index 28d59ae94ca3..1ecbff7116f6 100644
--- a/include/net/mctp.h
+++ b/include/net/mctp.h
@@ -298,4 +298,22 @@ void mctp_routes_exit(void);
int mctp_device_init(void);
void mctp_device_exit(void);
+/* MCTP IDs and Codes from DMTF specification
+ * "DSP0239 Management Component Transport Protocol (MCTP) IDs and Codes"
+ * https://www.dmtf.org/sites/default/files/standards/documents/DSP0239_1.11.1.pdf
+ */
+enum mctp_phys_binding {
+ MCTP_PHYS_BINDING_UNSPEC = 0x00,
+ MCTP_PHYS_BINDING_SMBUS = 0x01,
+ MCTP_PHYS_BINDING_PCIE_VDM = 0x02,
+ MCTP_PHYS_BINDING_USB = 0x03,
+ MCTP_PHYS_BINDING_KCS = 0x04,
+ MCTP_PHYS_BINDING_SERIAL = 0x05,
+ MCTP_PHYS_BINDING_I3C = 0x06,
+ MCTP_PHYS_BINDING_MMBI = 0x07,
+ MCTP_PHYS_BINDING_PCC = 0x08,
+ MCTP_PHYS_BINDING_UCIE = 0x09,
+ MCTP_PHYS_BINDING_VENDOR = 0xFF,
+};
+
#endif /* __NET_MCTP_H */
diff --git a/include/net/mctpdevice.h b/include/net/mctpdevice.h
index 5c0d04b5c12c..957d9ef924c5 100644
--- a/include/net/mctpdevice.h
+++ b/include/net/mctpdevice.h
@@ -22,6 +22,7 @@ struct mctp_dev {
refcount_t refs;
unsigned int net;
+ enum mctp_phys_binding binding;
const struct mctp_netdev_ops *ops;
@@ -44,7 +45,8 @@ struct mctp_dev *mctp_dev_get_rtnl(const struct net_device *dev);
struct mctp_dev *__mctp_dev_get(const struct net_device *dev);
int mctp_register_netdev(struct net_device *dev,
- const struct mctp_netdev_ops *ops);
+ const struct mctp_netdev_ops *ops,
+ enum mctp_phys_binding binding);
void mctp_unregister_netdev(struct net_device *dev);
void mctp_dev_hold(struct mctp_dev *mdev);
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 3887ed9e5026..9a832cab5b1d 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -29,6 +29,7 @@
#include <linux/sysctl.h>
#include <linux/workqueue.h>
#include <net/rtnetlink.h>
+#include <net/neighbour_tables.h>
/*
* NUD stands for "neighbor unreachability detection"
@@ -135,7 +136,8 @@ struct neigh_statistics {
#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field)
struct neighbour {
- struct neighbour __rcu *next;
+ struct hlist_node hash;
+ struct hlist_node dev_list;
struct neigh_table *tbl;
struct neigh_parms *parms;
unsigned long confirmed;
@@ -190,7 +192,7 @@ struct pneigh_entry {
#define NEIGH_NUM_HASH_RND 4
struct neigh_hash_table {
- struct neighbour __rcu **hash_buckets;
+ struct hlist_head *hash_heads;
unsigned int hash_shift;
__u32 hash_rnd[NEIGH_NUM_HASH_RND];
struct rcu_head rcu;
@@ -236,13 +238,6 @@ struct neigh_table {
struct pneigh_entry **phash_buckets;
};
-enum {
- NEIGH_ARP_TABLE = 0,
- NEIGH_ND_TABLE = 1,
- NEIGH_NR_TABLES,
- NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */
-};
-
static inline int neigh_parms_family(struct neigh_parms *p)
{
return p->tbl->family;
@@ -275,6 +270,12 @@ static inline void *neighbour_priv(const struct neighbour *n)
extern const struct nla_policy nda_policy[];
+#define neigh_for_each_in_bucket(pos, head) hlist_for_each_entry(pos, head, hash)
+#define neigh_for_each_in_bucket_rcu(pos, head) \
+ hlist_for_each_entry_rcu(pos, head, hash)
+#define neigh_for_each_in_bucket_safe(pos, tmp, head) \
+ hlist_for_each_entry_safe(pos, tmp, head, hash)
+
static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey)
{
return *(const u32 *)n->primary_key == *(const u32 *)pkey;
@@ -303,12 +304,9 @@ static inline struct neighbour *___neigh_lookup_noref(
u32 hash_val;
hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
- for (n = rcu_dereference(nht->hash_buckets[hash_val]);
- n != NULL;
- n = rcu_dereference(n->next)) {
+ neigh_for_each_in_bucket_rcu(n, &nht->hash_heads[hash_val])
if (n->dev == dev && key_eq(n, pkey))
return n;
- }
return NULL;
}
@@ -349,7 +347,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags,
u32 nlmsg_pid);
void __neigh_set_probe_once(struct neighbour *neigh);
-bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl);
+bool neigh_remove_one(struct neighbour *ndel);
void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev);
diff --git a/include/net/neighbour_tables.h b/include/net/neighbour_tables.h
new file mode 100644
index 000000000000..bcffbe8f7601
--- /dev/null
+++ b/include/net/neighbour_tables.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NET_NEIGHBOUR_TABLES_H
+#define _NET_NEIGHBOUR_TABLES_H
+
+enum {
+ NEIGH_ARP_TABLE = 0,
+ NEIGH_ND_TABLE = 1,
+ NEIGH_NR_TABLES,
+ NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */
+};
+
+#endif
diff --git a/include/net/net_debug.h b/include/net/net_debug.h
index 1e74684cbbdb..9fecb1496be3 100644
--- a/include/net/net_debug.h
+++ b/include/net/net_debug.h
@@ -149,9 +149,11 @@ do { \
#if defined(CONFIG_DEBUG_NET)
-#define DEBUG_NET_WARN_ON_ONCE(cond) (void)WARN_ON_ONCE(cond)
+#define DEBUG_NET_WARN_ON_ONCE(cond) ((void)WARN_ON_ONCE(cond))
+#define DEBUG_NET_WARN_ONCE(cond, format...) ((void)WARN_ONCE(cond, format))
#else
#define DEBUG_NET_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond)
+#define DEBUG_NET_WARN_ONCE(cond, format...) BUILD_BUG_ON_INVALID(cond)
#endif
#endif /* _LINUX_NET_DEBUG_H */
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 91ae20cb7648..80a537ac26cd 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -1103,6 +1103,7 @@ struct nft_rule_blob {
* @name: name of the chain
* @udlen: user data length
* @udata: user data in the chain
+ * @rcu_head: rcu head for deferred release
* @blob_next: rule blob pointer to the next in the chain
*/
struct nft_chain {
@@ -1120,6 +1121,7 @@ struct nft_chain {
char *name;
u16 udlen;
u8 *udata;
+ struct rcu_head rcu_head;
/* Only used during control plane commit phase: */
struct nft_rule_blob *blob_next;
@@ -1263,6 +1265,7 @@ static inline void nft_use_inc_restore(u32 *use)
* @sets: sets in the table
* @objects: stateful objects in the table
* @flowtables: flow tables in the table
+ * @net: netnamespace this table belongs to
* @hgenerator: handle generator state
* @handle: table handle
* @use: number of chain references to this table
@@ -1282,6 +1285,7 @@ struct nft_table {
struct list_head sets;
struct list_head objects;
struct list_head flowtables;
+ possible_net_t net;
u64 hgenerator;
u64 handle;
u32 use;
@@ -1463,7 +1467,8 @@ struct nft_flowtable {
struct nf_flowtable data;
};
-struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
+struct nft_flowtable *nft_flowtable_lookup(const struct net *net,
+ const struct nft_table *table,
const struct nlattr *nla,
u8 genmask);
@@ -1754,28 +1759,29 @@ enum nft_trans_elem_flags {
NFT_TRANS_UPD_EXPIRATION = (1 << 1),
};
+struct nft_elem_update {
+ u64 timeout;
+ u64 expiration;
+ u8 flags;
+};
+
+struct nft_trans_one_elem {
+ struct nft_elem_priv *priv;
+ struct nft_elem_update *update;
+};
+
struct nft_trans_elem {
struct nft_trans nft_trans;
struct nft_set *set;
- struct nft_elem_priv *elem_priv;
- u64 timeout;
- u64 expiration;
- u8 update_flags;
bool bound;
+ unsigned int nelems;
+ struct nft_trans_one_elem elems[] __counted_by(nelems);
};
#define nft_trans_container_elem(t) \
container_of(t, struct nft_trans_elem, nft_trans)
#define nft_trans_elem_set(trans) \
nft_trans_container_elem(trans)->set
-#define nft_trans_elem_priv(trans) \
- nft_trans_container_elem(trans)->elem_priv
-#define nft_trans_elem_update_flags(trans) \
- nft_trans_container_elem(trans)->update_flags
-#define nft_trans_elem_timeout(trans) \
- nft_trans_container_elem(trans)->timeout
-#define nft_trans_elem_expiration(trans) \
- nft_trans_container_elem(trans)->expiration
#define nft_trans_elem_set_bound(trans) \
nft_trans_container_elem(trans)->bound
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 529160f76cac..4afd934b1238 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -208,6 +208,7 @@ struct netlbl_lsm_secattr {
* struct netlbl_calipso_ops - NetLabel CALIPSO operations
* @doi_add: add a CALIPSO DOI
* @doi_free: free a CALIPSO DOI
+ * @doi_remove: remove a CALIPSO DOI
* @doi_getdef: returns a reference to a DOI
* @doi_putdef: releases a reference of a DOI
* @doi_walk: enumerate the DOI list
diff --git a/include/net/netlink.h b/include/net/netlink.h
index db6af207287c..39eaa6be6ca8 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -142,6 +142,8 @@
* nla_get_flag(nla) return 1 if flag is true
* nla_get_msecs(nla) get payload for a msecs attribute
*
+ * The same functions also exist with _default().
+ *
* Attribute Misc:
* nla_memcpy(dest, nla, count) copy attribute into memory
* nla_memcmp(nla, data, size) compare attribute with memory area
@@ -469,6 +471,7 @@ struct nla_policy {
.max = _len \
}
#define NLA_POLICY_MIN_LEN(_len) NLA_POLICY_MIN(NLA_BINARY, _len)
+#define NLA_POLICY_MAX_LEN(_len) NLA_POLICY_MAX(NLA_BINARY, _len)
/**
* struct nl_info - netlink source information
@@ -1695,6 +1698,20 @@ static inline u32 nla_get_u32(const struct nlattr *nla)
}
/**
+ * nla_get_u32_default - return payload of u32 attribute or default
+ * @nla: u32 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline u32 nla_get_u32_default(const struct nlattr *nla, u32 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_u32(nla);
+}
+
+/**
* nla_get_be32 - return payload of __be32 attribute
* @nla: __be32 netlink attribute
*/
@@ -1704,6 +1721,21 @@ static inline __be32 nla_get_be32(const struct nlattr *nla)
}
/**
+ * nla_get_be32_default - return payload of be32 attribute or default
+ * @nla: __be32 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __be32 nla_get_be32_default(const struct nlattr *nla,
+ __be32 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_be32(nla);
+}
+
+/**
* nla_get_le32 - return payload of __le32 attribute
* @nla: __le32 netlink attribute
*/
@@ -1713,6 +1745,21 @@ static inline __le32 nla_get_le32(const struct nlattr *nla)
}
/**
+ * nla_get_le32_default - return payload of le32 attribute or default
+ * @nla: __le32 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __le32 nla_get_le32_default(const struct nlattr *nla,
+ __le32 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_le32(nla);
+}
+
+/**
* nla_get_u16 - return payload of u16 attribute
* @nla: u16 netlink attribute
*/
@@ -1722,6 +1769,20 @@ static inline u16 nla_get_u16(const struct nlattr *nla)
}
/**
+ * nla_get_u16_default - return payload of u16 attribute or default
+ * @nla: u16 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline u16 nla_get_u16_default(const struct nlattr *nla, u16 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_u16(nla);
+}
+
+/**
* nla_get_be16 - return payload of __be16 attribute
* @nla: __be16 netlink attribute
*/
@@ -1731,6 +1792,21 @@ static inline __be16 nla_get_be16(const struct nlattr *nla)
}
/**
+ * nla_get_be16_default - return payload of be16 attribute or default
+ * @nla: __be16 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __be16 nla_get_be16_default(const struct nlattr *nla,
+ __be16 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_be16(nla);
+}
+
+/**
* nla_get_le16 - return payload of __le16 attribute
* @nla: __le16 netlink attribute
*/
@@ -1740,6 +1816,21 @@ static inline __le16 nla_get_le16(const struct nlattr *nla)
}
/**
+ * nla_get_le16_default - return payload of le16 attribute or default
+ * @nla: __le16 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __le16 nla_get_le16_default(const struct nlattr *nla,
+ __le16 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_le16(nla);
+}
+
+/**
* nla_get_u8 - return payload of u8 attribute
* @nla: u8 netlink attribute
*/
@@ -1749,6 +1840,20 @@ static inline u8 nla_get_u8(const struct nlattr *nla)
}
/**
+ * nla_get_u8_default - return payload of u8 attribute or default
+ * @nla: u8 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline u8 nla_get_u8_default(const struct nlattr *nla, u8 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_u8(nla);
+}
+
+/**
* nla_get_u64 - return payload of u64 attribute
* @nla: u64 netlink attribute
*/
@@ -1762,6 +1867,20 @@ static inline u64 nla_get_u64(const struct nlattr *nla)
}
/**
+ * nla_get_u64_default - return payload of u64 attribute or default
+ * @nla: u64 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline u64 nla_get_u64_default(const struct nlattr *nla, u64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_u64(nla);
+}
+
+/**
* nla_get_uint - return payload of uint attribute
* @nla: uint netlink attribute
*/
@@ -1773,6 +1892,20 @@ static inline u64 nla_get_uint(const struct nlattr *nla)
}
/**
+ * nla_get_uint_default - return payload of uint attribute or default
+ * @nla: uint netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline u64 nla_get_uint_default(const struct nlattr *nla, u64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_uint(nla);
+}
+
+/**
* nla_get_be64 - return payload of __be64 attribute
* @nla: __be64 netlink attribute
*/
@@ -1786,6 +1919,21 @@ static inline __be64 nla_get_be64(const struct nlattr *nla)
}
/**
+ * nla_get_be64_default - return payload of be64 attribute or default
+ * @nla: __be64 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __be64 nla_get_be64_default(const struct nlattr *nla,
+ __be64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_be64(nla);
+}
+
+/**
* nla_get_le64 - return payload of __le64 attribute
* @nla: __le64 netlink attribute
*/
@@ -1795,6 +1943,21 @@ static inline __le64 nla_get_le64(const struct nlattr *nla)
}
/**
+ * nla_get_le64_default - return payload of le64 attribute or default
+ * @nla: __le64 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __le64 nla_get_le64_default(const struct nlattr *nla,
+ __le64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_le64(nla);
+}
+
+/**
* nla_get_s32 - return payload of s32 attribute
* @nla: s32 netlink attribute
*/
@@ -1804,6 +1967,20 @@ static inline s32 nla_get_s32(const struct nlattr *nla)
}
/**
+ * nla_get_s32_default - return payload of s32 attribute or default
+ * @nla: s32 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline s32 nla_get_s32_default(const struct nlattr *nla, s32 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_s32(nla);
+}
+
+/**
* nla_get_s16 - return payload of s16 attribute
* @nla: s16 netlink attribute
*/
@@ -1813,6 +1990,20 @@ static inline s16 nla_get_s16(const struct nlattr *nla)
}
/**
+ * nla_get_s16_default - return payload of s16 attribute or default
+ * @nla: s16 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline s16 nla_get_s16_default(const struct nlattr *nla, s16 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_s16(nla);
+}
+
+/**
* nla_get_s8 - return payload of s8 attribute
* @nla: s8 netlink attribute
*/
@@ -1822,6 +2013,20 @@ static inline s8 nla_get_s8(const struct nlattr *nla)
}
/**
+ * nla_get_s8_default - return payload of s8 attribute or default
+ * @nla: s8 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline s8 nla_get_s8_default(const struct nlattr *nla, s8 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_s8(nla);
+}
+
+/**
* nla_get_s64 - return payload of s64 attribute
* @nla: s64 netlink attribute
*/
@@ -1835,6 +2040,20 @@ static inline s64 nla_get_s64(const struct nlattr *nla)
}
/**
+ * nla_get_s64_default - return payload of s64 attribute or default
+ * @nla: s64 netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline s64 nla_get_s64_default(const struct nlattr *nla, s64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_s64(nla);
+}
+
+/**
* nla_get_sint - return payload of uint attribute
* @nla: uint netlink attribute
*/
@@ -1846,6 +2065,20 @@ static inline s64 nla_get_sint(const struct nlattr *nla)
}
/**
+ * nla_get_sint_default - return payload of sint attribute or default
+ * @nla: sint netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline s64 nla_get_sint_default(const struct nlattr *nla, s64 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_sint(nla);
+}
+
+/**
* nla_get_flag - return payload of flag attribute
* @nla: flag netlink attribute
*/
@@ -1868,6 +2101,21 @@ static inline unsigned long nla_get_msecs(const struct nlattr *nla)
}
/**
+ * nla_get_msecs_default - return payload of msecs attribute or default
+ * @nla: msecs netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline unsigned long nla_get_msecs_default(const struct nlattr *nla,
+ unsigned long defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_msecs(nla);
+}
+
+/**
* nla_get_in_addr - return payload of IPv4 address attribute
* @nla: IPv4 address netlink attribute
*/
@@ -1877,6 +2125,21 @@ static inline __be32 nla_get_in_addr(const struct nlattr *nla)
}
/**
+ * nla_get_in_addr_default - return payload of be32 attribute or default
+ * @nla: IPv4 address netlink attribute, may be %NULL
+ * @defvalue: default value to use if @nla is %NULL
+ *
+ * Return: the value of the attribute, or the default value if not present
+ */
+static inline __be32 nla_get_in_addr_default(const struct nlattr *nla,
+ __be32 defvalue)
+{
+ if (!nla)
+ return defvalue;
+ return nla_get_in_addr(nla);
+}
+
+/**
* nla_get_in6_addr - return payload of IPv6 address attribute
* @nla: IPv6 address netlink attribute
*/
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
index dc36519d16aa..09efcaed7c3f 100644
--- a/include/net/nfc/nci.h
+++ b/include/net/nfc/nci.h
@@ -475,7 +475,7 @@ struct nci_rf_discover_ntf {
#define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
struct activation_params_nfca_poll_iso_dep {
__u8 rats_res_len;
- __u8 rats_res[20];
+ __u8 rats_res[NFC_ATS_MAXSIZE];
};
struct activation_params_nfcb_poll_iso_dep {
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index ea8595651c38..e180bdf2f82b 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -265,6 +265,10 @@ struct nci_dev {
/* stored during intf_activated_ntf */
__u8 remote_gb[NFC_MAX_GT_LEN];
__u8 remote_gb_len;
+
+ /* stored during intf_activated_ntf */
+ __u8 target_ats[NFC_ATS_MAXSIZE];
+ __u8 target_ats_len;
};
/* ----- NCI Devices ----- */
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 3a3781838c67..127e6c7d910d 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -86,6 +86,8 @@ struct nfc_ops {
* is a type A one. The %sens_res most significant byte must be byte 2
* as described by the NFC Forum digital specification (i.e. the platform
* configuration one) while %sens_res least significant byte is byte 1.
+ * @ats_len: length of Answer To Select in bytes
+ * @ats: Answer To Select returned by an ISO 14443 Type A target upon activation
*/
struct nfc_target {
u32 idx;
@@ -105,6 +107,8 @@ struct nfc_target {
u8 is_iso15693;
u8 iso15693_dsfid;
u8 iso15693_uid[NFC_ISO15693_UID_MAXSIZE];
+ u8 ats_len;
+ u8 ats[NFC_ATS_MAXSIZE];
};
/**
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 4880b3a7aced..cf199af85c52 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -755,6 +755,7 @@ tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
cls_common->chain_index = tp->chain->index;
cls_common->protocol = tp->protocol;
cls_common->prio = tp->prio >> 16;
+ cls_common->skip_sw = tc_skip_sw(flags);
if (tc_skip_sw(flags) || flags & TCA_CLS_FLAGS_VERBOSE)
cls_common->extack = extack;
}
diff --git a/include/net/route.h b/include/net/route.h
index 586e59f7ed8a..84cb1e04f5cd 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -156,12 +156,12 @@ static inline struct rtable *ip_route_output_key(struct net *net, struct flowi4
* structure is only partially set, it may bypass some fib-rules.
*/
static inline struct rtable *ip_route_output(struct net *net, __be32 daddr,
- __be32 saddr, u8 tos, int oif,
- __u8 scope)
+ __be32 saddr, dscp_t dscp,
+ int oif, __u8 scope)
{
struct flowi4 fl4 = {
.flowi4_oif = oif,
- .flowi4_tos = tos,
+ .flowi4_tos = inet_dscp_to_dsfield(dscp),
.flowi4_scope = scope,
.daddr = daddr,
.saddr = saddr,
@@ -199,30 +199,34 @@ static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4
return ip_route_output_key(net, fl4);
}
-int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev,
- struct in_device *in_dev, u32 *itag);
-int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev);
-int ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+enum skb_drop_reason
+ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
dscp_t dscp, struct net_device *dev,
- const struct sk_buff *hint);
-
-static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
- dscp_t dscp, struct net_device *devin)
+ struct in_device *in_dev, u32 *itag);
+enum skb_drop_reason
+ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev);
+enum skb_drop_reason
+ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev,
+ const struct sk_buff *hint);
+
+static inline enum skb_drop_reason
+ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, dscp_t dscp,
+ struct net_device *devin)
{
- int err;
+ enum skb_drop_reason reason;
rcu_read_lock();
- err = ip_route_input_noref(skb, dst, src, dscp, devin);
- if (!err) {
+ reason = ip_route_input_noref(skb, dst, src, dscp, devin);
+ if (!reason) {
skb_dst_force(skb);
if (!skb_dst(skb))
- err = -EINVAL;
+ reason = SKB_DROP_REASON_NOT_SPECIFIED;
}
rcu_read_unlock();
- return err;
+ return reason;
}
void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif,
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index e0d9a8eae6b6..bc0069a8b6ea 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -12,6 +12,8 @@ typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
enum rtnl_link_flags {
RTNL_FLAG_DOIT_UNLOCKED = BIT(0),
+#define RTNL_FLAG_DOIT_PERNET RTNL_FLAG_DOIT_UNLOCKED
+#define RTNL_FLAG_DOIT_PERNET_WIP RTNL_FLAG_DOIT_UNLOCKED
RTNL_FLAG_BULK_DEL_SUPPORTED = BIT(1),
RTNL_FLAG_DUMP_UNLOCKED = BIT(2),
RTNL_FLAG_DUMP_SPLIT_NLM_DONE = BIT(3), /* legacy behavior */
@@ -70,10 +72,11 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh)
/**
* struct rtnl_link_ops - rtnetlink link operations
*
- * @list: Used internally, protected by RTNL and SRCU
+ * @list: Used internally, protected by link_ops_mutex and SRCU
* @srcu: Used internally
* @kind: Identifier
* @netns_refund: Physical device, move to init_net on netns exit
+ * @peer_type: Peer device specific netlink attribute number (e.g. VETH_INFO_PEER)
* @maxtype: Highest device specific netlink attribute number
* @policy: Netlink policy for device specific attribute validation
* @validate: Optional validation function for netlink/changelink parameters
@@ -115,6 +118,7 @@ struct rtnl_link_ops {
void (*setup)(struct net_device *dev);
bool netns_refund;
+ const u16 peer_type;
unsigned int maxtype;
const struct nla_policy *policy;
int (*validate)(struct nlattr *tb[],
@@ -163,9 +167,6 @@ struct rtnl_link_ops {
int *prividx, int attr);
};
-int __rtnl_link_register(struct rtnl_link_ops *ops);
-void __rtnl_link_unregister(struct rtnl_link_ops *ops);
-
int rtnl_link_register(struct rtnl_link_ops *ops);
void rtnl_link_unregister(struct rtnl_link_ops *ops);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 739a9fb83d0c..e9b37b76e894 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2430,6 +2430,20 @@ void tcp_plb_update_state(const struct sock *sk, struct tcp_plb_state *plb,
void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb);
void tcp_plb_update_state_upon_rto(struct sock *sk, struct tcp_plb_state *plb);
+static inline void tcp_warn_once(const struct sock *sk, bool cond, const char *str)
+{
+ WARN_ONCE(cond,
+ "%scwn:%u out:%u sacked:%u lost:%u retrans:%u tlp_high_seq:%u sk_state:%u ca_state:%u advmss:%u mss_cache:%u pmtu:%u\n",
+ str,
+ tcp_snd_cwnd(tcp_sk(sk)),
+ tcp_sk(sk)->packets_out, tcp_sk(sk)->sacked_out,
+ tcp_sk(sk)->lost_out, tcp_sk(sk)->retrans_out,
+ tcp_sk(sk)->tlp_high_seq, sk->sk_state,
+ inet_csk(sk)->icsk_ca_state,
+ tcp_sk(sk)->advmss, tcp_sk(sk)->mss_cache,
+ inet_csk(sk)->icsk_pmtu_cookie);
+}
+
/* At how many usecs into the future should the RTO fire? */
static inline s64 tcp_rto_delta_us(const struct sock *sk)
{
@@ -2441,17 +2455,7 @@ static inline s64 tcp_rto_delta_us(const struct sock *sk)
return rto_time_stamp_us - tcp_sk(sk)->tcp_mstamp;
} else {
- WARN_ONCE(1,
- "rtx queue empty: "
- "out:%u sacked:%u lost:%u retrans:%u "
- "tlp_high_seq:%u sk_state:%u ca_state:%u "
- "advmss:%u mss_cache:%u pmtu:%u\n",
- tcp_sk(sk)->packets_out, tcp_sk(sk)->sacked_out,
- tcp_sk(sk)->lost_out, tcp_sk(sk)->retrans_out,
- tcp_sk(sk)->tlp_high_seq, sk->sk_state,
- inet_csk(sk)->icsk_ca_state,
- tcp_sk(sk)->advmss, tcp_sk(sk)->mss_cache,
- inet_csk(sk)->icsk_pmtu_cookie);
+ tcp_warn_once(sk, 1, "rtx queue empty: ");
return jiffies_to_usecs(rto);
}
diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h
index 1d46460d0fef..df655ce6987d 100644
--- a/include/net/tcp_ao.h
+++ b/include/net/tcp_ao.h
@@ -183,7 +183,8 @@ int tcp_ao_hash_skb(unsigned short int family,
const u8 *tkey, int hash_offset, u32 sne);
int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family,
sockptr_t optval, int optlen);
-struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao,
+struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk,
+ struct tcp_ao_info *ao,
int sndid, int rcvid);
int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk,
struct request_sock *req, struct sk_buff *skb,
diff --git a/include/net/tls.h b/include/net/tls.h
index 3a33924db2bc..61fef2880114 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -390,8 +390,12 @@ tls_offload_ctx_tx(const struct tls_context *tls_ctx)
static inline bool tls_sw_has_ctx_tx(const struct sock *sk)
{
- struct tls_context *ctx = tls_get_ctx(sk);
+ struct tls_context *ctx;
+
+ if (!sk_is_inet(sk) || !inet_test_bit(IS_ICSK, sk))
+ return false;
+ ctx = tls_get_ctx(sk);
if (!ctx)
return false;
return !!tls_sw_ctx_tx(ctx);
@@ -399,8 +403,12 @@ static inline bool tls_sw_has_ctx_tx(const struct sock *sk)
static inline bool tls_sw_has_ctx_rx(const struct sock *sk)
{
- struct tls_context *ctx = tls_get_ctx(sk);
+ struct tls_context *ctx;
+
+ if (!sk_is_inet(sk) || !inet_test_bit(IS_ICSK, sk))
+ return false;
+ ctx = tls_get_ctx(sk);
if (!ctx)
return false;
return !!tls_sw_ctx_rx(ctx);
diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h
index 0d3d6beb7fdb..7f7a4932d7f1 100644
--- a/include/soc/fsl/qman.h
+++ b/include/soc/fsl/qman.h
@@ -242,7 +242,7 @@ static inline void qm_sg_entry_set_f(struct qm_sg_entry *sg, int len)
static inline int qm_sg_entry_get_off(const struct qm_sg_entry *sg)
{
- return be32_to_cpu(sg->offset) & QM_SG_OFF_MASK;
+ return be16_to_cpu(sg->offset) & QM_SG_OFF_MASK;
}
/* "Frame Dequeue Response" */
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 450c44c83a5d..a0aed1a428a1 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -331,7 +331,11 @@ enum yfs_cm_operation {
EM(afs_edit_dir_delete, "delete") \
EM(afs_edit_dir_delete_error, "d_err ") \
EM(afs_edit_dir_delete_inval, "d_invl") \
- E_(afs_edit_dir_delete_noent, "d_nent")
+ EM(afs_edit_dir_delete_noent, "d_nent") \
+ EM(afs_edit_dir_update_dd, "u_ddot") \
+ EM(afs_edit_dir_update_error, "u_fail") \
+ EM(afs_edit_dir_update_inval, "u_invl") \
+ E_(afs_edit_dir_update_nodd, "u_nodd")
#define afs_edit_dir_reasons \
EM(afs_edit_dir_for_create, "Create") \
@@ -340,6 +344,7 @@ enum yfs_cm_operation {
EM(afs_edit_dir_for_rename_0, "Renam0") \
EM(afs_edit_dir_for_rename_1, "Renam1") \
EM(afs_edit_dir_for_rename_2, "Renam2") \
+ EM(afs_edit_dir_for_rename_sub, "RnmSub") \
EM(afs_edit_dir_for_rmdir, "RmDir ") \
EM(afs_edit_dir_for_silly_0, "S_Ren0") \
EM(afs_edit_dir_for_silly_1, "S_Ren1") \
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index a1b126a6b0d7..d03e0bd8c028 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -287,6 +287,7 @@
EM(rxrpc_call_see_input, "SEE input ") \
EM(rxrpc_call_see_release, "SEE release ") \
EM(rxrpc_call_see_userid_exists, "SEE u-exists") \
+ EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \
E_(rxrpc_call_see_zap, "SEE zap ")
#define rxrpc_txqueue_traces \
@@ -772,6 +773,31 @@ TRACE_EVENT(rxrpc_rx_done,
TP_printk("r=%d a=%d", __entry->result, __entry->abort_code)
);
+TRACE_EVENT(rxrpc_abort_call,
+ TP_PROTO(const struct rxrpc_call *call, int abort_code),
+
+ TP_ARGS(call, abort_code),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, call_nr)
+ __field(enum rxrpc_abort_reason, why)
+ __field(int, abort_code)
+ __field(int, error)
+ ),
+
+ TP_fast_assign(
+ __entry->call_nr = call->debug_id;
+ __entry->why = call->send_abort_why;
+ __entry->abort_code = abort_code;
+ __entry->error = call->send_abort_err;
+ ),
+
+ TP_printk("c=%08x a=%d e=%d %s",
+ __entry->call_nr,
+ __entry->abort_code, __entry->error,
+ __print_symbolic(__entry->why, rxrpc_abort_reasons))
+ );
+
TRACE_EVENT(rxrpc_abort,
TP_PROTO(unsigned int call_nr, enum rxrpc_abort_reason why,
u32 cid, u32 call_id, rxrpc_seq_t seq, int abort_code, int error),
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index e8241b320c6d..4a939c90dc2e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1121,6 +1121,9 @@ enum bpf_attach_type {
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
+/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
+ * in sync with the definitions below.
+ */
enum bpf_link_type {
BPF_LINK_TYPE_UNSPEC = 0,
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h
index b0654ade7b7e..bf97d4b6d51f 100644
--- a/include/uapi/linux/dpll.h
+++ b/include/uapi/linux/dpll.h
@@ -79,6 +79,29 @@ enum dpll_lock_status_error {
DPLL_LOCK_STATUS_ERROR_MAX = (__DPLL_LOCK_STATUS_ERROR_MAX - 1)
};
+/*
+ * level of quality of a clock device. This mainly applies when the dpll
+ * lock-status is DPLL_LOCK_STATUS_HOLDOVER. The current list is defined
+ * according to the table 11-7 contained in ITU-T G.8264/Y.1364 document. One
+ * may extend this list freely by other ITU-T defined clock qualities, or
+ * different ones defined by another standardization body (for those, please
+ * use different prefix).
+ */
+enum dpll_clock_quality_level {
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC = 1,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC,
+ DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC,
+
+ /* private: */
+ __DPLL_CLOCK_QUALITY_LEVEL_MAX,
+ DPLL_CLOCK_QUALITY_LEVEL_MAX = (__DPLL_CLOCK_QUALITY_LEVEL_MAX - 1)
+};
+
#define DPLL_TEMP_DIVIDER 1000
/**
@@ -180,6 +203,7 @@ enum dpll_a {
DPLL_A_TEMP,
DPLL_A_TYPE,
DPLL_A_LOCK_STATUS_ERROR,
+ DPLL_A_CLOCK_QUALITY_LEVEL,
__DPLL_A_MAX,
DPLL_A_MAX = (__DPLL_A_MAX - 1)
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index c405ed63acfa..fc1f54b065f9 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -2511,21 +2511,24 @@ enum ethtool_reset_flags {
* autonegotiation; 0 if unknown or not applicable. Read-only.
*/
struct ethtool_link_settings {
- __u32 cmd;
- __u32 speed;
- __u8 duplex;
- __u8 port;
- __u8 phy_address;
- __u8 autoneg;
- __u8 mdio_support;
- __u8 eth_tp_mdix;
- __u8 eth_tp_mdix_ctrl;
- __s8 link_mode_masks_nwords;
- __u8 transceiver;
- __u8 master_slave_cfg;
- __u8 master_slave_state;
- __u8 rate_matching;
- __u32 reserved[7];
+ /* New members MUST be added within the __struct_group() macro below. */
+ __struct_group(ethtool_link_settings_hdr, hdr, /* no attrs */,
+ __u32 cmd;
+ __u32 speed;
+ __u8 duplex;
+ __u8 port;
+ __u8 phy_address;
+ __u8 autoneg;
+ __u8 mdio_support;
+ __u8 eth_tp_mdix;
+ __u8 eth_tp_mdix_ctrl;
+ __s8 link_mode_masks_nwords;
+ __u8 transceiver;
+ __u8 master_slave_cfg;
+ __u8 master_slave_state;
+ __u8 rate_matching;
+ __u32 reserved[7];
+ );
__u32 link_mode_masks[];
/* layout of link_mode_masks fields:
* __u32 map_supported[link_mode_masks_nwords];
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 8516c1ccd57a..2575e0cd9b48 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1958,6 +1958,7 @@ struct ifla_rmnet_flags {
enum {
IFLA_MCTP_UNSPEC,
IFLA_MCTP_NET,
+ IFLA_MCTP_PHYS_BINDING,
__IFLA_MCTP_MAX,
};
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index e3ebb49f60d2..e4be227d3ad6 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -124,6 +124,7 @@ enum {
NETDEV_A_NAPI_PID,
NETDEV_A_NAPI_DEFER_HARD_IRQS,
NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT,
+ NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT,
__NETDEV_A_NAPI_MAX,
NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1)
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 9e9079321380..49c944e78463 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -564,16 +564,26 @@ enum nft_immediate_attributes {
/**
* enum nft_bitwise_ops - nf_tables bitwise operations
*
- * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and
- * XOR boolean operations
+ * @NFT_BITWISE_MASK_XOR: mask-and-xor operation used to implement NOT, AND, OR
+ * and XOR boolean operations
* @NFT_BITWISE_LSHIFT: left-shift operation
* @NFT_BITWISE_RSHIFT: right-shift operation
+ * @NFT_BITWISE_AND: and operation
+ * @NFT_BITWISE_OR: or operation
+ * @NFT_BITWISE_XOR: xor operation
*/
enum nft_bitwise_ops {
- NFT_BITWISE_BOOL,
+ NFT_BITWISE_MASK_XOR,
NFT_BITWISE_LSHIFT,
NFT_BITWISE_RSHIFT,
+ NFT_BITWISE_AND,
+ NFT_BITWISE_OR,
+ NFT_BITWISE_XOR,
};
+/*
+ * Old name for NFT_BITWISE_MASK_XOR. Retained for backwards-compatibility.
+ */
+#define NFT_BITWISE_BOOL NFT_BITWISE_MASK_XOR
/**
* enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
@@ -586,6 +596,7 @@ enum nft_bitwise_ops {
* @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
* @NFTA_BITWISE_DATA: argument for non-boolean operations
* (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_SREG2: second source register (NLA_U32: nft_registers)
*
* The bitwise expression supports boolean and shift operations. It implements
* the boolean operations by performing the following operation:
@@ -609,6 +620,7 @@ enum nft_bitwise_attributes {
NFTA_BITWISE_XOR,
NFTA_BITWISE_OP,
NFTA_BITWISE_DATA,
+ NFTA_BITWISE_SREG2,
__NFTA_BITWISE_MAX
};
#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 4fa4e979e948..2f5b4be25261 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -164,6 +164,7 @@ enum nfc_commands {
* @NFC_ATTR_VENDOR_SUBCMD: Vendor specific sub command
* @NFC_ATTR_VENDOR_DATA: Vendor specific data, to be optionally passed
* to a vendor specific command implementation
+ * @NFC_ATTR_TARGET_ATS: ISO 14443 type A target Answer To Select
*/
enum nfc_attrs {
NFC_ATTR_UNSPEC,
@@ -198,6 +199,7 @@ enum nfc_attrs {
NFC_ATTR_VENDOR_ID,
NFC_ATTR_VENDOR_SUBCMD,
NFC_ATTR_VENDOR_DATA,
+ NFC_ATTR_TARGET_ATS,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};
@@ -225,6 +227,7 @@ enum nfc_sdp_attr {
#define NFC_GB_MAXSIZE 48
#define NFC_FIRMWARE_NAME_MAXSIZE 32
#define NFC_ISO15693_UID_MAXSIZE 8
+#define NFC_ATS_MAXSIZE 20
/* NFC protocols */
#define NFC_PROTO_JEWEL 1
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f97f5adc8d51..6d11437596b9 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2868,6 +2868,9 @@ enum nl80211_commands {
* nested item, it contains attributes defined in
* &enum nl80211_if_combination_attrs.
*
+ * @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32).
+ * A value of 0 means all radios.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3416,6 +3419,8 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_RADIOS,
NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
+ NL80211_ATTR_VIF_RADIO_MASK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -4698,6 +4703,7 @@ enum nl80211_survey_info {
* overrides all other flags.
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
* and ACK incoming unicast packets.
+ * @NL80211_MNTR_FLAG_SKIP_TX: do not pass local tx packets
*
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -4710,6 +4716,7 @@ enum nl80211_mntr_flags {
NL80211_MNTR_FLAG_OTHER_BSS,
NL80211_MNTR_FLAG_COOK_FRAMES,
NL80211_MNTR_FLAG_ACTIVE,
+ NL80211_MNTR_FLAG_SKIP_TX,
/* keep last */
__NL80211_MNTR_FLAG_AFTER_LAST,
@@ -8031,6 +8038,8 @@ enum nl80211_ap_settings_flags {
* @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
* combination for this radio. Attribute may be present multiple times
* and contains attributes defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK: bitmask (u32) of antennas
+ * connected to this radio.
*
* @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
* @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
@@ -8041,6 +8050,7 @@ enum nl80211_wiphy_radio_attrs {
NL80211_WIPHY_RADIO_ATTR_INDEX,
NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
+ NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
/* keep last */
__NL80211_WIPHY_RADIO_ATTR_LAST,
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 3b687d20c9ed..db7254d52d93 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -174,7 +174,7 @@ enum {
#define RTM_GETLINKPROP RTM_GETLINKPROP
RTM_NEWVLAN = 112,
-#define RTM_NEWNVLAN RTM_NEWVLAN
+#define RTM_NEWVLAN RTM_NEWVLAN
RTM_DELVLAN,
#define RTM_DELVLAN RTM_DELVLAN
RTM_GETVLAN,
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h
index 99333cbd3114..c117672d4439 100644
--- a/include/uapi/sound/asoc.h
+++ b/include/uapi/sound/asoc.h
@@ -88,7 +88,7 @@
/* ABI version */
#define SND_SOC_TPLG_ABI_VERSION 0x5 /* current version */
-#define SND_SOC_TPLG_ABI_VERSION_MIN 0x4 /* oldest version supported */
+#define SND_SOC_TPLG_ABI_VERSION_MIN 0x5 /* oldest version supported */
/* Max size of TLV data */
#define SND_SOC_TPLG_TLV_SIZE 32
diff --git a/include/video/da8xx-fb.h b/include/video/da8xx-fb.h
deleted file mode 100644
index 1d19ae62b844..000000000000
--- a/include/video/da8xx-fb.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Header file for TI DA8XX LCD controller platform data.
- *
- * Copyright (C) 2008-2009 MontaVista Software Inc.
- * Copyright (C) 2008-2009 Texas Instruments Inc
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef DA8XX_FB_H
-#define DA8XX_FB_H
-
-enum panel_shade {
- MONOCHROME = 0,
- COLOR_ACTIVE,
- COLOR_PASSIVE,
-};
-
-enum raster_load_mode {
- LOAD_DATA = 1,
- LOAD_PALETTE,
-};
-
-enum da8xx_frame_complete {
- DA8XX_FRAME_WAIT,
- DA8XX_FRAME_NOWAIT,
-};
-
-struct da8xx_lcdc_platform_data {
- const char manu_name[10];
- void *controller_data;
- const char type[25];
-};
-
-struct lcd_ctrl_config {
- enum panel_shade panel_shade;
-
- /* AC Bias Pin Frequency */
- int ac_bias;
-
- /* AC Bias Pin Transitions per Interrupt */
- int ac_bias_intrpt;
-
- /* DMA burst size */
- int dma_burst_sz;
-
- /* Bits per pixel */
- int bpp;
-
- /* FIFO DMA Request Delay */
- int fdd;
-
- /* TFT Alternative Signal Mapping (Only for active) */
- unsigned char tft_alt_mode;
-
- /* 12 Bit Per Pixel (5-6-5) Mode (Only for passive) */
- unsigned char stn_565_mode;
-
- /* Mono 8-bit Mode: 1=D0-D7 or 0=D0-D3 */
- unsigned char mono_8bit_mode;
-
- /* Horizontal and Vertical Sync Edge: 0=rising 1=falling */
- unsigned char sync_edge;
-
- /* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */
- unsigned char raster_order;
-
- /* DMA FIFO threshold */
- int fifo_th;
-};
-
-struct lcd_sync_arg {
- int back_porch;
- int front_porch;
- int pulse_width;
-};
-
-/* ioctls */
-#define FBIOGET_CONTRAST _IOR('F', 1, int)
-#define FBIOPUT_CONTRAST _IOW('F', 2, int)
-#define FBIGET_BRIGHTNESS _IOR('F', 3, int)
-#define FBIPUT_BRIGHTNESS _IOW('F', 3, int)
-#define FBIGET_COLOR _IOR('F', 5, int)
-#define FBIPUT_COLOR _IOW('F', 6, int)
-#define FBIPUT_HSYNC _IOW('F', 9, int)
-#define FBIPUT_VSYNC _IOW('F', 10, int)
-
-/* Proprietary FB_SYNC_ flags */
-#define FB_SYNC_CLK_INVERT 0x40000000
-
-#endif /* ifndef DA8XX_FB_H */
-
diff --git a/io_uring/rw.c b/io_uring/rw.c
index 354c4e175654..155938f10093 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -1014,6 +1014,25 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
return IOU_OK;
}
+static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb)
+{
+ struct inode *inode;
+ bool ret;
+
+ if (!(req->flags & REQ_F_ISREG))
+ return true;
+ if (!(kiocb->ki_flags & IOCB_NOWAIT)) {
+ kiocb_start_write(kiocb);
+ return true;
+ }
+
+ inode = file_inode(kiocb->ki_filp);
+ ret = sb_start_write_trylock(inode->i_sb);
+ if (ret)
+ __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
+ return ret;
+}
+
int io_write(struct io_kiocb *req, unsigned int issue_flags)
{
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
@@ -1051,8 +1070,8 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
if (unlikely(ret))
return ret;
- if (req->flags & REQ_F_ISREG)
- kiocb_start_write(kiocb);
+ if (unlikely(!io_kiocb_start_write(req, kiocb)))
+ return -EAGAIN;
kiocb->ki_flags |= IOCB_WRITE;
if (likely(req->file->f_op->write_iter))
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index e7113d700b87..025d7e2214ae 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -24,6 +24,23 @@
DEFINE_STATIC_KEY_ARRAY_FALSE(cgroup_bpf_enabled_key, MAX_CGROUP_BPF_ATTACH_TYPE);
EXPORT_SYMBOL(cgroup_bpf_enabled_key);
+/*
+ * cgroup bpf destruction makes heavy use of work items and there can be a lot
+ * of concurrent destructions. Use a separate workqueue so that cgroup bpf
+ * destruction work items don't end up filling up max_active of system_wq
+ * which may lead to deadlock.
+ */
+static struct workqueue_struct *cgroup_bpf_destroy_wq;
+
+static int __init cgroup_bpf_wq_init(void)
+{
+ cgroup_bpf_destroy_wq = alloc_workqueue("cgroup_bpf_destroy", 0, 1);
+ if (!cgroup_bpf_destroy_wq)
+ panic("Failed to alloc workqueue for cgroup bpf destroy.\n");
+ return 0;
+}
+core_initcall(cgroup_bpf_wq_init);
+
/* __always_inline is necessary to prevent indirect call through run_prog
* function pointer.
*/
@@ -334,7 +351,7 @@ static void cgroup_bpf_release_fn(struct percpu_ref *ref)
struct cgroup *cgrp = container_of(ref, struct cgroup, bpf.refcnt);
INIT_WORK(&cgrp->bpf.release_work, cgroup_bpf_release);
- queue_work(system_wq, &cgrp->bpf.release_work);
+ queue_work(cgroup_bpf_destroy_wq, &cgrp->bpf.release_work);
}
/* Get underlying bpf_prog of bpf_prog_list entry, regardless if it's through
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 1a43d06eab28..3d45ebe8afb4 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -111,7 +111,7 @@ const struct bpf_func_proto bpf_map_pop_elem_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
+ .arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
};
BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
@@ -124,7 +124,7 @@ const struct bpf_func_proto bpf_map_peek_elem_proto = {
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_CONST_MAP_PTR,
- .arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
+ .arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
};
BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu)
@@ -538,7 +538,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_CONST_SIZE,
.arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(s64),
};
@@ -566,7 +566,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg2_type = ARG_CONST_SIZE,
.arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
@@ -1742,7 +1742,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
.arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
+ .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
};
BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, const struct bpf_dynptr_kern *, src,
@@ -2851,21 +2851,47 @@ struct bpf_iter_bits {
__u64 __opaque[2];
} __aligned(8);
+#define BITS_ITER_NR_WORDS_MAX 511
+
struct bpf_iter_bits_kern {
union {
- unsigned long *bits;
- unsigned long bits_copy;
+ __u64 *bits;
+ __u64 bits_copy;
};
- u32 nr_bits;
+ int nr_bits;
int bit;
} __aligned(8);
+/* On 64-bit hosts, unsigned long and u64 have the same size, so passing
+ * a u64 pointer and an unsigned long pointer to find_next_bit() will
+ * return the same result, as both point to the same 8-byte area.
+ *
+ * For 32-bit little-endian hosts, using a u64 pointer or unsigned long
+ * pointer also makes no difference. This is because the first iterated
+ * unsigned long is composed of bits 0-31 of the u64 and the second unsigned
+ * long is composed of bits 32-63 of the u64.
+ *
+ * However, for 32-bit big-endian hosts, this is not the case. The first
+ * iterated unsigned long will be bits 32-63 of the u64, so swap these two
+ * ulong values within the u64.
+ */
+static void swap_ulong_in_u64(u64 *bits, unsigned int nr)
+{
+#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ bits[i] = (bits[i] >> 32) | ((u64)(u32)bits[i] << 32);
+#endif
+}
+
/**
* bpf_iter_bits_new() - Initialize a new bits iterator for a given memory area
* @it: The new bpf_iter_bits to be created
* @unsafe_ptr__ign: A pointer pointing to a memory area to be iterated over
* @nr_words: The size of the specified memory area, measured in 8-byte units.
- * Due to the limitation of memalloc, it can't be greater than 512.
+ * The maximum value of @nr_words is @BITS_ITER_NR_WORDS_MAX. This limit may be
+ * further reduced by the BPF memory allocator implementation.
*
* This function initializes a new bpf_iter_bits structure for iterating over
* a memory area which is specified by the @unsafe_ptr__ign and @nr_words. It
@@ -2892,6 +2918,8 @@ bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign, u32 nr_w
if (!unsafe_ptr__ign || !nr_words)
return -EINVAL;
+ if (nr_words > BITS_ITER_NR_WORDS_MAX)
+ return -E2BIG;
/* Optimization for u64 mask */
if (nr_bits == 64) {
@@ -2899,10 +2927,15 @@ bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign, u32 nr_w
if (err)
return -EFAULT;
+ swap_ulong_in_u64(&kit->bits_copy, nr_words);
+
kit->nr_bits = nr_bits;
return 0;
}
+ if (bpf_mem_alloc_check_size(false, nr_bytes))
+ return -E2BIG;
+
/* Fallback to memalloc */
kit->bits = bpf_mem_alloc(&bpf_global_ma, nr_bytes);
if (!kit->bits)
@@ -2914,6 +2947,8 @@ bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign, u32 nr_w
return err;
}
+ swap_ulong_in_u64(kit->bits, nr_words);
+
kit->nr_bits = nr_bits;
return 0;
}
@@ -2930,17 +2965,16 @@ bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign, u32 nr_w
__bpf_kfunc int *bpf_iter_bits_next(struct bpf_iter_bits *it)
{
struct bpf_iter_bits_kern *kit = (void *)it;
- u32 nr_bits = kit->nr_bits;
- const unsigned long *bits;
- int bit;
+ int bit = kit->bit, nr_bits = kit->nr_bits;
+ const void *bits;
- if (nr_bits == 0)
+ if (!nr_bits || bit >= nr_bits)
return NULL;
bits = nr_bits == 64 ? &kit->bits_copy : kit->bits;
- bit = find_next_bit(bits, nr_bits, kit->bit + 1);
+ bit = find_next_bit(bits, nr_bits, bit + 1);
if (bit >= nr_bits) {
- kit->nr_bits = 0;
+ kit->bit = bit;
return NULL;
}
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index d8fc5eba529d..9aaf5124648b 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -880,7 +880,7 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
const struct btf_type *enum_t;
const char *enum_pfx;
u64 *delegate_msk, msk = 0;
- char *p;
+ char *p, *str;
int val;
/* ignore errors, fallback to hex */
@@ -911,7 +911,8 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
return -EINVAL;
}
- while ((p = strsep(&param->string, ":"))) {
+ str = param->string;
+ while ((p = strsep(&str, ":"))) {
if (strcmp(p, "any") == 0) {
msk |= ~0ULL;
} else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) {
diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c
index 0218a5132ab5..9b60eda0f727 100644
--- a/kernel/bpf/lpm_trie.c
+++ b/kernel/bpf/lpm_trie.c
@@ -655,7 +655,7 @@ static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
if (!key || key->prefixlen > trie->max_prefixlen)
goto find_leftmost;
- node_stack = kmalloc_array(trie->max_prefixlen,
+ node_stack = kmalloc_array(trie->max_prefixlen + 1,
sizeof(struct lpm_trie_node *),
GFP_ATOMIC | __GFP_NOWARN);
if (!node_stack)
diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
index b3858a76e0b3..146f5b57cfb1 100644
--- a/kernel/bpf/memalloc.c
+++ b/kernel/bpf/memalloc.c
@@ -35,6 +35,8 @@
*/
#define LLIST_NODE_SZ sizeof(struct llist_node)
+#define BPF_MEM_ALLOC_SIZE_MAX 4096
+
/* similar to kmalloc, but sizeof == 8 bucket is gone */
static u8 size_index[24] __ro_after_init = {
3, /* 8 */
@@ -65,7 +67,7 @@ static u8 size_index[24] __ro_after_init = {
static int bpf_mem_cache_idx(size_t size)
{
- if (!size || size > 4096)
+ if (!size || size > BPF_MEM_ALLOC_SIZE_MAX)
return -1;
if (size <= 192)
@@ -1005,3 +1007,13 @@ void notrace *bpf_mem_cache_alloc_flags(struct bpf_mem_alloc *ma, gfp_t flags)
return !ret ? NULL : ret + LLIST_NODE_SZ;
}
+
+int bpf_mem_alloc_check_size(bool percpu, size_t size)
+{
+ /* The size of percpu allocation doesn't have LLIST_NODE_SZ overhead */
+ if ((percpu && size > BPF_MEM_ALLOC_SIZE_MAX) ||
+ (!percpu && size > BPF_MEM_ALLOC_SIZE_MAX - LLIST_NODE_SZ))
+ return -E2BIG;
+
+ return 0;
+}
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
index de3b681d1d13..e1cfe890e0be 100644
--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -632,7 +632,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {
.arg1_type = ARG_CONST_MAP_PTR,
.arg2_type = ARG_ANYTHING,
.arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT,
+ .arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,
};
BPF_CALL_2(bpf_ringbuf_submit_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 8cfa7183d2ef..c5aa127ed4cc 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3069,13 +3069,17 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
{
const struct bpf_link *link = filp->private_data;
const struct bpf_prog *prog = link->prog;
+ enum bpf_link_type type = link->type;
char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
- seq_printf(m,
- "link_type:\t%s\n"
- "link_id:\t%u\n",
- bpf_link_type_strs[link->type],
- link->id);
+ if (type < ARRAY_SIZE(bpf_link_type_strs) && bpf_link_type_strs[type]) {
+ seq_printf(m, "link_type:\t%s\n", bpf_link_type_strs[type]);
+ } else {
+ WARN_ONCE(1, "missing BPF_LINK_TYPE(...) for link type %u\n", type);
+ seq_printf(m, "link_type:\t<%u>\n", type);
+ }
+ seq_printf(m, "link_id:\t%u\n", link->id);
+
if (prog) {
bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
seq_printf(m,
@@ -5892,7 +5896,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
.arg1_type = ARG_PTR_TO_MEM,
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
.arg3_type = ARG_ANYTHING,
- .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg4_size = sizeof(u64),
};
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 411ab1b57af4..bb99bada7e2e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6804,20 +6804,10 @@ static int check_stack_slot_within_bounds(struct bpf_verifier_env *env,
struct bpf_func_state *state,
enum bpf_access_type t)
{
- struct bpf_insn_aux_data *aux = &env->insn_aux_data[env->insn_idx];
- int min_valid_off, max_bpf_stack;
-
- /* If accessing instruction is a spill/fill from bpf_fastcall pattern,
- * add room for all caller saved registers below MAX_BPF_STACK.
- * In case if bpf_fastcall rewrite won't happen maximal stack depth
- * would be checked by check_max_stack_depth_subprog().
- */
- max_bpf_stack = MAX_BPF_STACK;
- if (aux->fastcall_pattern)
- max_bpf_stack += CALLER_SAVED_REGS * BPF_REG_SIZE;
+ int min_valid_off;
if (t == BPF_WRITE || env->allow_uninit_stack)
- min_valid_off = -max_bpf_stack;
+ min_valid_off = -MAX_BPF_STACK;
else
min_valid_off = -state->allocated_stack;
@@ -7438,7 +7428,8 @@ mark:
}
static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
- int access_size, bool zero_size_allowed,
+ int access_size, enum bpf_access_type access_type,
+ bool zero_size_allowed,
struct bpf_call_arg_meta *meta)
{
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
@@ -7450,7 +7441,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
return check_packet_access(env, regno, reg->off, access_size,
zero_size_allowed);
case PTR_TO_MAP_KEY:
- if (meta && meta->raw_mode) {
+ if (access_type == BPF_WRITE) {
verbose(env, "R%d cannot write into %s\n", regno,
reg_type_str(env, reg->type));
return -EACCES;
@@ -7458,15 +7449,13 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
return check_mem_region_access(env, regno, reg->off, access_size,
reg->map_ptr->key_size, false);
case PTR_TO_MAP_VALUE:
- if (check_map_access_type(env, regno, reg->off, access_size,
- meta && meta->raw_mode ? BPF_WRITE :
- BPF_READ))
+ if (check_map_access_type(env, regno, reg->off, access_size, access_type))
return -EACCES;
return check_map_access(env, regno, reg->off, access_size,
zero_size_allowed, ACCESS_HELPER);
case PTR_TO_MEM:
if (type_is_rdonly_mem(reg->type)) {
- if (meta && meta->raw_mode) {
+ if (access_type == BPF_WRITE) {
verbose(env, "R%d cannot write into %s\n", regno,
reg_type_str(env, reg->type));
return -EACCES;
@@ -7477,7 +7466,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
zero_size_allowed);
case PTR_TO_BUF:
if (type_is_rdonly_mem(reg->type)) {
- if (meta && meta->raw_mode) {
+ if (access_type == BPF_WRITE) {
verbose(env, "R%d cannot write into %s\n", regno,
reg_type_str(env, reg->type));
return -EACCES;
@@ -7505,7 +7494,6 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
* Dynamically check it now.
*/
if (!env->ops->convert_ctx_access) {
- enum bpf_access_type atype = meta && meta->raw_mode ? BPF_WRITE : BPF_READ;
int offset = access_size - 1;
/* Allow zero-byte read from PTR_TO_CTX */
@@ -7513,7 +7501,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
return zero_size_allowed ? 0 : -EACCES;
return check_mem_access(env, env->insn_idx, regno, offset, BPF_B,
- atype, -1, false, false);
+ access_type, -1, false, false);
}
fallthrough;
@@ -7538,6 +7526,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
*/
static int check_mem_size_reg(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, u32 regno,
+ enum bpf_access_type access_type,
bool zero_size_allowed,
struct bpf_call_arg_meta *meta)
{
@@ -7553,15 +7542,12 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
*/
meta->msize_max_value = reg->umax_value;
- /* The register is SCALAR_VALUE; the access check
- * happens using its boundaries.
+ /* The register is SCALAR_VALUE; the access check happens using
+ * its boundaries. For unprivileged variable accesses, disable
+ * raw mode so that the program is required to initialize all
+ * the memory that the helper could just partially fill up.
*/
if (!tnum_is_const(reg->var_off))
- /* For unprivileged variable accesses, disable raw
- * mode so that the program is required to
- * initialize all the memory that the helper could
- * just partially fill up.
- */
meta = NULL;
if (reg->smin_value < 0) {
@@ -7581,9 +7567,8 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
regno);
return -EACCES;
}
- err = check_helper_mem_access(env, regno - 1,
- reg->umax_value,
- zero_size_allowed, meta);
+ err = check_helper_mem_access(env, regno - 1, reg->umax_value,
+ access_type, zero_size_allowed, meta);
if (!err)
err = mark_chain_precision(env, regno);
return err;
@@ -7594,13 +7579,11 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg
{
bool may_be_null = type_may_be_null(reg->type);
struct bpf_reg_state saved_reg;
- struct bpf_call_arg_meta meta;
int err;
if (register_is_null(reg))
return 0;
- memset(&meta, 0, sizeof(meta));
/* Assuming that the register contains a value check if the memory
* access is safe. Temporarily save and restore the register's state as
* the conversion shouldn't be visible to a caller.
@@ -7610,10 +7593,8 @@ static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg
mark_ptr_not_null_reg(reg);
}
- err = check_helper_mem_access(env, regno, mem_size, true, &meta);
- /* Check access for BPF_WRITE */
- meta.raw_mode = true;
- err = err ?: check_helper_mem_access(env, regno, mem_size, true, &meta);
+ err = check_helper_mem_access(env, regno, mem_size, BPF_READ, true, NULL);
+ err = err ?: check_helper_mem_access(env, regno, mem_size, BPF_WRITE, true, NULL);
if (may_be_null)
*reg = saved_reg;
@@ -7639,13 +7620,12 @@ static int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg
mark_ptr_not_null_reg(mem_reg);
}
- err = check_mem_size_reg(env, reg, regno, true, &meta);
- /* Check access for BPF_WRITE */
- meta.raw_mode = true;
- err = err ?: check_mem_size_reg(env, reg, regno, true, &meta);
+ err = check_mem_size_reg(env, reg, regno, BPF_READ, true, &meta);
+ err = err ?: check_mem_size_reg(env, reg, regno, BPF_WRITE, true, &meta);
if (may_be_null)
*mem_reg = saved_reg;
+
return err;
}
@@ -8948,9 +8928,8 @@ skip_type_check:
verbose(env, "invalid map_ptr to access map->key\n");
return -EACCES;
}
- err = check_helper_mem_access(env, regno,
- meta->map_ptr->key_size, false,
- NULL);
+ err = check_helper_mem_access(env, regno, meta->map_ptr->key_size,
+ BPF_READ, false, NULL);
break;
case ARG_PTR_TO_MAP_VALUE:
if (type_may_be_null(arg_type) && register_is_null(reg))
@@ -8965,9 +8944,9 @@ skip_type_check:
return -EACCES;
}
meta->raw_mode = arg_type & MEM_UNINIT;
- err = check_helper_mem_access(env, regno,
- meta->map_ptr->value_size, false,
- meta);
+ err = check_helper_mem_access(env, regno, meta->map_ptr->value_size,
+ arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
+ false, meta);
break;
case ARG_PTR_TO_PERCPU_BTF_ID:
if (!reg->btf_id) {
@@ -9009,7 +8988,9 @@ skip_type_check:
*/
meta->raw_mode = arg_type & MEM_UNINIT;
if (arg_type & MEM_FIXED_SIZE) {
- err = check_helper_mem_access(env, regno, fn->arg_size[arg], false, meta);
+ err = check_helper_mem_access(env, regno, fn->arg_size[arg],
+ arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
+ false, meta);
if (err)
return err;
if (arg_type & MEM_ALIGNED)
@@ -9017,10 +8998,16 @@ skip_type_check:
}
break;
case ARG_CONST_SIZE:
- err = check_mem_size_reg(env, reg, regno, false, meta);
+ err = check_mem_size_reg(env, reg, regno,
+ fn->arg_type[arg - 1] & MEM_WRITE ?
+ BPF_WRITE : BPF_READ,
+ false, meta);
break;
case ARG_CONST_SIZE_OR_ZERO:
- err = check_mem_size_reg(env, reg, regno, true, meta);
+ err = check_mem_size_reg(env, reg, regno,
+ fn->arg_type[arg - 1] & MEM_WRITE ?
+ BPF_WRITE : BPF_READ,
+ true, meta);
break;
case ARG_PTR_TO_DYNPTR:
err = process_dynptr_func(env, regno, insn_idx, arg_type, 0);
@@ -17889,9 +17876,11 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
struct bpf_verifier_state_list *sl, **pprev;
struct bpf_verifier_state *cur = env->cur_state, *new, *loop_entry;
int i, j, n, err, states_cnt = 0;
- bool force_new_state = env->test_state_freq || is_force_checkpoint(env, insn_idx);
- bool add_new_state = force_new_state;
- bool force_exact;
+ bool force_new_state, add_new_state, force_exact;
+
+ force_new_state = env->test_state_freq || is_force_checkpoint(env, insn_idx) ||
+ /* Avoid accumulating infinitely long jmp history */
+ cur->jmp_history_cnt > 40;
/* bpf progs typically have pruning point every 4 instructions
* http://vger.kernel.org/bpfconf2019.html#session-1
@@ -17901,6 +17890,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
* In tests that amounts to up to 50% reduction into total verifier
* memory consumption and 20% verifier time speedup.
*/
+ add_new_state = force_new_state;
if (env->jmps_processed - env->prev_jmps_processed >= 2 &&
env->insn_processed - env->prev_insn_processed >= 8)
add_new_state = true;
@@ -21213,7 +21203,7 @@ patch_map_ops_generic:
delta += cnt - 1;
env->prog = prog = new_prog;
insn = new_prog->insnsi + i + delta;
- continue;
+ goto next_insn;
}
/* Implement bpf_kptr_xchg inline */
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 5886b95c6eae..044c7ba1cc48 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -5789,7 +5789,7 @@ static bool cgroup_check_hierarchy_limits(struct cgroup *parent)
{
struct cgroup *cgroup;
int ret = false;
- int level = 1;
+ int level = 0;
lockdep_assert_held(&cgroup_mutex);
@@ -5797,7 +5797,7 @@ static bool cgroup_check_hierarchy_limits(struct cgroup *parent)
if (cgroup->nr_descendants >= cgroup->max_descendants)
goto fail;
- if (level > cgroup->max_depth)
+ if (level >= cgroup->max_depth)
goto fail;
level++;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index cdd09769e6c5..df27d08a7232 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -13959,7 +13959,7 @@ static void perf_event_clear_cpumask(unsigned int cpu)
}
/* migrate */
- list_for_each_entry_rcu(pmu, &pmus, entry, lockdep_is_held(&pmus_srcu)) {
+ list_for_each_entry(pmu, &pmus, entry) {
if (pmu->scope == PERF_PMU_SCOPE_NONE ||
WARN_ON_ONCE(pmu->scope >= PERF_PMU_MAX_SCOPE))
continue;
diff --git a/kernel/fork.c b/kernel/fork.c
index 89ceb4a68af2..22f43721d031 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -105,6 +105,7 @@
#include <linux/rseq.h>
#include <uapi/linux/pidfd.h>
#include <linux/pidfs.h>
+#include <linux/tick.h>
#include <asm/pgalloc.h>
#include <linux/uaccess.h>
@@ -653,11 +654,6 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
mm->exec_vm = oldmm->exec_vm;
mm->stack_vm = oldmm->stack_vm;
- retval = ksm_fork(mm, oldmm);
- if (retval)
- goto out;
- khugepaged_fork(mm, oldmm);
-
/* Use __mt_dup() to efficiently build an identical maple tree. */
retval = __mt_dup(&oldmm->mm_mt, &mm->mm_mt, GFP_KERNEL);
if (unlikely(retval))
@@ -760,6 +756,8 @@ loop_out:
vma_iter_free(&vmi);
if (!retval) {
mt_set_in_rcu(vmi.mas.tree);
+ ksm_fork(mm, oldmm);
+ khugepaged_fork(mm, oldmm);
} else if (mpnt) {
/*
* The entire maple tree has already been duplicated. If the
@@ -775,7 +773,10 @@ out:
mmap_write_unlock(mm);
flush_tlb_mm(oldmm);
mmap_write_unlock(oldmm);
- dup_userfaultfd_complete(&uf);
+ if (!retval)
+ dup_userfaultfd_complete(&uf);
+ else
+ dup_userfaultfd_fail(&uf);
fail_uprobe_end:
uprobe_end_dup_mmap();
return retval;
@@ -2292,6 +2293,7 @@ __latent_entropy struct task_struct *copy_process(
acct_clear_integrals(p);
posix_cputimers_init(&p->posix_cputimers);
+ tick_dep_init_task(p);
p->io_context = NULL;
audit_set_context(p, NULL);
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 3a24d6b5f559..396a067a8a56 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -718,7 +718,7 @@ static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
if (ret < 0) {
if (ops->msi_free) {
- for (i--; i > 0; i--)
+ for (i--; i >= 0; i--)
ops->msi_free(domain, info, virq + i);
}
irq_domain_free_irqs_top(domain, virq, nr_irqs);
diff --git a/kernel/resource.c b/kernel/resource.c
index b730bd28b422..4101016e8b20 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -459,9 +459,7 @@ int walk_system_ram_res_rev(u64 start, u64 end, void *arg,
rams_size += 16;
}
- rams[i].start = res.start;
- rams[i++].end = res.end;
-
+ rams[i++] = res;
start = res.end + 1;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index dbfb5717d6af..a1c353a62c56 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4711,7 +4711,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
if (rt_prio(p->prio)) {
p->sched_class = &rt_sched_class;
#ifdef CONFIG_SCHED_CLASS_EXT
- } else if (task_should_scx(p)) {
+ } else if (task_should_scx(p->policy)) {
p->sched_class = &ext_sched_class;
#endif
} else {
@@ -5920,12 +5920,15 @@ static void prev_balance(struct rq *rq, struct task_struct *prev,
#ifdef CONFIG_SCHED_CLASS_EXT
/*
- * SCX requires a balance() call before every pick_next_task() including
- * when waking up from SCHED_IDLE. If @start_class is below SCX, start
- * from SCX instead.
+ * SCX requires a balance() call before every pick_task() including when
+ * waking up from SCHED_IDLE. If @start_class is below SCX, start from
+ * SCX instead. Also, set a flag to detect missing balance() call.
*/
- if (scx_enabled() && sched_class_above(&ext_sched_class, start_class))
- start_class = &ext_sched_class;
+ if (scx_enabled()) {
+ rq->scx.flags |= SCX_RQ_BAL_PENDING;
+ if (sched_class_above(&ext_sched_class, start_class))
+ start_class = &ext_sched_class;
+ }
#endif
/*
@@ -7025,7 +7028,7 @@ int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flag
}
EXPORT_SYMBOL(default_wake_function);
-const struct sched_class *__setscheduler_class(struct task_struct *p, int prio)
+const struct sched_class *__setscheduler_class(int policy, int prio)
{
if (dl_prio(prio))
return &dl_sched_class;
@@ -7034,7 +7037,7 @@ const struct sched_class *__setscheduler_class(struct task_struct *p, int prio)
return &rt_sched_class;
#ifdef CONFIG_SCHED_CLASS_EXT
- if (task_should_scx(p))
+ if (task_should_scx(policy))
return &ext_sched_class;
#endif
@@ -7142,7 +7145,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
queue_flag &= ~DEQUEUE_MOVE;
prev_class = p->sched_class;
- next_class = __setscheduler_class(p, prio);
+ next_class = __setscheduler_class(p->policy, prio);
if (prev_class != next_class && p->se.sched_delayed)
dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 5900b06fd036..51b7e04879d7 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -862,7 +862,8 @@ static DEFINE_MUTEX(scx_ops_enable_mutex);
DEFINE_STATIC_KEY_FALSE(__scx_ops_enabled);
DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem);
static atomic_t scx_ops_enable_state_var = ATOMIC_INIT(SCX_OPS_DISABLED);
-static atomic_t scx_ops_bypass_depth = ATOMIC_INIT(0);
+static int scx_ops_bypass_depth;
+static DEFINE_RAW_SPINLOCK(__scx_ops_bypass_lock);
static bool scx_ops_init_task_enabled;
static bool scx_switching_all;
DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
@@ -2633,7 +2634,7 @@ static int balance_one(struct rq *rq, struct task_struct *prev)
lockdep_assert_rq_held(rq);
rq->scx.flags |= SCX_RQ_IN_BALANCE;
- rq->scx.flags &= ~SCX_RQ_BAL_KEEP;
+ rq->scx.flags &= ~(SCX_RQ_BAL_PENDING | SCX_RQ_BAL_KEEP);
if (static_branch_unlikely(&scx_ops_cpu_preempt) &&
unlikely(rq->scx.cpu_released)) {
@@ -2947,12 +2948,11 @@ static struct task_struct *pick_task_scx(struct rq *rq)
{
struct task_struct *prev = rq->curr;
struct task_struct *p;
+ bool prev_on_scx = prev->sched_class == &ext_sched_class;
+ bool keep_prev = rq->scx.flags & SCX_RQ_BAL_KEEP;
+ bool kick_idle = false;
/*
- * If balance_scx() is telling us to keep running @prev, replenish slice
- * if necessary and keep running @prev. Otherwise, pop the first one
- * from the local DSQ.
- *
* WORKAROUND:
*
* %SCX_RQ_BAL_KEEP should be set iff $prev is on SCX as it must just
@@ -2961,22 +2961,41 @@ static struct task_struct *pick_task_scx(struct rq *rq)
* which then ends up calling pick_task_scx() without preceding
* balance_scx().
*
- * For now, ignore cases where $prev is not on SCX. This isn't great and
- * can theoretically lead to stalls. However, for switch_all cases, this
- * happens only while a BPF scheduler is being loaded or unloaded, and,
- * for partial cases, fair will likely keep triggering this CPU.
+ * Keep running @prev if possible and avoid stalling from entering idle
+ * without balancing.
*
- * Once fair is fixed, restore WARN_ON_ONCE().
+ * Once fair is fixed, remove the workaround and trigger WARN_ON_ONCE()
+ * if pick_task_scx() is called without preceding balance_scx().
*/
- if ((rq->scx.flags & SCX_RQ_BAL_KEEP) &&
- prev->sched_class == &ext_sched_class) {
+ if (unlikely(rq->scx.flags & SCX_RQ_BAL_PENDING)) {
+ if (prev_on_scx) {
+ keep_prev = true;
+ } else {
+ keep_prev = false;
+ kick_idle = true;
+ }
+ } else if (unlikely(keep_prev && !prev_on_scx)) {
+ /* only allowed during transitions */
+ WARN_ON_ONCE(scx_ops_enable_state() == SCX_OPS_ENABLED);
+ keep_prev = false;
+ }
+
+ /*
+ * If balance_scx() is telling us to keep running @prev, replenish slice
+ * if necessary and keep running @prev. Otherwise, pop the first one
+ * from the local DSQ.
+ */
+ if (keep_prev) {
p = prev;
if (!p->scx.slice)
p->scx.slice = SCX_SLICE_DFL;
} else {
p = first_local_task(rq);
- if (!p)
+ if (!p) {
+ if (kick_idle)
+ scx_bpf_kick_cpu(cpu_of(rq), SCX_KICK_IDLE);
return NULL;
+ }
if (unlikely(!p->scx.slice)) {
if (!scx_rq_bypassing(rq) && !scx_warned_zero_slice) {
@@ -4256,14 +4275,14 @@ static const struct kset_uevent_ops scx_uevent_ops = {
* Used by sched_fork() and __setscheduler_prio() to pick the matching
* sched_class. dl/rt are already handled.
*/
-bool task_should_scx(struct task_struct *p)
+bool task_should_scx(int policy)
{
if (!scx_enabled() ||
unlikely(scx_ops_enable_state() == SCX_OPS_DISABLING))
return false;
if (READ_ONCE(scx_switching_all))
return true;
- return p->policy == SCHED_EXT;
+ return policy == SCHED_EXT;
}
/**
@@ -4298,18 +4317,20 @@ bool task_should_scx(struct task_struct *p)
*/
static void scx_ops_bypass(bool bypass)
{
- int depth, cpu;
+ int cpu;
+ unsigned long flags;
+ raw_spin_lock_irqsave(&__scx_ops_bypass_lock, flags);
if (bypass) {
- depth = atomic_inc_return(&scx_ops_bypass_depth);
- WARN_ON_ONCE(depth <= 0);
- if (depth != 1)
- return;
+ scx_ops_bypass_depth++;
+ WARN_ON_ONCE(scx_ops_bypass_depth <= 0);
+ if (scx_ops_bypass_depth != 1)
+ goto unlock;
} else {
- depth = atomic_dec_return(&scx_ops_bypass_depth);
- WARN_ON_ONCE(depth < 0);
- if (depth != 0)
- return;
+ scx_ops_bypass_depth--;
+ WARN_ON_ONCE(scx_ops_bypass_depth < 0);
+ if (scx_ops_bypass_depth != 0)
+ goto unlock;
}
/*
@@ -4326,7 +4347,7 @@ static void scx_ops_bypass(bool bypass)
struct rq_flags rf;
struct task_struct *p, *n;
- rq_lock_irqsave(rq, &rf);
+ rq_lock(rq, &rf);
if (bypass) {
WARN_ON_ONCE(rq->scx.flags & SCX_RQ_BYPASSING);
@@ -4362,11 +4383,13 @@ static void scx_ops_bypass(bool bypass)
sched_enq_and_set_task(&ctx);
}
- rq_unlock_irqrestore(rq, &rf);
+ rq_unlock(rq, &rf);
/* resched to restore ticks and idle state */
resched_cpu(cpu);
}
+unlock:
+ raw_spin_unlock_irqrestore(&__scx_ops_bypass_lock, flags);
}
static void free_exit_info(struct scx_exit_info *ei)
@@ -4489,11 +4512,16 @@ static void scx_ops_disable_workfn(struct kthread_work *work)
scx_task_iter_start(&sti);
while ((p = scx_task_iter_next_locked(&sti))) {
const struct sched_class *old_class = p->sched_class;
+ const struct sched_class *new_class =
+ __setscheduler_class(p->policy, p->prio);
struct sched_enq_and_set_ctx ctx;
+ if (old_class != new_class && p->se.sched_delayed)
+ dequeue_task(task_rq(p), p, DEQUEUE_SLEEP | DEQUEUE_DELAYED);
+
sched_deq_and_put_task(p, DEQUEUE_SAVE | DEQUEUE_MOVE, &ctx);
- p->sched_class = __setscheduler_class(p, p->prio);
+ p->sched_class = new_class;
check_class_changing(task_rq(p), p, old_class);
sched_enq_and_set_task(&ctx);
@@ -4969,7 +4997,7 @@ static int scx_ops_enable(struct sched_ext_ops *ops, struct bpf_link *link)
if (!cpumask_equal(housekeeping_cpumask(HK_TYPE_DOMAIN),
cpu_possible_mask)) {
- pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation");
+ pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n");
return -EINVAL;
}
@@ -5199,12 +5227,17 @@ static int scx_ops_enable(struct sched_ext_ops *ops, struct bpf_link *link)
scx_task_iter_start(&sti);
while ((p = scx_task_iter_next_locked(&sti))) {
const struct sched_class *old_class = p->sched_class;
+ const struct sched_class *new_class =
+ __setscheduler_class(p->policy, p->prio);
struct sched_enq_and_set_ctx ctx;
+ if (old_class != new_class && p->se.sched_delayed)
+ dequeue_task(task_rq(p), p, DEQUEUE_SLEEP | DEQUEUE_DELAYED);
+
sched_deq_and_put_task(p, DEQUEUE_SAVE | DEQUEUE_MOVE, &ctx);
p->scx.slice = SCX_SLICE_DFL;
- p->sched_class = __setscheduler_class(p, p->prio);
+ p->sched_class = new_class;
check_class_changing(task_rq(p), p, old_class);
sched_enq_and_set_task(&ctx);
diff --git a/kernel/sched/ext.h b/kernel/sched/ext.h
index 246019519231..b1675bb59fc4 100644
--- a/kernel/sched/ext.h
+++ b/kernel/sched/ext.h
@@ -18,7 +18,7 @@ bool scx_can_stop_tick(struct rq *rq);
void scx_rq_activate(struct rq *rq);
void scx_rq_deactivate(struct rq *rq);
int scx_check_setscheduler(struct task_struct *p, int policy);
-bool task_should_scx(struct task_struct *p);
+bool task_should_scx(int policy);
void init_sched_ext_class(void);
static inline u32 scx_cpuperf_target(s32 cpu)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index c157d4860a3b..2d16c8545c71 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3369,7 +3369,7 @@ retry_pids:
vma = vma_next(&vmi);
}
- do {
+ for (; vma; vma = vma_next(&vmi)) {
if (!vma_migratable(vma) || !vma_policy_mof(vma) ||
is_vm_hugetlb_page(vma) || (vma->vm_flags & VM_MIXEDMAP)) {
trace_sched_skip_vma_numa(mm, vma, NUMAB_SKIP_UNSUITABLE);
@@ -3491,7 +3491,7 @@ retry_pids:
*/
if (vma_pids_forced)
break;
- } for_each_vma(vmi, vma);
+ }
/*
* If no VMAs are remaining and VMAs were skipped due to the PID
@@ -5625,8 +5625,9 @@ pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq)
struct sched_entity *se = pick_eevdf(cfs_rq);
if (se->sched_delayed) {
dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED);
- SCHED_WARN_ON(se->sched_delayed);
- SCHED_WARN_ON(se->on_rq);
+ /*
+ * Must not reference @se again, see __block_task().
+ */
return NULL;
}
return se;
@@ -7176,7 +7177,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags)
/* Fix-up what dequeue_task_fair() skipped */
hrtick_update(rq);
- /* Fix-up what block_task() skipped. */
+ /*
+ * Fix-up what block_task() skipped.
+ *
+ * Must be last, @p might not be valid after this.
+ */
__block_task(rq, p);
}
@@ -7193,12 +7198,14 @@ static bool dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
if (!(p->se.sched_delayed && (task_on_rq_migrating(p) || (flags & DEQUEUE_SAVE))))
util_est_dequeue(&rq->cfs, p);
- if (dequeue_entities(rq, &p->se, flags) < 0) {
- util_est_update(&rq->cfs, p, DEQUEUE_SLEEP);
+ util_est_update(&rq->cfs, p, flags & DEQUEUE_SLEEP);
+ if (dequeue_entities(rq, &p->se, flags) < 0)
return false;
- }
- util_est_update(&rq->cfs, p, flags & DEQUEUE_SLEEP);
+ /*
+ * Must not reference @p after dequeue_entities(DEQUEUE_DELAYED).
+ */
+
hrtick_update(rq);
return true;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 081519ffab46..c03b3d7b320e 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -751,8 +751,9 @@ enum scx_rq_flags {
*/
SCX_RQ_ONLINE = 1 << 0,
SCX_RQ_CAN_STOP_TICK = 1 << 1,
- SCX_RQ_BAL_KEEP = 1 << 2, /* balance decided to keep current */
- SCX_RQ_BYPASSING = 1 << 3,
+ SCX_RQ_BAL_PENDING = 1 << 2, /* balance hasn't run yet */
+ SCX_RQ_BAL_KEEP = 1 << 3, /* balance decided to keep current */
+ SCX_RQ_BYPASSING = 1 << 4,
SCX_RQ_IN_WAKEUP = 1 << 16,
SCX_RQ_IN_BALANCE = 1 << 17,
@@ -2769,8 +2770,6 @@ static inline void sub_nr_running(struct rq *rq, unsigned count)
static inline void __block_task(struct rq *rq, struct task_struct *p)
{
- WRITE_ONCE(p->on_rq, 0);
- ASSERT_EXCLUSIVE_WRITER(p->on_rq);
if (p->sched_contributes_to_load)
rq->nr_uninterruptible++;
@@ -2778,6 +2777,38 @@ static inline void __block_task(struct rq *rq, struct task_struct *p)
atomic_inc(&rq->nr_iowait);
delayacct_blkio_start();
}
+
+ ASSERT_EXCLUSIVE_WRITER(p->on_rq);
+
+ /*
+ * The moment this write goes through, ttwu() can swoop in and migrate
+ * this task, rendering our rq->__lock ineffective.
+ *
+ * __schedule() try_to_wake_up()
+ * LOCK rq->__lock LOCK p->pi_lock
+ * pick_next_task()
+ * pick_next_task_fair()
+ * pick_next_entity()
+ * dequeue_entities()
+ * __block_task()
+ * RELEASE p->on_rq = 0 if (p->on_rq && ...)
+ * break;
+ *
+ * ACQUIRE (after ctrl-dep)
+ *
+ * cpu = select_task_rq();
+ * set_task_cpu(p, cpu);
+ * ttwu_queue()
+ * ttwu_do_activate()
+ * LOCK rq->__lock
+ * activate_task()
+ * STORE p->on_rq = 1
+ * UNLOCK rq->__lock
+ *
+ * Callers must ensure to not reference @p after this -- we no longer
+ * own it.
+ */
+ smp_store_release(&p->on_rq, 0);
}
extern void activate_task(struct rq *rq, struct task_struct *p, int flags);
@@ -3800,7 +3831,7 @@ static inline int rt_effective_prio(struct task_struct *p, int prio)
extern int __sched_setscheduler(struct task_struct *p, const struct sched_attr *attr, bool user, bool pi);
extern int __sched_setaffinity(struct task_struct *p, struct affinity_context *ctx);
-extern const struct sched_class *__setscheduler_class(struct task_struct *p, int prio);
+extern const struct sched_class *__setscheduler_class(int policy, int prio);
extern void set_load_weight(struct task_struct *p, bool update_load);
extern void enqueue_task(struct rq *rq, struct task_struct *p, int flags);
extern bool dequeue_task(struct rq *rq, struct task_struct *p, int flags);
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index 0470bcc3d204..24f9f90b6574 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -707,7 +707,7 @@ change:
}
prev_class = p->sched_class;
- next_class = __setscheduler_class(p, newprio);
+ next_class = __setscheduler_class(policy, newprio);
if (prev_class != next_class && p->se.sched_delayed)
dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
diff --git a/kernel/signal.c b/kernel/signal.c
index 4344860ffcac..cbabb2d05e0a 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -419,7 +419,8 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
*/
rcu_read_lock();
ucounts = task_ucounts(t);
- sigpending = inc_rlimit_get_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING);
+ sigpending = inc_rlimit_get_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING,
+ override_rlimit);
rcu_read_unlock();
if (!sigpending)
return NULL;
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 3bd402fa62a4..630b763e5240 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1202,7 +1202,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u64),
};
@@ -1219,7 +1219,7 @@ static const struct bpf_func_proto bpf_get_func_ret_proto = {
.func = get_func_ret,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
.arg2_size = sizeof(u64),
};
@@ -2216,8 +2216,6 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
old_array = bpf_event_rcu_dereference(event->tp_event->prog_array);
ret = bpf_prog_array_copy(old_array, event->prog, NULL, 0, &new_array);
- if (ret == -ENOENT)
- goto unlock;
if (ret < 0) {
bpf_prog_array_delete_safe(old_array, event->prog);
} else {
diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
index 41e7a15dcb50..69e226a48daa 100644
--- a/kernel/trace/fgraph.c
+++ b/kernel/trace/fgraph.c
@@ -1252,10 +1252,10 @@ int register_ftrace_graph(struct fgraph_ops *gops)
int ret = 0;
int i = -1;
- mutex_lock(&ftrace_lock);
+ guard(mutex)(&ftrace_lock);
if (!fgraph_initialized) {
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "fgraph_idle_init",
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "fgraph:online",
fgraph_cpu_init, NULL);
if (ret < 0) {
pr_warn("fgraph: Error to init cpu hotplug support\n");
@@ -1273,10 +1273,8 @@ int register_ftrace_graph(struct fgraph_ops *gops)
}
i = fgraph_lru_alloc_index();
- if (i < 0 || WARN_ON_ONCE(fgraph_array[i] != &fgraph_stub)) {
- ret = -ENOSPC;
- goto out;
- }
+ if (i < 0 || WARN_ON_ONCE(fgraph_array[i] != &fgraph_stub))
+ return -ENOSPC;
gops->idx = i;
ftrace_graph_active++;
@@ -1313,8 +1311,6 @@ error:
gops->saved_func = NULL;
fgraph_lru_release_index(i);
}
-out:
- mutex_unlock(&ftrace_lock);
return ret;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a8f52b6527ca..2b64b3ec67d9 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5501,6 +5501,10 @@ static const struct file_operations tracing_iter_fops = {
static const char readme_msg[] =
"tracing mini-HOWTO:\n\n"
+ "By default tracefs removes all OTH file permission bits.\n"
+ "When mounting tracefs an optional group id can be specified\n"
+ "which adds the group to every directory and file in tracefs:\n\n"
+ "\t e.g. mount -t tracefs [-o [gid=<gid>]] nodev /sys/kernel/tracing\n\n"
"# echo 0 > tracing_on : quick way to disable tracing\n"
"# echo 1 > tracing_on : quick way to re-enable tracing\n\n"
" Important files:\n"
diff --git a/kernel/ucount.c b/kernel/ucount.c
index 8c07714ff27d..696406939be5 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -307,7 +307,8 @@ void dec_rlimit_put_ucounts(struct ucounts *ucounts, enum rlimit_type type)
do_dec_rlimit_put_ucounts(ucounts, NULL, type);
}
-long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type)
+long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type,
+ bool override_rlimit)
{
/* Caller must hold a reference to ucounts */
struct ucounts *iter;
@@ -317,10 +318,11 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type)
for (iter = ucounts; iter; iter = iter->ns->ucounts) {
long new = atomic_long_add_return(1, &iter->rlimit[type]);
if (new < 0 || new > max)
- goto unwind;
+ goto dec_unwind;
if (iter == ucounts)
ret = new;
- max = get_userns_rlimit_max(iter->ns, type);
+ if (!override_rlimit)
+ max = get_userns_rlimit_max(iter->ns, type);
/*
* Grab an extra ucount reference for the caller when
* the rlimit count was previously 0.
@@ -334,7 +336,6 @@ long inc_rlimit_get_ucounts(struct ucounts *ucounts, enum rlimit_type type)
dec_unwind:
dec = atomic_long_sub_return(1, &iter->rlimit[type]);
WARN_ON_ONCE(dec < 0);
-unwind:
do_dec_rlimit_put_ucounts(ucounts, iter, type);
return 0;
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 7312ae7c3cc5..67b669d2e70e 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2115,6 +2115,16 @@ config FAIL_SUNRPC
Provide fault-injection capability for SunRPC and
its consumers.
+config FAIL_SKB_REALLOC
+ bool "Fault-injection capability forcing skb to reallocate"
+ depends on FAULT_INJECTION_DEBUG_FS
+ help
+ Provide fault-injection capability that forces the skb to be
+ reallocated, catching possible invalid pointers to the skb.
+
+ For more information, check
+ Documentation/dev-tools/fault-injection/fault-injection.rst
+
config FAULT_INJECTION_CONFIGFS
bool "Configfs interface for fault-injection capabilities"
depends on FAULT_INJECTION
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index 233ab2096924..98016e137b7f 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -22,11 +22,8 @@ config ARCH_DISABLE_KASAN_INLINE
config CC_HAS_KASAN_GENERIC
def_bool $(cc-option, -fsanitize=kernel-address)
-# GCC appears to ignore no_sanitize_address when -fsanitize=kernel-hwaddress
-# is passed. See https://bugzilla.kernel.org/show_bug.cgi?id=218854 (and
-# the linked LKML thread) for more details.
config CC_HAS_KASAN_SW_TAGS
- def_bool !CC_IS_GCC && $(cc-option, -fsanitize=kernel-hwaddress)
+ def_bool $(cc-option, -fsanitize=kernel-hwaddress)
# This option is only required for software KASAN modes.
# Old GCC versions do not have proper support for no_sanitize_address.
@@ -101,7 +98,7 @@ config KASAN_SW_TAGS
help
Enables Software Tag-Based KASAN.
- Requires Clang.
+ Requires GCC 11+ or Clang.
Supported only on arm64 CPUs and relies on Top Byte Ignore.
diff --git a/lib/checksum.c b/lib/checksum.c
index 6860d6b05a17..025ba546e1ec 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -34,15 +34,6 @@
#include <asm/byteorder.h>
#ifndef do_csum
-static inline unsigned short from32to16(unsigned int x)
-{
- /* add up 16-bit and 16-bit for 16+c bit */
- x = (x & 0xffff) + (x >> 16);
- /* add up carry.. */
- x = (x & 0xffff) + (x >> 16);
- return x;
-}
-
static unsigned int do_csum(const unsigned char *buff, int len)
{
int odd;
@@ -90,7 +81,7 @@ static unsigned int do_csum(const unsigned char *buff, int len)
#else
result += (*buff << 8);
#endif
- result = from32to16(result);
+ result = csum_from32to16(result);
if (odd)
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
out:
diff --git a/lib/dim/dim.c b/lib/dim/dim.c
index 83b65ac74d73..97c3d084ebf0 100644
--- a/lib/dim/dim.c
+++ b/lib/dim/dim.c
@@ -54,7 +54,8 @@ void dim_park_tired(struct dim *dim)
}
EXPORT_SYMBOL(dim_park_tired);
-bool dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
+bool dim_calc_stats(const struct dim_sample *start,
+ const struct dim_sample *end,
struct dim_stats *curr_stats)
{
/* u32 holds up to 71 minutes, should be enough */
diff --git a/lib/dim/net_dim.c b/lib/dim/net_dim.c
index d7e7028e9b19..d6aa09a979b3 100644
--- a/lib/dim/net_dim.c
+++ b/lib/dim/net_dim.c
@@ -347,7 +347,7 @@ static bool net_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
return dim->profile_ix != prev_ix;
}
-void net_dim(struct dim *dim, struct dim_sample end_sample)
+void net_dim(struct dim *dim, const struct dim_sample *end_sample)
{
struct dim_stats curr_stats;
u16 nevents;
@@ -355,11 +355,11 @@ void net_dim(struct dim *dim, struct dim_sample end_sample)
switch (dim->state) {
case DIM_MEASURE_IN_PROGRESS:
nevents = BIT_GAP(BITS_PER_TYPE(u16),
- end_sample.event_ctr,
+ end_sample->event_ctr,
dim->start_sample.event_ctr);
if (nevents < DIM_NEVENTS)
break;
- if (!dim_calc_stats(&dim->start_sample, &end_sample, &curr_stats))
+ if (!dim_calc_stats(&dim->start_sample, end_sample, &curr_stats))
break;
if (net_dim_decision(&curr_stats, dim)) {
dim->state = DIM_APPLY_NEW_PROFILE;
@@ -368,8 +368,8 @@ void net_dim(struct dim *dim, struct dim_sample end_sample)
}
fallthrough;
case DIM_START_MEASURE:
- dim_update_sample(end_sample.event_ctr, end_sample.pkt_ctr,
- end_sample.byte_ctr, &dim->start_sample);
+ dim_update_sample(end_sample->event_ctr, end_sample->pkt_ctr,
+ end_sample->byte_ctr, &dim->start_sample);
dim->state = DIM_MEASURE_IN_PROGRESS;
break;
case DIM_APPLY_NEW_PROFILE:
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
index e49deddd3de9..c1b7638a594a 100644
--- a/lib/dynamic_queue_limits.c
+++ b/lib/dynamic_queue_limits.c
@@ -179,7 +179,7 @@ void dql_completed(struct dql *dql, unsigned int count)
dql->adj_limit = limit + completed;
dql->prev_ovlimit = ovlimit;
- dql->prev_last_obj_cnt = dql->last_obj_cnt;
+ dql->prev_last_obj_cnt = READ_ONCE(dql->last_obj_cnt);
dql->num_completed = completed;
dql->prev_num_queued = num_queued;
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 1abb32c0da50..908e75a28d90 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -461,6 +461,8 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
size_t bytes, struct iov_iter *i)
{
size_t n, copied = 0;
+ bool uses_kmap = IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) ||
+ PageHighMem(page);
if (!page_copy_sane(page, offset, bytes))
return 0;
@@ -471,7 +473,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
char *p;
n = bytes - copied;
- if (PageHighMem(page)) {
+ if (uses_kmap) {
page += offset / PAGE_SIZE;
offset %= PAGE_SIZE;
n = min_t(size_t, n, PAGE_SIZE - offset);
@@ -482,7 +484,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
kunmap_atomic(p);
copied += n;
offset += n;
- } while (PageHighMem(page) && copied != bytes && n > 0);
+ } while (uses_kmap && copied != bytes && n > 0);
return copied;
}
@@ -1021,15 +1023,18 @@ static ssize_t iter_folioq_get_pages(struct iov_iter *iter,
size_t offset = iov_offset, fsize = folioq_folio_size(folioq, slot);
size_t part = PAGE_SIZE - offset % PAGE_SIZE;
- part = umin(part, umin(maxsize - extracted, fsize - offset));
- count -= part;
- iov_offset += part;
- extracted += part;
+ if (offset < fsize) {
+ part = umin(part, umin(maxsize - extracted, fsize - offset));
+ count -= part;
+ iov_offset += part;
+ extracted += part;
+
+ *pages = folio_page(folio, offset / PAGE_SIZE);
+ get_page(*pages);
+ pages++;
+ maxpages--;
+ }
- *pages = folio_page(folio, offset / PAGE_SIZE);
- get_page(*pages);
- pages++;
- maxpages--;
if (maxpages == 0 || extracted >= maxsize)
break;
diff --git a/lib/objpool.c b/lib/objpool.c
index fd108fe0d095..b998b720c732 100644
--- a/lib/objpool.c
+++ b/lib/objpool.c
@@ -74,15 +74,21 @@ objpool_init_percpu_slots(struct objpool_head *pool, int nr_objs,
* warm caches and TLB hits. in default vmalloc is used to
* reduce the pressure of kernel slab system. as we know,
* mimimal size of vmalloc is one page since vmalloc would
- * always align the requested size to page size
+ * always align the requested size to page size.
+ * but if vmalloc fails or it is not available (e.g. GFP_ATOMIC)
+ * allocate percpu slot with kmalloc.
*/
- if ((pool->gfp & GFP_ATOMIC) == GFP_ATOMIC)
- slot = kmalloc_node(size, pool->gfp, cpu_to_node(i));
- else
+ slot = NULL;
+
+ if ((pool->gfp & (GFP_ATOMIC | GFP_KERNEL)) != GFP_ATOMIC)
slot = __vmalloc_node(size, sizeof(void *), pool->gfp,
cpu_to_node(i), __builtin_return_address(0));
- if (!slot)
- return -ENOMEM;
+
+ if (!slot) {
+ slot = kmalloc_node(size, pool->gfp, cpu_to_node(i));
+ if (!slot)
+ return -ENOMEM;
+ }
memset(slot, 0, size);
pool->cpu_slots[i] = slot;
diff --git a/lib/slub_kunit.c b/lib/slub_kunit.c
index 80e39f003344..33564f965958 100644
--- a/lib/slub_kunit.c
+++ b/lib/slub_kunit.c
@@ -141,7 +141,7 @@ static void test_kmalloc_redzone_access(struct kunit *test)
{
struct kmem_cache *s = test_kmem_cache_create("TestSlub_RZ_kmalloc", 32,
SLAB_KMALLOC|SLAB_STORE_USER|SLAB_RED_ZONE);
- u8 *p = __kmalloc_cache_noprof(s, GFP_KERNEL, 18);
+ u8 *p = alloc_hooks(__kmalloc_cache_noprof(s, GFP_KERNEL, 18));
kasan_disable_current();
diff --git a/mm/Kconfig b/mm/Kconfig
index 4c9f5ea13271..33fa51d608dc 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1085,7 +1085,6 @@ config HMM_MIRROR
depends on MMU
config GET_FREE_REGION
- depends on SPARSEMEM
bool
config DEVICE_PRIVATE
diff --git a/mm/Makefile b/mm/Makefile
index d5639b036166..dba52bb0da8a 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -65,6 +65,7 @@ page-alloc-$(CONFIG_SHUFFLE_PAGE_ALLOCATOR) += shuffle.o
memory-hotplug-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-y += page-alloc.o
+obj-y += page_frag_cache.o
obj-y += init-mm.o
obj-y += memblock.o
obj-y += $(memory-hotplug-y)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index a83f3b736d51..511c3f61ab44 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1412,7 +1412,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
damon_for_each_scheme(s, c) {
struct damos_quota *quota = &s->quota;
- if (c->passed_sample_intervals != s->next_apply_sis)
+ if (c->passed_sample_intervals < s->next_apply_sis)
continue;
if (!s->wmarks.activated)
@@ -1456,17 +1456,31 @@ static unsigned long damon_feed_loop_next_input(unsigned long last_input,
unsigned long score)
{
const unsigned long goal = 10000;
- unsigned long score_goal_diff = max(goal, score) - min(goal, score);
- unsigned long score_goal_diff_bp = score_goal_diff * 10000 / goal;
- unsigned long compensation = last_input * score_goal_diff_bp / 10000;
/* Set minimum input as 10000 to avoid compensation be zero */
const unsigned long min_input = 10000;
+ unsigned long score_goal_diff, compensation;
+ bool over_achieving = score > goal;
- if (goal > score)
+ if (score == goal)
+ return last_input;
+ if (score >= goal * 2)
+ return min_input;
+
+ if (over_achieving)
+ score_goal_diff = score - goal;
+ else
+ score_goal_diff = goal - score;
+
+ if (last_input < ULONG_MAX / score_goal_diff)
+ compensation = last_input * score_goal_diff / goal;
+ else
+ compensation = last_input / goal * score_goal_diff;
+
+ if (over_achieving)
+ return max(last_input - compensation, min_input);
+ if (last_input < ULONG_MAX - compensation)
return last_input + compensation;
- if (last_input > compensation + min_input)
- return last_input - compensation;
- return min_input;
+ return ULONG_MAX;
}
#ifdef CONFIG_PSI
@@ -1622,7 +1636,7 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
bool has_schemes_to_apply = false;
damon_for_each_scheme(s, c) {
- if (c->passed_sample_intervals != s->next_apply_sis)
+ if (c->passed_sample_intervals < s->next_apply_sis)
continue;
if (!s->wmarks.activated)
@@ -1642,9 +1656,9 @@ static void kdamond_apply_schemes(struct damon_ctx *c)
}
damon_for_each_scheme(s, c) {
- if (c->passed_sample_intervals != s->next_apply_sis)
+ if (c->passed_sample_intervals < s->next_apply_sis)
continue;
- s->next_apply_sis +=
+ s->next_apply_sis = c->passed_sample_intervals +
(s->apply_interval_us ? s->apply_interval_us :
c->attrs.aggr_interval) / sample_interval;
}
@@ -2000,7 +2014,7 @@ static int kdamond_fn(void *data)
if (ctx->ops.check_accesses)
max_nr_accesses = ctx->ops.check_accesses(ctx);
- if (ctx->passed_sample_intervals == next_aggregation_sis) {
+ if (ctx->passed_sample_intervals >= next_aggregation_sis) {
kdamond_merge_regions(ctx,
max_nr_accesses / 10,
sz_limit);
@@ -2018,7 +2032,7 @@ static int kdamond_fn(void *data)
sample_interval = ctx->attrs.sample_interval ?
ctx->attrs.sample_interval : 1;
- if (ctx->passed_sample_intervals == next_aggregation_sis) {
+ if (ctx->passed_sample_intervals >= next_aggregation_sis) {
ctx->next_aggregation_sis = next_aggregation_sis +
ctx->attrs.aggr_interval / sample_interval;
@@ -2028,7 +2042,7 @@ static int kdamond_fn(void *data)
ctx->ops.reset_aggregated(ctx);
}
- if (ctx->passed_sample_intervals == next_ops_update_sis) {
+ if (ctx->passed_sample_intervals >= next_ops_update_sis) {
ctx->next_ops_update_sis = next_ops_update_sis +
ctx->attrs.ops_update_interval /
sample_interval;
diff --git a/mm/filemap.c b/mm/filemap.c
index 36d22968be9a..56fa431c52af 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2625,7 +2625,7 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
if (unlikely(!iov_iter_count(iter)))
return 0;
- iov_iter_truncate(iter, inode->i_sb->s_maxbytes);
+ iov_iter_truncate(iter, inode->i_sb->s_maxbytes - iocb->ki_pos);
folio_batch_init(&fbatch);
do {
diff --git a/mm/gup.c b/mm/gup.c
index a82890b46a36..ad0c8922dac3 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -2273,20 +2273,57 @@ struct page *get_dump_page(unsigned long addr)
#endif /* CONFIG_ELF_CORE */
#ifdef CONFIG_MIGRATION
+
+/*
+ * An array of either pages or folios ("pofs"). Although it may seem tempting to
+ * avoid this complication, by simply interpreting a list of folios as a list of
+ * pages, that approach won't work in the longer term, because eventually the
+ * layouts of struct page and struct folio will become completely different.
+ * Furthermore, this pof approach avoids excessive page_folio() calls.
+ */
+struct pages_or_folios {
+ union {
+ struct page **pages;
+ struct folio **folios;
+ void **entries;
+ };
+ bool has_folios;
+ long nr_entries;
+};
+
+static struct folio *pofs_get_folio(struct pages_or_folios *pofs, long i)
+{
+ if (pofs->has_folios)
+ return pofs->folios[i];
+ return page_folio(pofs->pages[i]);
+}
+
+static void pofs_clear_entry(struct pages_or_folios *pofs, long i)
+{
+ pofs->entries[i] = NULL;
+}
+
+static void pofs_unpin(struct pages_or_folios *pofs)
+{
+ if (pofs->has_folios)
+ unpin_folios(pofs->folios, pofs->nr_entries);
+ else
+ unpin_user_pages(pofs->pages, pofs->nr_entries);
+}
+
/*
* Returns the number of collected folios. Return value is always >= 0.
*/
static unsigned long collect_longterm_unpinnable_folios(
- struct list_head *movable_folio_list,
- unsigned long nr_folios,
- struct folio **folios)
+ struct list_head *movable_folio_list,
+ struct pages_or_folios *pofs)
{
unsigned long i, collected = 0;
struct folio *prev_folio = NULL;
bool drain_allow = true;
- for (i = 0; i < nr_folios; i++) {
- struct folio *folio = folios[i];
+ for (i = 0; i < pofs->nr_entries; i++) {
+ struct folio *folio = pofs_get_folio(pofs, i);
if (folio == prev_folio)
continue;
@@ -2327,16 +2364,15 @@ static unsigned long collect_longterm_unpinnable_folios(
* Returns -EAGAIN if all folios were successfully migrated or -errno for
* failure (or partial success).
*/
-static int migrate_longterm_unpinnable_folios(
- struct list_head *movable_folio_list,
- unsigned long nr_folios,
- struct folio **folios)
+static int
+migrate_longterm_unpinnable_folios(struct list_head *movable_folio_list,
+ struct pages_or_folios *pofs)
{
int ret;
unsigned long i;
- for (i = 0; i < nr_folios; i++) {
- struct folio *folio = folios[i];
+ for (i = 0; i < pofs->nr_entries; i++) {
+ struct folio *folio = pofs_get_folio(pofs, i);
if (folio_is_device_coherent(folio)) {
/*
@@ -2344,7 +2380,7 @@ static int migrate_longterm_unpinnable_folios(
* convert the pin on the source folio to a normal
* reference.
*/
- folios[i] = NULL;
+ pofs_clear_entry(pofs, i);
folio_get(folio);
gup_put_folio(folio, 1, FOLL_PIN);
@@ -2363,8 +2399,8 @@ static int migrate_longterm_unpinnable_folios(
* calling folio_isolate_lru() which takes a reference so the
* folio won't be freed if it's migrating.
*/
- unpin_folio(folios[i]);
- folios[i] = NULL;
+ unpin_folio(folio);
+ pofs_clear_entry(pofs, i);
}
if (!list_empty(movable_folio_list)) {
@@ -2387,66 +2423,73 @@ static int migrate_longterm_unpinnable_folios(
return -EAGAIN;
err:
- unpin_folios(folios, nr_folios);
+ pofs_unpin(pofs);
putback_movable_pages(movable_folio_list);
return ret;
}
+static long
+check_and_migrate_movable_pages_or_folios(struct pages_or_folios *pofs)
+{
+ LIST_HEAD(movable_folio_list);
+ unsigned long collected;
+
+ collected = collect_longterm_unpinnable_folios(&movable_folio_list,
+ pofs);
+ if (!collected)
+ return 0;
+
+ return migrate_longterm_unpinnable_folios(&movable_folio_list, pofs);
+}
+
/*
- * Check whether all folios are *allowed* to be pinned indefinitely (longterm).
+ * Check whether all folios are *allowed* to be pinned indefinitely (long term).
* Rather confusingly, all folios in the range are required to be pinned via
* FOLL_PIN, before calling this routine.
*
- * If any folios in the range are not allowed to be pinned, then this routine
- * will migrate those folios away, unpin all the folios in the range and return
- * -EAGAIN. The caller should re-pin the entire range with FOLL_PIN and then
- * call this routine again.
+ * Return values:
*
- * If an error other than -EAGAIN occurs, this indicates a migration failure.
- * The caller should give up, and propagate the error back up the call stack.
- *
- * If everything is OK and all folios in the range are allowed to be pinned,
+ * 0: if everything is OK and all folios in the range are allowed to be pinned,
* then this routine leaves all folios pinned and returns zero for success.
+ *
+ * -EAGAIN: if any folios in the range are not allowed to be pinned, then this
+ * routine will migrate those folios away, unpin all the folios in the range. If
+ * migration of the entire set of folios succeeds, then -EAGAIN is returned. The
+ * caller should re-pin the entire range with FOLL_PIN and then call this
+ * routine again.
+ *
+ * -ENOMEM, or any other -errno: if an error *other* than -EAGAIN occurs, this
+ * indicates a migration failure. The caller should give up, and propagate the
+ * error back up the call stack. The caller does not need to unpin any folios in
+ * that case, because this routine will do the unpinning.
*/
static long check_and_migrate_movable_folios(unsigned long nr_folios,
struct folio **folios)
{
- unsigned long collected;
- LIST_HEAD(movable_folio_list);
+ struct pages_or_folios pofs = {
+ .folios = folios,
+ .has_folios = true,
+ .nr_entries = nr_folios,
+ };
- collected = collect_longterm_unpinnable_folios(&movable_folio_list,
- nr_folios, folios);
- if (!collected)
- return 0;
-
- return migrate_longterm_unpinnable_folios(&movable_folio_list,
- nr_folios, folios);
+ return check_and_migrate_movable_pages_or_folios(&pofs);
}
/*
- * This routine just converts all the pages in the @pages array to folios and
- * calls check_and_migrate_movable_folios() to do the heavy lifting.
- *
- * Please see the check_and_migrate_movable_folios() documentation for details.
+ * Return values and behavior are the same as those for
+ * check_and_migrate_movable_folios().
*/
static long check_and_migrate_movable_pages(unsigned long nr_pages,
struct page **pages)
{
- struct folio **folios;
- long i, ret;
+ struct pages_or_folios pofs = {
+ .pages = pages,
+ .has_folios = false,
+ .nr_entries = nr_pages,
+ };
- folios = kmalloc_array(nr_pages, sizeof(*folios), GFP_KERNEL);
- if (!folios)
- return -ENOMEM;
-
- for (i = 0; i < nr_pages; i++)
- folios[i] = page_folio(pages[i]);
-
- ret = check_and_migrate_movable_folios(nr_pages, folios);
-
- kfree(folios);
- return ret;
+ return check_and_migrate_movable_pages_or_folios(&pofs);
}
#else
static long check_and_migrate_movable_pages(unsigned long nr_pages,
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2fb328880b50..5734d5d5060f 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3588,10 +3588,27 @@ int split_folio_to_list(struct folio *folio, struct list_head *list)
return split_huge_page_to_list_to_order(&folio->page, list, ret);
}
-void __folio_undo_large_rmappable(struct folio *folio)
+/*
+ * __folio_unqueue_deferred_split() is not to be called directly:
+ * the folio_unqueue_deferred_split() inline wrapper in mm/internal.h
+ * limits its calls to those folios which may have a _deferred_list for
+ * queueing THP splits, and that list is (racily observed to be) non-empty.
+ *
+ * It is unsafe to call folio_unqueue_deferred_split() until folio refcount is
+ * zero: because even when split_queue_lock is held, a non-empty _deferred_list
+ * might be in use on deferred_split_scan()'s unlocked on-stack list.
+ *
+ * If memory cgroups are enabled, split_queue_lock is in the mem_cgroup: it is
+ * therefore important to unqueue deferred split before changing folio memcg.
+ */
+bool __folio_unqueue_deferred_split(struct folio *folio)
{
struct deferred_split *ds_queue;
unsigned long flags;
+ bool unqueued = false;
+
+ WARN_ON_ONCE(folio_ref_count(folio));
+ WARN_ON_ONCE(!mem_cgroup_disabled() && !folio_memcg(folio));
ds_queue = get_deferred_split_queue(folio);
spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
@@ -3603,8 +3620,11 @@ void __folio_undo_large_rmappable(struct folio *folio)
MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1);
}
list_del_init(&folio->_deferred_list);
+ unqueued = true;
}
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
+
+ return unqueued; /* useful for debug warnings */
}
/* partially_mapped=false won't clear PG_partially_mapped folio flag */
@@ -3627,14 +3647,11 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped)
return;
/*
- * The try_to_unmap() in page reclaim path might reach here too,
- * this may cause a race condition to corrupt deferred split queue.
- * And, if page reclaim is already handling the same folio, it is
- * unnecessary to handle it again in shrinker.
- *
- * Check the swapcache flag to determine if the folio is being
- * handled by page reclaim since THP swap would add the folio into
- * swap cache before calling try_to_unmap().
+ * Exclude swapcache: originally to avoid a corrupt deferred split
+ * queue. Nowadays that is fully prevented by mem_cgroup_swapout();
+ * but if page reclaim is already handling the same folio, it is
+ * unnecessary to handle it again in the shrinker, so excluding
+ * swapcache here may still be a useful optimization.
*/
if (folio_test_swapcache(folio))
return;
@@ -3718,8 +3735,8 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
struct deferred_split *ds_queue = &pgdata->deferred_split_queue;
unsigned long flags;
LIST_HEAD(list);
- struct folio *folio, *next;
- int split = 0;
+ struct folio *folio, *next, *prev = NULL;
+ int split = 0, removed = 0;
#ifdef CONFIG_MEMCG
if (sc->memcg)
@@ -3773,17 +3790,32 @@ next:
* in the case it was underused, then consider it used and
* don't add it back to split_queue.
*/
- if (!did_split && !folio_test_partially_mapped(folio)) {
+ if (did_split) {
+ ; /* folio already removed from list */
+ } else if (!folio_test_partially_mapped(folio)) {
list_del_init(&folio->_deferred_list);
- ds_queue->split_queue_len--;
+ removed++;
+ } else {
+ /*
+ * That unlocked list_del_init() above would be unsafe,
+ * unless its folio is separated from any earlier folios
+ * left on the list (which may be concurrently unqueued)
+ * by one safe folio with refcount still raised.
+ */
+ swap(folio, prev);
}
- folio_put(folio);
+ if (folio)
+ folio_put(folio);
}
spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
list_splice_tail(&list, &ds_queue->split_queue);
+ ds_queue->split_queue_len -= removed;
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
+ if (prev)
+ folio_put(prev);
+
/*
* Stop shrinker if we didn't split any page, but the queue is empty.
* This can happen if pages were freed under us.
diff --git a/mm/internal.h b/mm/internal.h
index 93083bbeeefa..64c2eb0b160e 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -108,6 +108,51 @@ static inline void *folio_raw_mapping(const struct folio *folio)
return (void *)(mapping & ~PAGE_MAPPING_FLAGS);
}
+/*
+ * This is a file-backed mapping, and is about to be memory mapped - invoke its
+ * mmap hook and safely handle error conditions. On error, VMA hooks will be
+ * mutated.
+ *
+ * @file: File which backs the mapping.
+ * @vma: VMA which we are mapping.
+ *
+ * Returns: 0 if success, error otherwise.
+ */
+static inline int mmap_file(struct file *file, struct vm_area_struct *vma)
+{
+ int err = call_mmap(file, vma);
+
+ if (likely(!err))
+ return 0;
+
+ /*
+ * OK, we tried to call the file hook for mmap(), but an error
+ * arose. The mapping is in an inconsistent state and we most not invoke
+ * any further hooks on it.
+ */
+ vma->vm_ops = &vma_dummy_vm_ops;
+
+ return err;
+}
+
+/*
+ * If the VMA has a close hook then close it, and since closing it might leave
+ * it in an inconsistent state which makes the use of any hooks suspect, clear
+ * them down by installing dummy empty hooks.
+ */
+static inline void vma_close(struct vm_area_struct *vma)
+{
+ if (vma->vm_ops && vma->vm_ops->close) {
+ vma->vm_ops->close(vma);
+
+ /*
+ * The mapping is in an inconsistent state, and no further hooks
+ * may be invoked upon it.
+ */
+ vma->vm_ops = &vma_dummy_vm_ops;
+ }
+}
+
#ifdef CONFIG_MMU
/* Flags for folio_pte_batch(). */
@@ -639,11 +684,11 @@ static inline void folio_set_order(struct folio *folio, unsigned int order)
#endif
}
-void __folio_undo_large_rmappable(struct folio *folio);
-static inline void folio_undo_large_rmappable(struct folio *folio)
+bool __folio_unqueue_deferred_split(struct folio *folio);
+static inline bool folio_unqueue_deferred_split(struct folio *folio)
{
if (folio_order(folio) <= 1 || !folio_test_large_rmappable(folio))
- return;
+ return false;
/*
* At this point, there is no one trying to add the folio to
@@ -651,9 +696,9 @@ static inline void folio_undo_large_rmappable(struct folio *folio)
* to check without acquiring the split_queue_lock.
*/
if (data_race(list_empty(&folio->_deferred_list)))
- return;
+ return false;
- __folio_undo_large_rmappable(folio);
+ return __folio_unqueue_deferred_split(folio);
}
static inline struct folio *page_rmappable_folio(struct page *page)
diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
index a181e4780d9d..d8fb281e439d 100644
--- a/mm/kasan/kasan_test_c.c
+++ b/mm/kasan/kasan_test_c.c
@@ -1810,32 +1810,6 @@ static void vm_map_ram_tags(struct kunit *test)
free_pages((unsigned long)p_ptr, 1);
}
-static void vmalloc_percpu(struct kunit *test)
-{
- char __percpu *ptr;
- int cpu;
-
- /*
- * This test is specifically crafted for the software tag-based mode,
- * the only tag-based mode that poisons percpu mappings.
- */
- KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_SW_TAGS);
-
- ptr = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
-
- for_each_possible_cpu(cpu) {
- char *c_ptr = per_cpu_ptr(ptr, cpu);
-
- KUNIT_EXPECT_GE(test, (u8)get_tag(c_ptr), (u8)KASAN_TAG_MIN);
- KUNIT_EXPECT_LT(test, (u8)get_tag(c_ptr), (u8)KASAN_TAG_KERNEL);
-
- /* Make sure that in-bounds accesses don't crash the kernel. */
- *c_ptr = 0;
- }
-
- free_percpu(ptr);
-}
-
/*
* Check that the assigned pointer tag falls within the [KASAN_TAG_MIN,
* KASAN_TAG_KERNEL) range (note: excluding the match-all tag) for tag-based
@@ -2023,7 +1997,6 @@ static struct kunit_case kasan_kunit_test_cases[] = {
KUNIT_CASE(vmalloc_oob),
KUNIT_CASE(vmap_tags),
KUNIT_CASE(vm_map_ram_tags),
- KUNIT_CASE(vmalloc_percpu),
KUNIT_CASE(match_all_not_assigned),
KUNIT_CASE(match_all_ptr_tag),
KUNIT_CASE(match_all_mem_tag),
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index 81d8819f13cd..f8744f5630bb 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -848,6 +848,8 @@ static int mem_cgroup_move_account(struct folio *folio,
css_get(&to->css);
css_put(&from->css);
+ /* Warning should never happen, so don't worry about refcount non-0 */
+ WARN_ON_ONCE(folio_unqueue_deferred_split(folio));
folio->memcg_data = (unsigned long)to;
__folio_memcg_unlock(from);
@@ -1217,7 +1219,9 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
enum mc_target_type target_type;
union mc_target target;
struct folio *folio;
+ bool tried_split_before = false;
+retry_pmd:
ptl = pmd_trans_huge_lock(pmd, vma);
if (ptl) {
if (mc.precharge < HPAGE_PMD_NR) {
@@ -1227,6 +1231,27 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
target_type = get_mctgt_type_thp(vma, addr, *pmd, &target);
if (target_type == MC_TARGET_PAGE) {
folio = target.folio;
+ /*
+ * Deferred split queue locking depends on memcg,
+ * and unqueue is unsafe unless folio refcount is 0:
+ * split or skip if on the queue? first try to split.
+ */
+ if (!list_empty(&folio->_deferred_list)) {
+ spin_unlock(ptl);
+ if (!tried_split_before)
+ split_folio(folio);
+ folio_unlock(folio);
+ folio_put(folio);
+ if (tried_split_before)
+ return 0;
+ tried_split_before = true;
+ goto retry_pmd;
+ }
+ /*
+ * So long as that pmd lock is held, the folio cannot
+ * be racily added to the _deferred_list, because
+ * __folio_remove_rmap() will find !partially_mapped.
+ */
if (folio_isolate_lru(folio)) {
if (!mem_cgroup_move_account(folio, true,
mc.from, mc.to)) {
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7845c64a2c57..53db98d2c4a1 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -431,6 +431,10 @@ static const unsigned int memcg_vm_event_stat[] = {
PGDEACTIVATE,
PGLAZYFREE,
PGLAZYFREED,
+#ifdef CONFIG_SWAP
+ SWPIN_ZERO,
+ SWPOUT_ZERO,
+#endif
#ifdef CONFIG_ZSWAP
ZSWPIN,
ZSWPOUT,
@@ -4629,10 +4633,6 @@ static void uncharge_folio(struct folio *folio, struct uncharge_gather *ug)
struct obj_cgroup *objcg;
VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
- VM_BUG_ON_FOLIO(folio_order(folio) > 1 &&
- !folio_test_hugetlb(folio) &&
- !list_empty(&folio->_deferred_list) &&
- folio_test_partially_mapped(folio), folio);
/*
* Nobody should be changing or seriously looking at
@@ -4679,6 +4679,7 @@ static void uncharge_folio(struct folio *folio, struct uncharge_gather *ug)
ug->nr_memory += nr_pages;
ug->pgpgout++;
+ WARN_ON_ONCE(folio_unqueue_deferred_split(folio));
folio->memcg_data = 0;
}
@@ -4790,6 +4791,9 @@ void mem_cgroup_migrate(struct folio *old, struct folio *new)
/* Transfer the charge and the css ref */
commit_charge(new, memcg);
+
+ /* Warning should never happen, so don't worry about refcount non-0 */
+ WARN_ON_ONCE(folio_unqueue_deferred_split(old));
old->memcg_data = 0;
}
@@ -4976,6 +4980,7 @@ void mem_cgroup_swapout(struct folio *folio, swp_entry_t entry)
VM_BUG_ON_FOLIO(oldid, folio);
mod_memcg_state(swap_memcg, MEMCG_SWAP, nr_entries);
+ folio_unqueue_deferred_split(folio);
folio->memcg_data = 0;
if (!mem_cgroup_is_root(memcg))
diff --git a/mm/memory.c b/mm/memory.c
index 3ccee51adfbb..bdf77a3ec47b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4187,6 +4187,8 @@ static struct folio *alloc_swap_folio(struct vm_fault *vmf)
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+static DECLARE_WAIT_QUEUE_HEAD(swapcache_wq);
+
/*
* We enter with non-exclusive mmap_lock (to exclude vma changes,
* but allow concurrent faults), and pte mapped but not yet locked.
@@ -4199,6 +4201,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct folio *swapcache, *folio = NULL;
+ DECLARE_WAITQUEUE(wait, current);
struct page *page;
struct swap_info_struct *si = NULL;
rmap_t rmap_flags = RMAP_NONE;
@@ -4297,7 +4300,9 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
* Relax a bit to prevent rapid
* repeated page faults.
*/
+ add_wait_queue(&swapcache_wq, &wait);
schedule_timeout_uninterruptible(1);
+ remove_wait_queue(&swapcache_wq, &wait);
goto out_page;
}
need_clear_cache = true;
@@ -4604,8 +4609,11 @@ unlock:
pte_unmap_unlock(vmf->pte, vmf->ptl);
out:
/* Clear the swap cache pin for direct swapin after PTL unlock */
- if (need_clear_cache)
+ if (need_clear_cache) {
swapcache_clear(si, entry, nr_pages);
+ if (waitqueue_active(&swapcache_wq))
+ wake_up(&swapcache_wq);
+ }
if (si)
put_swap_device(si);
return ret;
@@ -4620,8 +4628,11 @@ out_release:
folio_unlock(swapcache);
folio_put(swapcache);
}
- if (need_clear_cache)
+ if (need_clear_cache) {
swapcache_clear(si, entry, nr_pages);
+ if (waitqueue_active(&swapcache_wq))
+ wake_up(&swapcache_wq);
+ }
if (si)
put_swap_device(si);
return ret;
diff --git a/mm/migrate.c b/mm/migrate.c
index df91248755e4..dfa24e41e8f9 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -206,7 +206,8 @@ static bool try_to_map_unused_to_zeropage(struct page_vma_mapped_walk *pvmw,
pte_t newpte;
void *addr;
- VM_BUG_ON_PAGE(PageCompound(page), page);
+ if (PageCompound(page))
+ return false;
VM_BUG_ON_PAGE(!PageAnon(page), page);
VM_BUG_ON_PAGE(!PageLocked(page), page);
VM_BUG_ON_PAGE(pte_present(*pvmw->pte), page);
@@ -489,7 +490,7 @@ static int __folio_migrate_mapping(struct address_space *mapping,
folio_test_large_rmappable(folio)) {
if (!folio_ref_freeze(folio, expected_count))
return -EAGAIN;
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
folio_ref_unfreeze(folio, expected_count);
}
@@ -514,7 +515,7 @@ static int __folio_migrate_mapping(struct address_space *mapping,
}
/* Take off deferred split queue while frozen and memcg set */
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
/*
* Now we know that no one else is looking at the folio:
@@ -1177,7 +1178,7 @@ static void migrate_folio_done(struct folio *src,
* not accounted to NR_ISOLATED_*. They can be recognized
* as __folio_test_movable
*/
- if (likely(!__folio_test_movable(src)))
+ if (likely(!__folio_test_movable(src)) && reason != MR_DEMOTION)
mod_node_page_state(folio_pgdat(src), NR_ISOLATED_ANON +
folio_is_file_lru(src), -folio_nr_pages(src));
diff --git a/mm/mlock.c b/mm/mlock.c
index e3e3dc2b2956..cde076fa7d5e 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -725,14 +725,17 @@ static int apply_mlockall_flags(int flags)
}
for_each_vma(vmi, vma) {
+ int error;
vm_flags_t newflags;
newflags = vma->vm_flags & ~VM_LOCKED_MASK;
newflags |= to_add;
- /* Ignore errors */
- mlock_fixup(&vmi, vma, &prev, vma->vm_start, vma->vm_end,
- newflags);
+ error = mlock_fixup(&vmi, vma, &prev, vma->vm_start, vma->vm_end,
+ newflags);
+ /* Ignore errors, but prev needs fixing up. */
+ if (error)
+ prev = vma;
cond_resched();
}
out:
diff --git a/mm/mmap.c b/mm/mmap.c
index 9c0fb43064b5..79d541f1502b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -344,7 +344,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
* to. we assume access permissions have been handled by the open
* of the memory object, so we don't do any here.
*/
- vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
+ vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(file, flags) |
mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
/* Obtain the address to map to. we verify (or select) it and ensure
@@ -900,7 +900,8 @@ __get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
if (get_area) {
addr = get_area(file, addr, len, pgoff, flags);
- } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
+ } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)
+ && IS_ALIGNED(len, PMD_SIZE)) {
/* Ensures that larger anonymous mappings are THP aligned. */
addr = thp_get_unmapped_area_vmflags(file, addr, len,
pgoff, flags, vm_flags);
@@ -1357,20 +1358,18 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
return do_vmi_munmap(&vmi, mm, start, len, uf, false);
}
-unsigned long mmap_region(struct file *file, unsigned long addr,
+static unsigned long __mmap_region(struct file *file, unsigned long addr,
unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
struct list_head *uf)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma = NULL;
pgoff_t pglen = PHYS_PFN(len);
- struct vm_area_struct *merge;
unsigned long charged = 0;
struct vma_munmap_struct vms;
struct ma_state mas_detach;
struct maple_tree mt_detach;
unsigned long end = addr + len;
- bool writable_file_mapping = false;
int error;
VMA_ITERATOR(vmi, mm, addr);
VMG_STATE(vmg, mm, &vmi, addr, end, vm_flags, pgoff);
@@ -1418,6 +1417,13 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vmg.flags = vm_flags;
}
+ /*
+ * clear PTEs while the vma is still in the tree so that rmap
+ * cannot race with the freeing later in the truncate scenario.
+ * This is also needed for mmap_file(), which is why vm_ops
+ * close function is called.
+ */
+ vms_clean_up_area(&vms, &mas_detach);
vma = vma_merge_new_range(&vmg);
if (vma)
goto expanded;
@@ -1437,40 +1443,35 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vm_flags_init(vma, vm_flags);
vma->vm_page_prot = vm_get_page_prot(vm_flags);
+ if (vma_iter_prealloc(&vmi, vma)) {
+ error = -ENOMEM;
+ goto free_vma;
+ }
+
if (file) {
vma->vm_file = get_file(file);
- /*
- * call_mmap() may map PTE, so ensure there are no existing PTEs
- * and call the vm_ops close function if one exists.
- */
- vms_clean_up_area(&vms, &mas_detach);
- error = call_mmap(file, vma);
+ error = mmap_file(file, vma);
if (error)
- goto unmap_and_free_vma;
-
- if (vma_is_shared_maywrite(vma)) {
- error = mapping_map_writable(file->f_mapping);
- if (error)
- goto close_and_free_vma;
-
- writable_file_mapping = true;
- }
+ goto unmap_and_free_file_vma;
+ /* Drivers cannot alter the address of the VMA. */
+ WARN_ON_ONCE(addr != vma->vm_start);
/*
- * Expansion is handled above, merging is handled below.
- * Drivers should not alter the address of the VMA.
+ * Drivers should not permit writability when previously it was
+ * disallowed.
*/
- if (WARN_ON((addr != vma->vm_start))) {
- error = -EINVAL;
- goto close_and_free_vma;
- }
+ VM_WARN_ON_ONCE(vm_flags != vma->vm_flags &&
+ !(vm_flags & VM_MAYWRITE) &&
+ (vma->vm_flags & VM_MAYWRITE));
vma_iter_config(&vmi, addr, end);
/*
- * If vm_flags changed after call_mmap(), we should try merge
+ * If vm_flags changed after mmap_file(), we should try merge
* vma again as we may succeed this time.
*/
if (unlikely(vm_flags != vma->vm_flags && vmg.prev)) {
+ struct vm_area_struct *merge;
+
vmg.flags = vma->vm_flags;
/* If this fails, state is reset ready for a reattempt. */
merge = vma_merge_new_range(&vmg);
@@ -1488,7 +1489,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vma = merge;
/* Update vm_flags to pick up the change. */
vm_flags = vma->vm_flags;
- goto unmap_writable;
+ goto file_expanded;
}
vma_iter_config(&vmi, addr, end);
}
@@ -1497,26 +1498,15 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
} else if (vm_flags & VM_SHARED) {
error = shmem_zero_setup(vma);
if (error)
- goto free_vma;
+ goto free_iter_vma;
} else {
vma_set_anonymous(vma);
}
- if (map_deny_write_exec(vma, vma->vm_flags)) {
- error = -EACCES;
- goto close_and_free_vma;
- }
-
- /* Allow architectures to sanity-check the vm_flags */
- if (!arch_validate_flags(vma->vm_flags)) {
- error = -EINVAL;
- goto close_and_free_vma;
- }
-
- if (vma_iter_prealloc(&vmi, vma)) {
- error = -ENOMEM;
- goto close_and_free_vma;
- }
+#ifdef CONFIG_SPARC64
+ /* TODO: Fix SPARC ADI! */
+ WARN_ON_ONCE(!arch_validate_flags(vm_flags));
+#endif
/* Lock the VMA since it is modified after insertion into VMA tree */
vma_start_write(vma);
@@ -1530,10 +1520,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
*/
khugepaged_enter_vma(vma, vma->vm_flags);
- /* Once vma denies write, undo our temporary denial count */
-unmap_writable:
- if (writable_file_mapping)
- mapping_unmap_writable(file->f_mapping);
+file_expanded:
file = vma->vm_file;
ksm_add_vma(vma);
expanded:
@@ -1566,24 +1553,17 @@ expanded:
vma_set_page_prot(vma);
- validate_mm(mm);
return addr;
-close_and_free_vma:
- if (file && !vms.closed_vm_ops && vma->vm_ops && vma->vm_ops->close)
- vma->vm_ops->close(vma);
-
- if (file || vma->vm_file) {
-unmap_and_free_vma:
- fput(vma->vm_file);
- vma->vm_file = NULL;
+unmap_and_free_file_vma:
+ fput(vma->vm_file);
+ vma->vm_file = NULL;
- vma_iter_set(&vmi, vma->vm_end);
- /* Undo any partial mapping done by a device driver. */
- unmap_region(&vmi.mas, vma, vmg.prev, vmg.next);
- }
- if (writable_file_mapping)
- mapping_unmap_writable(file->f_mapping);
+ vma_iter_set(&vmi, vma->vm_end);
+ /* Undo any partial mapping done by a device driver. */
+ unmap_region(&vmi.mas, vma, vmg.prev, vmg.next);
+free_iter_vma:
+ vma_iter_free(&vmi);
free_vma:
vm_area_free(vma);
unacct_error:
@@ -1593,10 +1573,43 @@ unacct_error:
abort_munmap:
vms_abort_munmap_vmas(&vms, &mas_detach);
gather_failed:
- validate_mm(mm);
return error;
}
+unsigned long mmap_region(struct file *file, unsigned long addr,
+ unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
+ struct list_head *uf)
+{
+ unsigned long ret;
+ bool writable_file_mapping = false;
+
+ /* Check to see if MDWE is applicable. */
+ if (map_deny_write_exec(vm_flags, vm_flags))
+ return -EACCES;
+
+ /* Allow architectures to sanity-check the vm_flags. */
+ if (!arch_validate_flags(vm_flags))
+ return -EINVAL;
+
+ /* Map writable and ensure this isn't a sealed memfd. */
+ if (file && is_shared_maywrite(vm_flags)) {
+ int error = mapping_map_writable(file->f_mapping);
+
+ if (error)
+ return error;
+ writable_file_mapping = true;
+ }
+
+ ret = __mmap_region(file, addr, len, vm_flags, pgoff, uf);
+
+ /* Clear our write mapping regardless of error. */
+ if (writable_file_mapping)
+ mapping_unmap_writable(file->f_mapping);
+
+ validate_mm(current->mm);
+ return ret;
+}
+
static int __vm_munmap(unsigned long start, size_t len, bool unlock)
{
int ret;
@@ -1640,6 +1653,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
unsigned long populate = 0;
unsigned long ret = -EINVAL;
struct file *file;
+ vm_flags_t vm_flags;
pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/mm/remap_file_pages.rst.\n",
current->comm, current->pid);
@@ -1656,12 +1670,60 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
if (pgoff + (size >> PAGE_SHIFT) < pgoff)
return ret;
- if (mmap_write_lock_killable(mm))
+ if (mmap_read_lock_killable(mm))
return -EINTR;
+ /*
+ * Look up VMA under read lock first so we can perform the security
+ * without holding locks (which can be problematic). We reacquire a
+ * write lock later and check nothing changed underneath us.
+ */
vma = vma_lookup(mm, start);
- if (!vma || !(vma->vm_flags & VM_SHARED))
+ if (!vma || !(vma->vm_flags & VM_SHARED)) {
+ mmap_read_unlock(mm);
+ return -EINVAL;
+ }
+
+ prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
+ prot |= vma->vm_flags & VM_WRITE ? PROT_WRITE : 0;
+ prot |= vma->vm_flags & VM_EXEC ? PROT_EXEC : 0;
+
+ flags &= MAP_NONBLOCK;
+ flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
+ if (vma->vm_flags & VM_LOCKED)
+ flags |= MAP_LOCKED;
+
+ /* Save vm_flags used to calculate prot and flags, and recheck later. */
+ vm_flags = vma->vm_flags;
+ file = get_file(vma->vm_file);
+
+ mmap_read_unlock(mm);
+
+ /* Call outside mmap_lock to be consistent with other callers. */
+ ret = security_mmap_file(file, prot, flags);
+ if (ret) {
+ fput(file);
+ return ret;
+ }
+
+ ret = -EINVAL;
+
+ /* OK security check passed, take write lock + let it rip. */
+ if (mmap_write_lock_killable(mm)) {
+ fput(file);
+ return -EINTR;
+ }
+
+ vma = vma_lookup(mm, start);
+
+ if (!vma)
+ goto out;
+
+ /* Make sure things didn't change under us. */
+ if (vma->vm_flags != vm_flags)
+ goto out;
+ if (vma->vm_file != file)
goto out;
if (start + size > vma->vm_end) {
@@ -1689,25 +1751,11 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
goto out;
}
- prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
- prot |= vma->vm_flags & VM_WRITE ? PROT_WRITE : 0;
- prot |= vma->vm_flags & VM_EXEC ? PROT_EXEC : 0;
-
- flags &= MAP_NONBLOCK;
- flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
- if (vma->vm_flags & VM_LOCKED)
- flags |= MAP_LOCKED;
-
- file = get_file(vma->vm_file);
- ret = security_mmap_file(vma->vm_file, prot, flags);
- if (ret)
- goto out_fput;
ret = do_mmap(vma->vm_file, start, size,
prot, flags, 0, pgoff, &populate, NULL);
-out_fput:
- fput(file);
out:
mmap_write_unlock(mm);
+ fput(file);
if (populate)
mm_populate(ret, populate);
if (!IS_ERR_VALUE(ret))
@@ -1754,7 +1802,8 @@ static int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
VMG_STATE(vmg, mm, vmi, addr, addr + len, flags, PHYS_PFN(addr));
vmg.prev = vma;
- vma_iter_next_range(vmi);
+ /* vmi is positioned at prev, which this mode expects. */
+ vmg.merge_flags = VMG_FLAG_JUST_EXPAND;
if (vma_merge_new_range(&vmg))
goto out;
@@ -1895,7 +1944,7 @@ void exit_mmap(struct mm_struct *mm)
do {
if (vma->vm_flags & VM_ACCOUNT)
nr_accounted += vma_pages(vma);
- remove_vma(vma, /* unreachable = */ true, /* closed = */ false);
+ remove_vma(vma, /* unreachable = */ true);
count++;
cond_resched();
vma = vma_next(&vmi);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 0c5d6d06107d..6f450af3252e 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -810,7 +810,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
break;
}
- if (map_deny_write_exec(vma, newflags)) {
+ if (map_deny_write_exec(vma->vm_flags, newflags)) {
error = -EACCES;
break;
}
diff --git a/mm/nommu.c b/mm/nommu.c
index 385b0c15add8..9cb6e99215e2 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -573,7 +573,7 @@ static int delete_vma_from_mm(struct vm_area_struct *vma)
VMA_ITERATOR(vmi, vma->vm_mm, vma->vm_start);
vma_iter_config(&vmi, vma->vm_start, vma->vm_end);
- if (vma_iter_prealloc(&vmi, vma)) {
+ if (vma_iter_prealloc(&vmi, NULL)) {
pr_warn("Allocation of vma tree for process %d failed\n",
current->pid);
return -ENOMEM;
@@ -589,8 +589,7 @@ static int delete_vma_from_mm(struct vm_area_struct *vma)
*/
static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma)
{
- if (vma->vm_ops && vma->vm_ops->close)
- vma->vm_ops->close(vma);
+ vma_close(vma);
if (vma->vm_file)
fput(vma->vm_file);
put_nommu_region(vma->vm_region);
@@ -843,7 +842,7 @@ static unsigned long determine_vm_flags(struct file *file,
{
unsigned long vm_flags;
- vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(flags);
+ vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
if (!file) {
/*
@@ -885,7 +884,7 @@ static int do_mmap_shared_file(struct vm_area_struct *vma)
{
int ret;
- ret = call_mmap(vma->vm_file, vma);
+ ret = mmap_file(vma->vm_file, vma);
if (ret == 0) {
vma->vm_region->vm_top = vma->vm_region->vm_end;
return 0;
@@ -918,7 +917,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
* happy.
*/
if (capabilities & NOMMU_MAP_DIRECT) {
- ret = call_mmap(vma->vm_file, vma);
+ ret = mmap_file(vma->vm_file, vma);
/* shouldn't return success if we're not sharing */
if (WARN_ON_ONCE(!is_nommu_shared_mapping(vma->vm_flags)))
ret = -ENOSYS;
diff --git a/mm/numa_memblks.c b/mm/numa_memblks.c
index be52b93a9c58..a3877e9bc878 100644
--- a/mm/numa_memblks.c
+++ b/mm/numa_memblks.c
@@ -349,7 +349,7 @@ static void __init numa_clear_kernel_node_hotplug(void)
for_each_reserved_mem_region(mb_region) {
int nid = memblock_get_region_node(mb_region);
- if (nid != MAX_NUMNODES)
+ if (numa_valid_node(nid))
node_set(nid, reserved_nodemask);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8afab64814dc..45e12658438e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -635,6 +635,8 @@ compaction_capture(struct capture_control *capc, struct page *page,
static inline void account_freepages(struct zone *zone, int nr_pages,
int migratetype)
{
+ lockdep_assert_held(&zone->lock);
+
if (is_migrate_isolate(migratetype))
return;
@@ -642,6 +644,9 @@ static inline void account_freepages(struct zone *zone, int nr_pages,
if (is_migrate_cma(migratetype))
__mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages);
+ else if (is_migrate_highatomic(migratetype))
+ WRITE_ONCE(zone->nr_free_highatomic,
+ zone->nr_free_highatomic + nr_pages);
}
/* Used for pages not on another list */
@@ -961,9 +966,8 @@ static int free_tail_page_prepare(struct page *head_page, struct page *page)
break;
case 2:
/* the second tail page: deferred_list overlaps ->mapping */
- if (unlikely(!list_empty(&folio->_deferred_list) &&
- folio_test_partially_mapped(folio))) {
- bad_page(page, "partially mapped folio on deferred list");
+ if (unlikely(!list_empty(&folio->_deferred_list))) {
+ bad_page(page, "on deferred list");
goto out;
}
break;
@@ -1044,6 +1048,7 @@ __always_inline bool free_pages_prepare(struct page *page,
bool skip_kasan_poison = should_skip_kasan_poison(page);
bool init = want_init_on_free();
bool compound = PageCompound(page);
+ struct folio *folio = page_folio(page);
VM_BUG_ON_PAGE(PageTail(page), page);
@@ -1053,6 +1058,20 @@ __always_inline bool free_pages_prepare(struct page *page,
if (memcg_kmem_online() && PageMemcgKmem(page))
__memcg_kmem_uncharge_page(page, order);
+ /*
+ * In rare cases, when truncation or holepunching raced with
+ * munlock after VM_LOCKED was cleared, Mlocked may still be
+ * found set here. This does not indicate a problem, unless
+ * "unevictable_pgs_cleared" appears worryingly large.
+ */
+ if (unlikely(folio_test_mlocked(folio))) {
+ long nr_pages = folio_nr_pages(folio);
+
+ __folio_clear_mlocked(folio);
+ zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
+ count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
+ }
+
if (unlikely(PageHWPoison(page)) && !order) {
/* Do not let hwpoison pages hit pcplists/buddy */
reset_page_owner(page, order);
@@ -2682,7 +2701,6 @@ void free_unref_folios(struct folio_batch *folios)
unsigned long pfn = folio_pfn(folio);
unsigned int order = folio_order(folio);
- folio_undo_large_rmappable(folio);
if (!free_pages_prepare(&folio->page, order))
continue;
/*
@@ -2893,12 +2911,12 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,
page = __rmqueue(zone, order, migratetype, alloc_flags);
/*
- * If the allocation fails, allow OOM handling access
- * to HIGHATOMIC reserves as failing now is worse than
- * failing a high-order atomic allocation in the
- * future.
+ * If the allocation fails, allow OOM handling and
+ * order-0 (atomic) allocs access to HIGHATOMIC
+ * reserves as failing now is worse than failing a
+ * high-order atomic allocation in the future.
*/
- if (!page && (alloc_flags & ALLOC_OOM))
+ if (!page && (alloc_flags & (ALLOC_OOM|ALLOC_NON_BLOCK)))
page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
if (!page) {
@@ -3081,11 +3099,10 @@ static inline long __zone_watermark_unusable_free(struct zone *z,
/*
* If the caller does not have rights to reserves below the min
- * watermark then subtract the high-atomic reserves. This will
- * over-estimate the size of the atomic reserve but it avoids a search.
+ * watermark then subtract the free pages reserved for highatomic.
*/
if (likely(!(alloc_flags & ALLOC_RESERVES)))
- unusable_free += z->nr_reserved_highatomic;
+ unusable_free += READ_ONCE(z->nr_free_highatomic);
#ifdef CONFIG_CMA
/* If allocation can't use CMA areas don't use free CMA pages */
@@ -4836,142 +4853,6 @@ void free_pages(unsigned long addr, unsigned int order)
EXPORT_SYMBOL(free_pages);
-/*
- * Page Fragment:
- * An arbitrary-length arbitrary-offset area of memory which resides
- * within a 0 or higher order page. Multiple fragments within that page
- * are individually refcounted, in the page's reference counter.
- *
- * The page_frag functions below provide a simple allocation framework for
- * page fragments. This is used by the network stack and network device
- * drivers to provide a backing region of memory for use as either an
- * sk_buff->head, or to be used in the "frags" portion of skb_shared_info.
- */
-static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
- gfp_t gfp_mask)
-{
- struct page *page = NULL;
- gfp_t gfp = gfp_mask;
-
-#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
- gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP |
- __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;
- page = alloc_pages_node(NUMA_NO_NODE, gfp_mask,
- PAGE_FRAG_CACHE_MAX_ORDER);
- nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE;
-#endif
- if (unlikely(!page))
- page = alloc_pages_node(NUMA_NO_NODE, gfp, 0);
-
- nc->va = page ? page_address(page) : NULL;
-
- return page;
-}
-
-void page_frag_cache_drain(struct page_frag_cache *nc)
-{
- if (!nc->va)
- return;
-
- __page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias);
- nc->va = NULL;
-}
-EXPORT_SYMBOL(page_frag_cache_drain);
-
-void __page_frag_cache_drain(struct page *page, unsigned int count)
-{
- VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
-
- if (page_ref_sub_and_test(page, count))
- free_unref_page(page, compound_order(page));
-}
-EXPORT_SYMBOL(__page_frag_cache_drain);
-
-void *__page_frag_alloc_align(struct page_frag_cache *nc,
- unsigned int fragsz, gfp_t gfp_mask,
- unsigned int align_mask)
-{
- unsigned int size = PAGE_SIZE;
- struct page *page;
- int offset;
-
- if (unlikely(!nc->va)) {
-refill:
- page = __page_frag_cache_refill(nc, gfp_mask);
- if (!page)
- return NULL;
-
-#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
- /* if size can vary use size else just use PAGE_SIZE */
- size = nc->size;
-#endif
- /* Even if we own the page, we do not use atomic_set().
- * This would break get_page_unless_zero() users.
- */
- page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE);
-
- /* reset page count bias and offset to start of new frag */
- nc->pfmemalloc = page_is_pfmemalloc(page);
- nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
- nc->offset = size;
- }
-
- offset = nc->offset - fragsz;
- if (unlikely(offset < 0)) {
- page = virt_to_page(nc->va);
-
- if (!page_ref_sub_and_test(page, nc->pagecnt_bias))
- goto refill;
-
- if (unlikely(nc->pfmemalloc)) {
- free_unref_page(page, compound_order(page));
- goto refill;
- }
-
-#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
- /* if size can vary use size else just use PAGE_SIZE */
- size = nc->size;
-#endif
- /* OK, page count is 0, we can safely set it */
- set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
-
- /* reset page count bias and offset to start of new frag */
- nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
- offset = size - fragsz;
- if (unlikely(offset < 0)) {
- /*
- * The caller is trying to allocate a fragment
- * with fragsz > PAGE_SIZE but the cache isn't big
- * enough to satisfy the request, this may
- * happen in low memory conditions.
- * We don't release the cache page because
- * it could make memory pressure worse
- * so we simply return NULL here.
- */
- return NULL;
- }
- }
-
- nc->pagecnt_bias--;
- offset &= align_mask;
- nc->offset = offset;
-
- return nc->va + offset;
-}
-EXPORT_SYMBOL(__page_frag_alloc_align);
-
-/*
- * Frees a page fragment allocated out of either a compound or order 0 page.
- */
-void page_frag_free(void *addr)
-{
- struct page *page = virt_to_head_page(addr);
-
- if (unlikely(put_page_testzero(page)))
- free_unref_page(page, compound_order(page));
-}
-EXPORT_SYMBOL(page_frag_free);
-
static void *make_alloc_exact(unsigned long addr, unsigned int order,
size_t size)
{
diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c
new file mode 100644
index 000000000000..3f7a203d35c6
--- /dev/null
+++ b/mm/page_frag_cache.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Page fragment allocator
+ *
+ * Page Fragment:
+ * An arbitrary-length arbitrary-offset area of memory which resides within a
+ * 0 or higher order page. Multiple fragments within that page are
+ * individually refcounted, in the page's reference counter.
+ *
+ * The page_frag functions provide a simple allocation framework for page
+ * fragments. This is used by the network stack and network device drivers to
+ * provide a backing region of memory for use as either an sk_buff->head, or to
+ * be used in the "frags" portion of skb_shared_info.
+ */
+
+#include <linux/build_bug.h>
+#include <linux/export.h>
+#include <linux/gfp_types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/page_frag_cache.h>
+#include "internal.h"
+
+static unsigned long encoded_page_create(struct page *page, unsigned int order,
+ bool pfmemalloc)
+{
+ BUILD_BUG_ON(PAGE_FRAG_CACHE_MAX_ORDER > PAGE_FRAG_CACHE_ORDER_MASK);
+ BUILD_BUG_ON(PAGE_FRAG_CACHE_PFMEMALLOC_BIT >= PAGE_SIZE);
+
+ return (unsigned long)page_address(page) |
+ (order & PAGE_FRAG_CACHE_ORDER_MASK) |
+ ((unsigned long)pfmemalloc * PAGE_FRAG_CACHE_PFMEMALLOC_BIT);
+}
+
+static unsigned long encoded_page_decode_order(unsigned long encoded_page)
+{
+ return encoded_page & PAGE_FRAG_CACHE_ORDER_MASK;
+}
+
+static void *encoded_page_decode_virt(unsigned long encoded_page)
+{
+ return (void *)(encoded_page & PAGE_MASK);
+}
+
+static struct page *encoded_page_decode_page(unsigned long encoded_page)
+{
+ return virt_to_page((void *)encoded_page);
+}
+
+static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
+ gfp_t gfp_mask)
+{
+ unsigned long order = PAGE_FRAG_CACHE_MAX_ORDER;
+ struct page *page = NULL;
+ gfp_t gfp = gfp_mask;
+
+#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
+ gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP |
+ __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;
+ page = __alloc_pages(gfp_mask, PAGE_FRAG_CACHE_MAX_ORDER,
+ numa_mem_id(), NULL);
+#endif
+ if (unlikely(!page)) {
+ page = __alloc_pages(gfp, 0, numa_mem_id(), NULL);
+ order = 0;
+ }
+
+ nc->encoded_page = page ?
+ encoded_page_create(page, order, page_is_pfmemalloc(page)) : 0;
+
+ return page;
+}
+
+void page_frag_cache_drain(struct page_frag_cache *nc)
+{
+ if (!nc->encoded_page)
+ return;
+
+ __page_frag_cache_drain(encoded_page_decode_page(nc->encoded_page),
+ nc->pagecnt_bias);
+ nc->encoded_page = 0;
+}
+EXPORT_SYMBOL(page_frag_cache_drain);
+
+void __page_frag_cache_drain(struct page *page, unsigned int count)
+{
+ VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
+
+ if (page_ref_sub_and_test(page, count))
+ free_unref_page(page, compound_order(page));
+}
+EXPORT_SYMBOL(__page_frag_cache_drain);
+
+void *__page_frag_alloc_align(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask,
+ unsigned int align_mask)
+{
+ unsigned long encoded_page = nc->encoded_page;
+ unsigned int size, offset;
+ struct page *page;
+
+ if (unlikely(!encoded_page)) {
+refill:
+ page = __page_frag_cache_refill(nc, gfp_mask);
+ if (!page)
+ return NULL;
+
+ encoded_page = nc->encoded_page;
+
+ /* Even if we own the page, we do not use atomic_set().
+ * This would break get_page_unless_zero() users.
+ */
+ page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE);
+
+ /* reset page count bias and offset to start of new frag */
+ nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
+ nc->offset = 0;
+ }
+
+ size = PAGE_SIZE << encoded_page_decode_order(encoded_page);
+ offset = __ALIGN_KERNEL_MASK(nc->offset, ~align_mask);
+ if (unlikely(offset + fragsz > size)) {
+ if (unlikely(fragsz > PAGE_SIZE)) {
+ /*
+ * The caller is trying to allocate a fragment
+ * with fragsz > PAGE_SIZE but the cache isn't big
+ * enough to satisfy the request, this may
+ * happen in low memory conditions.
+ * We don't release the cache page because
+ * it could make memory pressure worse
+ * so we simply return NULL here.
+ */
+ return NULL;
+ }
+
+ page = encoded_page_decode_page(encoded_page);
+
+ if (!page_ref_sub_and_test(page, nc->pagecnt_bias))
+ goto refill;
+
+ if (unlikely(encoded_page_decode_pfmemalloc(encoded_page))) {
+ free_unref_page(page,
+ encoded_page_decode_order(encoded_page));
+ goto refill;
+ }
+
+ /* OK, page count is 0, we can safely set it */
+ set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
+
+ /* reset page count bias and offset to start of new frag */
+ nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
+ offset = 0;
+ }
+
+ nc->pagecnt_bias--;
+ nc->offset = offset + fragsz;
+
+ return encoded_page_decode_virt(encoded_page) + offset;
+}
+EXPORT_SYMBOL(__page_frag_alloc_align);
+
+/*
+ * Frees a page fragment allocated out of either a compound or order 0 page.
+ */
+void page_frag_free(void *addr)
+{
+ struct page *page = virt_to_head_page(addr);
+
+ if (unlikely(put_page_testzero(page)))
+ free_unref_page(page, compound_order(page));
+}
+EXPORT_SYMBOL(page_frag_free);
diff --git a/mm/page_io.c b/mm/page_io.c
index 78bc88acee79..01749b99fb54 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -204,7 +204,9 @@ static bool is_folio_zero_filled(struct folio *folio)
static void swap_zeromap_folio_set(struct folio *folio)
{
+ struct obj_cgroup *objcg = get_obj_cgroup_from_folio(folio);
struct swap_info_struct *sis = swp_swap_info(folio->swap);
+ int nr_pages = folio_nr_pages(folio);
swp_entry_t entry;
unsigned int i;
@@ -212,6 +214,12 @@ static void swap_zeromap_folio_set(struct folio *folio)
entry = page_swap_entry(folio_page(folio, i));
set_bit(swp_offset(entry), sis->zeromap);
}
+
+ count_vm_events(SWPOUT_ZERO, nr_pages);
+ if (objcg) {
+ count_objcg_events(objcg, SWPOUT_ZERO, nr_pages);
+ obj_cgroup_put(objcg);
+ }
}
static void swap_zeromap_folio_clear(struct folio *folio)
@@ -503,6 +511,7 @@ static void sio_read_complete(struct kiocb *iocb, long ret)
static bool swap_read_folio_zeromap(struct folio *folio)
{
int nr_pages = folio_nr_pages(folio);
+ struct obj_cgroup *objcg;
bool is_zeromap;
/*
@@ -517,6 +526,13 @@ static bool swap_read_folio_zeromap(struct folio *folio)
if (!is_zeromap)
return false;
+ objcg = get_obj_cgroup_from_folio(folio);
+ count_vm_events(SWPIN_ZERO, nr_pages);
+ if (objcg) {
+ count_objcg_events(objcg, SWPIN_ZERO, nr_pages);
+ obj_cgroup_put(objcg);
+ }
+
folio_zero_range(folio, 0, folio_size(folio));
folio_mark_uptodate(folio);
return true;
@@ -570,7 +586,7 @@ static void swap_read_folio_bdev_sync(struct folio *folio,
* attempt to access it in the page fault retry time check.
*/
get_task_struct(current);
- count_vm_event(PSWPIN);
+ count_vm_events(PSWPIN, folio_nr_pages(folio));
submit_bio_wait(&bio);
__end_swap_bio_read(&bio);
put_task_struct(current);
@@ -585,7 +601,7 @@ static void swap_read_folio_bdev_async(struct folio *folio,
bio->bi_iter.bi_sector = swap_folio_sector(folio);
bio->bi_end_io = end_swap_bio_read;
bio_add_folio_nofail(bio, folio, folio_size(folio), 0);
- count_vm_event(PSWPIN);
+ count_vm_events(PSWPIN, folio_nr_pages(folio));
submit_bio(bio);
}
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 461ea3bbd8d9..5f9f01532e67 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -744,7 +744,8 @@ struct folio *folio_walk_start(struct folio_walk *fw,
pud = pudp_get(pudp);
if (pud_none(pud))
goto not_found;
- if (IS_ENABLED(CONFIG_PGTABLE_HAS_HUGE_LEAVES) && pud_leaf(pud)) {
+ if (IS_ENABLED(CONFIG_PGTABLE_HAS_HUGE_LEAVES) &&
+ (!pud_present(pud) || pud_leaf(pud))) {
ptl = pud_lock(vma->vm_mm, pudp);
pud = pudp_get(pudp);
@@ -753,6 +754,10 @@ struct folio *folio_walk_start(struct folio_walk *fw,
fw->pudp = pudp;
fw->pud = pud;
+ /*
+ * TODO: FW_MIGRATION support for PUD migration entries
+ * once there are relevant users.
+ */
if (!pud_present(pud) || pud_devmap(pud) || pud_special(pud)) {
spin_unlock(ptl);
goto not_found;
@@ -769,12 +774,13 @@ struct folio *folio_walk_start(struct folio_walk *fw,
}
pmd_table:
- VM_WARN_ON_ONCE(pud_leaf(*pudp));
+ VM_WARN_ON_ONCE(!pud_present(pud) || pud_leaf(pud));
pmdp = pmd_offset(pudp, addr);
pmd = pmdp_get_lockless(pmdp);
if (pmd_none(pmd))
goto not_found;
- if (IS_ENABLED(CONFIG_PGTABLE_HAS_HUGE_LEAVES) && pmd_leaf(pmd)) {
+ if (IS_ENABLED(CONFIG_PGTABLE_HAS_HUGE_LEAVES) &&
+ (!pmd_present(pmd) || pmd_leaf(pmd))) {
ptl = pmd_lock(vma->vm_mm, pmdp);
pmd = pmdp_get(pmdp);
@@ -786,7 +792,7 @@ pmd_table:
if (pmd_none(pmd)) {
spin_unlock(ptl);
goto not_found;
- } else if (!pmd_leaf(pmd)) {
+ } else if (pmd_present(pmd) && !pmd_leaf(pmd)) {
spin_unlock(ptl);
goto pte_table;
} else if (pmd_present(pmd)) {
@@ -812,7 +818,7 @@ pmd_table:
}
pte_table:
- VM_WARN_ON_ONCE(pmd_leaf(pmdp_get_lockless(pmdp)));
+ VM_WARN_ON_ONCE(!pmd_present(pmd) || pmd_leaf(pmd));
ptep = pte_offset_map_lock(vma->vm_mm, pmdp, addr, &ptl);
if (!ptep)
goto not_found;
diff --git a/mm/rmap.c b/mm/rmap.c
index a8797d1b3d49..73d5998677d4 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -885,13 +885,10 @@ static bool folio_referenced_one(struct folio *folio,
return false;
}
- if (pvmw.pte) {
- if (lru_gen_enabled() &&
- pte_young(ptep_get(pvmw.pte))) {
- lru_gen_look_around(&pvmw);
+ if (lru_gen_enabled() && pvmw.pte) {
+ if (lru_gen_look_around(&pvmw))
referenced++;
- }
-
+ } else if (pvmw.pte) {
if (ptep_clear_flush_young_notify(vma, address,
pvmw.pte))
referenced++;
diff --git a/mm/shmem.c b/mm/shmem.c
index c5adb987b23c..e87f5d6799a7 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1166,7 +1166,9 @@ static int shmem_getattr(struct mnt_idmap *idmap,
stat->attributes_mask |= (STATX_ATTR_APPEND |
STATX_ATTR_IMMUTABLE |
STATX_ATTR_NODUMP);
+ inode_lock_shared(inode);
generic_fillattr(idmap, request_mask, inode, stat);
+ inode_unlock_shared(inode);
if (shmem_huge_global_enabled(inode, 0, 0, false, NULL, 0))
stat->blksize = HPAGE_PMD_SIZE;
@@ -2731,9 +2733,6 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
if (ret)
return ret;
- /* arm64 - allow memory tagging on RAM-based files */
- vm_flags_set(vma, VM_MTE_ALLOWED);
-
file_accessed(file);
/* This is anonymous shared memory if it is unlinked at the time of mmap */
if (inode->i_nlink)
diff --git a/mm/shrinker.c b/mm/shrinker.c
index dc5d2a6fcfc4..4a93fd433689 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -76,19 +76,21 @@ void free_shrinker_info(struct mem_cgroup *memcg)
int alloc_shrinker_info(struct mem_cgroup *memcg)
{
- struct shrinker_info *info;
int nid, ret = 0;
int array_size = 0;
mutex_lock(&shrinker_mutex);
array_size = shrinker_unit_size(shrinker_nr_max);
for_each_node(nid) {
- info = kvzalloc_node(sizeof(*info) + array_size, GFP_KERNEL, nid);
+ struct shrinker_info *info = kvzalloc_node(sizeof(*info) + array_size,
+ GFP_KERNEL, nid);
if (!info)
goto err;
info->map_nr_max = shrinker_nr_max;
- if (shrinker_unit_alloc(info, NULL, nid))
+ if (shrinker_unit_alloc(info, NULL, nid)) {
+ kvfree(info);
goto err;
+ }
rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_info, info);
}
mutex_unlock(&shrinker_mutex);
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 3d26c257ed8b..893d32059915 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -380,8 +380,11 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
unsigned int usersize,
void (*ctor)(void *))
{
+ unsigned long mask = 0;
+ unsigned int idx;
kmem_buckets *b;
- int idx;
+
+ BUILD_BUG_ON(ARRAY_SIZE(kmalloc_caches[KMALLOC_NORMAL]) > BITS_PER_LONG);
/*
* When the separate buckets API is not built in, just return
@@ -403,7 +406,7 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
for (idx = 0; idx < ARRAY_SIZE(kmalloc_caches[KMALLOC_NORMAL]); idx++) {
char *short_size, *cache_name;
unsigned int cache_useroffset, cache_usersize;
- unsigned int size;
+ unsigned int size, aligned_idx;
if (!kmalloc_caches[KMALLOC_NORMAL][idx])
continue;
@@ -416,10 +419,6 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
if (WARN_ON(!short_size))
goto fail;
- cache_name = kasprintf(GFP_KERNEL, "%s-%s", name, short_size + 1);
- if (WARN_ON(!cache_name))
- goto fail;
-
if (useroffset >= size) {
cache_useroffset = 0;
cache_usersize = 0;
@@ -427,18 +426,28 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
cache_useroffset = useroffset;
cache_usersize = min(size - cache_useroffset, usersize);
}
- (*b)[idx] = kmem_cache_create_usercopy(cache_name, size,
+
+ aligned_idx = __kmalloc_index(size, false);
+ if (!(*b)[aligned_idx]) {
+ cache_name = kasprintf(GFP_KERNEL, "%s-%s", name, short_size + 1);
+ if (WARN_ON(!cache_name))
+ goto fail;
+ (*b)[aligned_idx] = kmem_cache_create_usercopy(cache_name, size,
0, flags, cache_useroffset,
cache_usersize, ctor);
- kfree(cache_name);
- if (WARN_ON(!(*b)[idx]))
- goto fail;
+ kfree(cache_name);
+ if (WARN_ON(!(*b)[aligned_idx]))
+ goto fail;
+ set_bit(aligned_idx, &mask);
+ }
+ if (idx != aligned_idx)
+ (*b)[idx] = (*b)[aligned_idx];
}
return b;
fail:
- for (idx = 0; idx < ARRAY_SIZE(kmalloc_caches[KMALLOC_NORMAL]); idx++)
+ for_each_set_bit(idx, &mask, ARRAY_SIZE(kmalloc_caches[KMALLOC_NORMAL]))
kmem_cache_destroy((*b)[idx]);
kmem_cache_free(kmem_buckets_cache, b);
@@ -1209,7 +1218,7 @@ __do_krealloc(const void *p, size_t new_size, gfp_t flags)
/* Zero out spare memory. */
if (want_init_on_alloc(flags)) {
kasan_disable_current();
- memset((void *)p + new_size, 0, ks - new_size);
+ memset(kasan_reset_tag(p) + new_size, 0, ks - new_size);
kasan_enable_current();
}
diff --git a/mm/swap.c b/mm/swap.c
index 835bdf324b76..59f30a981c6f 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -78,20 +78,6 @@ static void __page_cache_release(struct folio *folio, struct lruvec **lruvecp,
lruvec_del_folio(*lruvecp, folio);
__folio_clear_lru_flags(folio);
}
-
- /*
- * In rare cases, when truncation or holepunching raced with
- * munlock after VM_LOCKED was cleared, Mlocked may still be
- * found set here. This does not indicate a problem, unless
- * "unevictable_pgs_cleared" appears worryingly large.
- */
- if (unlikely(folio_test_mlocked(folio))) {
- long nr_pages = folio_nr_pages(folio);
-
- __folio_clear_mlocked(folio);
- zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
- count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
- }
}
/*
@@ -121,7 +107,7 @@ void __folio_put(struct folio *folio)
}
page_cache_release(folio);
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
mem_cgroup_uncharge(folio);
free_unref_page(&folio->page, folio_order(folio));
}
@@ -988,7 +974,7 @@ void folios_put_refs(struct folio_batch *folios, unsigned int *refs)
free_huge_folio(folio);
continue;
}
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
__page_cache_release(folio, &lruvec, &flags);
if (j != i)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index b0915f3fab31..9c85bd46ab7f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -731,15 +731,16 @@ done:
return offset;
}
-static void swap_reclaim_full_clusters(struct swap_info_struct *si)
+/* Return true if reclaimed a whole cluster */
+static void swap_reclaim_full_clusters(struct swap_info_struct *si, bool force)
{
long to_scan = 1;
unsigned long offset, end;
struct swap_cluster_info *ci;
unsigned char *map = si->swap_map;
- int nr_reclaim, total_reclaimed = 0;
+ int nr_reclaim;
- if (atomic_long_read(&nr_swap_pages) <= SWAPFILE_CLUSTER)
+ if (force)
to_scan = si->inuse_pages / SWAPFILE_CLUSTER;
while (!list_empty(&si->full_clusters)) {
@@ -749,28 +750,36 @@ static void swap_reclaim_full_clusters(struct swap_info_struct *si)
end = min(si->max, offset + SWAPFILE_CLUSTER);
to_scan--;
+ spin_unlock(&si->lock);
while (offset < end) {
if (READ_ONCE(map[offset]) == SWAP_HAS_CACHE) {
- spin_unlock(&si->lock);
nr_reclaim = __try_to_reclaim_swap(si, offset,
TTRS_ANYWAY | TTRS_DIRECT);
- spin_lock(&si->lock);
- if (nr_reclaim > 0) {
- offset += nr_reclaim;
- total_reclaimed += nr_reclaim;
- continue;
- } else if (nr_reclaim < 0) {
- offset += -nr_reclaim;
+ if (nr_reclaim) {
+ offset += abs(nr_reclaim);
continue;
}
}
offset++;
}
- if (to_scan <= 0 || total_reclaimed)
+ spin_lock(&si->lock);
+
+ if (to_scan <= 0)
break;
}
}
+static void swap_reclaim_work(struct work_struct *work)
+{
+ struct swap_info_struct *si;
+
+ si = container_of(work, struct swap_info_struct, reclaim_work);
+
+ spin_lock(&si->lock);
+ swap_reclaim_full_clusters(si, true);
+ spin_unlock(&si->lock);
+}
+
/*
* Try to get swap entries with specified order from current cpu's swap entry
* pool (a cluster). This might involve allocating a new cluster for current CPU
@@ -800,6 +809,10 @@ new_cluster:
goto done;
}
+ /* Try reclaim from full clusters if free clusters list is drained */
+ if (vm_swap_full())
+ swap_reclaim_full_clusters(si, false);
+
if (order < PMD_ORDER) {
unsigned int frags = 0;
@@ -881,13 +894,6 @@ new_cluster:
}
done:
- /* Try reclaim from full clusters if device is nearfull */
- if (vm_swap_full() && (!found || (si->pages - si->inuse_pages) < SWAPFILE_CLUSTER)) {
- swap_reclaim_full_clusters(si);
- if (!found && !order && si->pages != si->inuse_pages)
- goto new_cluster;
- }
-
cluster->next[order] = offset;
return found;
}
@@ -922,6 +928,9 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset,
si->lowest_bit = si->max;
si->highest_bit = 0;
del_from_avail_list(si);
+
+ if (si->cluster_info && vm_swap_full())
+ schedule_work(&si->reclaim_work);
}
}
@@ -2816,6 +2825,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
wait_for_completion(&p->comp);
flush_work(&p->discard_work);
+ flush_work(&p->reclaim_work);
destroy_swap_extents(p);
if (p->flags & SWP_CONTINUED)
@@ -3376,6 +3386,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
return PTR_ERR(si);
INIT_WORK(&si->discard_work, swap_discard_work);
+ INIT_WORK(&si->reclaim_work, swap_reclaim_work);
name = getname(specialfile);
if (IS_ERR(name)) {
diff --git a/mm/vma.c b/mm/vma.c
index 4737afcb064c..7621384d64cf 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -323,11 +323,10 @@ static bool can_vma_merge_right(struct vma_merge_struct *vmg,
/*
* Close a vm structure and free it.
*/
-void remove_vma(struct vm_area_struct *vma, bool unreachable, bool closed)
+void remove_vma(struct vm_area_struct *vma, bool unreachable)
{
might_sleep();
- if (!closed && vma->vm_ops && vma->vm_ops->close)
- vma->vm_ops->close(vma);
+ vma_close(vma);
if (vma->vm_file)
fput(vma->vm_file);
mpol_put(vma_policy(vma));
@@ -917,6 +916,7 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
pgoff_t pgoff = vmg->pgoff;
pgoff_t pglen = PHYS_PFN(end - start);
bool can_merge_left, can_merge_right;
+ bool just_expand = vmg->merge_flags & VMG_FLAG_JUST_EXPAND;
mmap_assert_write_locked(vmg->mm);
VM_WARN_ON(vmg->vma);
@@ -930,7 +930,7 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
return NULL;
can_merge_left = can_vma_merge_left(vmg);
- can_merge_right = can_vma_merge_right(vmg, can_merge_left);
+ can_merge_right = !just_expand && can_vma_merge_right(vmg, can_merge_left);
/* If we can merge with the next VMA, adjust vmg accordingly. */
if (can_merge_right) {
@@ -953,7 +953,11 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
if (can_merge_right && !can_merge_remove_vma(next))
vmg->end = end;
- vma_prev(vmg->vmi); /* Equivalent to going to the previous range */
+ /* In expand-only case we are already positioned at prev. */
+ if (!just_expand) {
+ /* Equivalent to going to the previous range. */
+ vma_prev(vmg->vmi);
+ }
}
/*
@@ -967,12 +971,14 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
}
/* If expansion failed, reset state. Allows us to retry merge later. */
- vmg->vma = NULL;
- vmg->start = start;
- vmg->end = end;
- vmg->pgoff = pgoff;
- if (vmg->vma == prev)
- vma_iter_set(vmg->vmi, start);
+ if (!just_expand) {
+ vmg->vma = NULL;
+ vmg->start = start;
+ vmg->end = end;
+ vmg->pgoff = pgoff;
+ if (vmg->vma == prev)
+ vma_iter_set(vmg->vmi, start);
+ }
return NULL;
}
@@ -1108,9 +1114,7 @@ void vms_clean_up_area(struct vma_munmap_struct *vms,
vms_clear_ptes(vms, mas_detach, true);
mas_set(mas_detach, 0);
mas_for_each(mas_detach, vma, ULONG_MAX)
- if (vma->vm_ops && vma->vm_ops->close)
- vma->vm_ops->close(vma);
- vms->closed_vm_ops = true;
+ vma_close(vma);
}
/*
@@ -1153,7 +1157,7 @@ void vms_complete_munmap_vmas(struct vma_munmap_struct *vms,
/* Remove and clean up vmas */
mas_set(mas_detach, 0);
mas_for_each(mas_detach, vma, ULONG_MAX)
- remove_vma(vma, /* = */ false, vms->closed_vm_ops);
+ remove_vma(vma, /* unreachable = */ false);
vm_unacct_memory(vms->nr_accounted);
validate_mm(mm);
@@ -1677,8 +1681,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
return new_vma;
out_vma_link:
- if (new_vma->vm_ops && new_vma->vm_ops->close)
- new_vma->vm_ops->close(new_vma);
+ vma_close(new_vma);
if (new_vma->vm_file)
fput(new_vma->vm_file);
diff --git a/mm/vma.h b/mm/vma.h
index 819f994cf727..d58068c0ff2e 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -42,8 +42,7 @@ struct vma_munmap_struct {
int vma_count; /* Number of vmas that will be removed */
bool unlock; /* Unlock after the munmap */
bool clear_ptes; /* If there are outstanding PTE to be cleared */
- bool closed_vm_ops; /* call_mmap() was encountered, so vmas may be closed */
- /* 1 byte hole */
+ /* 2 byte hole */
unsigned long nr_pages; /* Number of pages being removed */
unsigned long locked_vm; /* Number of locked pages */
unsigned long nr_accounted; /* Number of VM_ACCOUNT pages */
@@ -59,6 +58,17 @@ enum vma_merge_state {
VMA_MERGE_SUCCESS,
};
+enum vma_merge_flags {
+ VMG_FLAG_DEFAULT = 0,
+ /*
+ * If we can expand, simply do so. We know there is nothing to merge to
+ * the right. Does not reset state upon failure to merge. The VMA
+ * iterator is assumed to be positioned at the previous VMA, rather than
+ * at the gap.
+ */
+ VMG_FLAG_JUST_EXPAND = 1 << 0,
+};
+
/* Represents a VMA merge operation. */
struct vma_merge_struct {
struct mm_struct *mm;
@@ -75,6 +85,7 @@ struct vma_merge_struct {
struct mempolicy *policy;
struct vm_userfaultfd_ctx uffd_ctx;
struct anon_vma_name *anon_name;
+ enum vma_merge_flags merge_flags;
enum vma_merge_state state;
};
@@ -99,6 +110,7 @@ static inline pgoff_t vma_pgoff_offset(struct vm_area_struct *vma,
.flags = flags_, \
.pgoff = pgoff_, \
.state = VMA_MERGE_START, \
+ .merge_flags = VMG_FLAG_DEFAULT, \
}
#define VMG_VMA_STATE(name, vmi_, prev_, vma_, start_, end_) \
@@ -118,6 +130,7 @@ static inline pgoff_t vma_pgoff_offset(struct vm_area_struct *vma,
.uffd_ctx = vma_->vm_userfaultfd_ctx, \
.anon_name = anon_vma_name(vma_), \
.state = VMA_MERGE_START, \
+ .merge_flags = VMG_FLAG_DEFAULT, \
}
#ifdef CONFIG_DEBUG_VM_MAPLE_TREE
@@ -184,7 +197,6 @@ static inline void init_vma_munmap(struct vma_munmap_struct *vms,
vms->unmap_start = FIRST_USER_ADDRESS;
vms->unmap_end = USER_PGTABLES_CEILING;
vms->clear_ptes = false;
- vms->closed_vm_ops = false;
}
#endif
@@ -241,15 +253,9 @@ static inline void vms_abort_munmap_vmas(struct vma_munmap_struct *vms,
* failure method of leaving a gap where the MAP_FIXED mapping failed.
*/
mas_set_range(mas, vms->start, vms->end - 1);
- if (unlikely(mas_store_gfp(mas, NULL, GFP_KERNEL))) {
- pr_warn_once("%s: (%d) Unable to abort munmap() operation\n",
- current->comm, current->pid);
- /* Leaving vmas detached and in-tree may hamper recovery */
- reattach_vmas(mas_detach);
- } else {
- /* Clean up the insertion of the unfortunate gap */
- vms_complete_munmap_vmas(vms, mas_detach);
- }
+ mas_store_gfp(mas, NULL, GFP_KERNEL|__GFP_NOFAIL);
+ /* Clean up the insertion of the unfortunate gap */
+ vms_complete_munmap_vmas(vms, mas_detach);
}
int
@@ -261,7 +267,7 @@ int do_vmi_munmap(struct vma_iterator *vmi, struct mm_struct *mm,
unsigned long start, size_t len, struct list_head *uf,
bool unlock);
-void remove_vma(struct vm_area_struct *vma, bool unreachable, bool closed);
+void remove_vma(struct vm_area_struct *vma, bool unreachable);
void unmap_region(struct ma_state *mas, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct vm_area_struct *next);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index eb4e8440c507..28ba2b06fc7d 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -56,6 +56,7 @@
#include <linux/khugepaged.h>
#include <linux/rculist_nulls.h>
#include <linux/random.h>
+#include <linux/mmu_notifier.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -1475,7 +1476,7 @@ free_it:
*/
nr_reclaimed += nr_pages;
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
if (folio_batch_add(&free_folios, folio) == 0) {
mem_cgroup_uncharge_folios(&free_folios);
try_to_unmap_flush();
@@ -1863,7 +1864,7 @@ static unsigned int move_folios_to_lru(struct lruvec *lruvec,
if (unlikely(folio_put_testzero(folio))) {
__folio_clear_lru_flags(folio);
- folio_undo_large_rmappable(folio);
+ folio_unqueue_deferred_split(folio);
if (folio_batch_add(&free_folios, folio) == 0) {
spin_unlock_irq(&lruvec->lru_lock);
mem_cgroup_uncharge_folios(&free_folios);
@@ -3294,7 +3295,8 @@ static bool get_next_vma(unsigned long mask, unsigned long size, struct mm_walk
return false;
}
-static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr)
+static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr,
+ struct pglist_data *pgdat)
{
unsigned long pfn = pte_pfn(pte);
@@ -3306,13 +3308,20 @@ static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned
if (WARN_ON_ONCE(pte_devmap(pte) || pte_special(pte)))
return -1;
+ if (!pte_young(pte) && !mm_has_notifiers(vma->vm_mm))
+ return -1;
+
if (WARN_ON_ONCE(!pfn_valid(pfn)))
return -1;
+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
+ return -1;
+
return pfn;
}
-static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr)
+static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr,
+ struct pglist_data *pgdat)
{
unsigned long pfn = pmd_pfn(pmd);
@@ -3324,9 +3333,15 @@ static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned
if (WARN_ON_ONCE(pmd_devmap(pmd)))
return -1;
+ if (!pmd_young(pmd) && !mm_has_notifiers(vma->vm_mm))
+ return -1;
+
if (WARN_ON_ONCE(!pfn_valid(pfn)))
return -1;
+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
+ return -1;
+
return pfn;
}
@@ -3335,10 +3350,6 @@ static struct folio *get_pfn_folio(unsigned long pfn, struct mem_cgroup *memcg,
{
struct folio *folio;
- /* try to avoid unnecessary memory loads */
- if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
- return NULL;
-
folio = pfn_folio(pfn);
if (folio_nid(folio) != pgdat->node_id)
return NULL;
@@ -3394,21 +3405,16 @@ restart:
total++;
walk->mm_stats[MM_LEAF_TOTAL]++;
- pfn = get_pte_pfn(ptent, args->vma, addr);
+ pfn = get_pte_pfn(ptent, args->vma, addr, pgdat);
if (pfn == -1)
continue;
- if (!pte_young(ptent)) {
- walk->mm_stats[MM_LEAF_OLD]++;
- continue;
- }
-
folio = get_pfn_folio(pfn, memcg, pgdat, walk->can_swap);
if (!folio)
continue;
- if (!ptep_test_and_clear_young(args->vma, addr, pte + i))
- VM_WARN_ON_ONCE(true);
+ if (!ptep_clear_young_notify(args->vma, addr, pte + i))
+ continue;
young++;
walk->mm_stats[MM_LEAF_YOUNG]++;
@@ -3474,21 +3480,25 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
/* don't round down the first address */
addr = i ? (*first & PMD_MASK) + i * PMD_SIZE : *first;
- pfn = get_pmd_pfn(pmd[i], vma, addr);
- if (pfn == -1)
+ if (!pmd_present(pmd[i]))
goto next;
if (!pmd_trans_huge(pmd[i])) {
- if (!walk->force_scan && should_clear_pmd_young())
+ if (!walk->force_scan && should_clear_pmd_young() &&
+ !mm_has_notifiers(args->mm))
pmdp_test_and_clear_young(vma, addr, pmd + i);
goto next;
}
+ pfn = get_pmd_pfn(pmd[i], vma, addr, pgdat);
+ if (pfn == -1)
+ goto next;
+
folio = get_pfn_folio(pfn, memcg, pgdat, walk->can_swap);
if (!folio)
goto next;
- if (!pmdp_test_and_clear_young(vma, addr, pmd + i))
+ if (!pmdp_clear_young_notify(vma, addr, pmd + i))
goto next;
walk->mm_stats[MM_LEAF_YOUNG]++;
@@ -3546,27 +3556,18 @@ restart:
}
if (pmd_trans_huge(val)) {
- unsigned long pfn = pmd_pfn(val);
struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec);
+ unsigned long pfn = get_pmd_pfn(val, vma, addr, pgdat);
walk->mm_stats[MM_LEAF_TOTAL]++;
- if (!pmd_young(val)) {
- walk->mm_stats[MM_LEAF_OLD]++;
- continue;
- }
-
- /* try to avoid unnecessary memory loads */
- if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
- continue;
-
- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first);
+ if (pfn != -1)
+ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first);
continue;
}
- walk->mm_stats[MM_NONLEAF_TOTAL]++;
-
- if (!walk->force_scan && should_clear_pmd_young()) {
+ if (!walk->force_scan && should_clear_pmd_young() &&
+ !mm_has_notifiers(args->mm)) {
if (!pmd_young(val))
continue;
@@ -4040,13 +4041,13 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc)
* the PTE table to the Bloom filter. This forms a feedback loop between the
* eviction and the aging.
*/
-void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
+bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
{
int i;
unsigned long start;
unsigned long end;
struct lru_gen_mm_walk *walk;
- int young = 0;
+ int young = 1;
pte_t *pte = pvmw->pte;
unsigned long addr = pvmw->address;
struct vm_area_struct *vma = pvmw->vma;
@@ -4062,12 +4063,15 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
lockdep_assert_held(pvmw->ptl);
VM_WARN_ON_ONCE_FOLIO(folio_test_lru(folio), folio);
+ if (!ptep_clear_young_notify(vma, addr, pte))
+ return false;
+
if (spin_is_contended(pvmw->ptl))
- return;
+ return true;
/* exclude special VMAs containing anon pages from COW */
if (vma->vm_flags & VM_SPECIAL)
- return;
+ return true;
/* avoid taking the LRU lock under the PTL when possible */
walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL;
@@ -4075,6 +4079,9 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
start = max(addr & PMD_MASK, vma->vm_start);
end = min(addr | ~PMD_MASK, vma->vm_end - 1) + 1;
+ if (end - start == PAGE_SIZE)
+ return true;
+
if (end - start > MIN_LRU_BATCH * PAGE_SIZE) {
if (addr - start < MIN_LRU_BATCH * PAGE_SIZE / 2)
end = start + MIN_LRU_BATCH * PAGE_SIZE;
@@ -4088,7 +4095,7 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
/* folio_update_gen() requires stable folio_memcg() */
if (!mem_cgroup_trylock_pages(memcg))
- return;
+ return true;
arch_enter_lazy_mmu_mode();
@@ -4098,19 +4105,16 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
unsigned long pfn;
pte_t ptent = ptep_get(pte + i);
- pfn = get_pte_pfn(ptent, vma, addr);
+ pfn = get_pte_pfn(ptent, vma, addr, pgdat);
if (pfn == -1)
continue;
- if (!pte_young(ptent))
- continue;
-
folio = get_pfn_folio(pfn, memcg, pgdat, can_swap);
if (!folio)
continue;
- if (!ptep_test_and_clear_young(vma, addr, pte + i))
- VM_WARN_ON_ONCE(true);
+ if (!ptep_clear_young_notify(vma, addr, pte + i))
+ continue;
young++;
@@ -4140,6 +4144,8 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
/* feedback from rmap walkers to page table walkers */
if (mm_state && suitable_to_scan(i, young))
update_bloom_filter(mm_state, max_seq, pvmw->pmd);
+
+ return true;
}
/******************************************************************************
@@ -5254,11 +5260,11 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec,
for (tier = 0; tier < MAX_NR_TIERS; tier++) {
seq_printf(m, " %10d", tier);
for (type = 0; type < ANON_AND_FILE; type++) {
- const char *s = " ";
+ const char *s = "xxx";
unsigned long n[3] = {};
if (seq == max_seq) {
- s = "RT ";
+ s = "RTx";
n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]);
n[1] = READ_ONCE(lrugen->avg_total[type][tier]);
} else if (seq == min_seq[type] || NR_HIST_GENS > 1) {
@@ -5280,14 +5286,14 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec,
seq_puts(m, " ");
for (i = 0; i < NR_MM_STATS; i++) {
- const char *s = " ";
+ const char *s = "xxxx";
unsigned long n = 0;
if (seq == max_seq && NR_HIST_GENS == 1) {
- s = "LOYNFA";
+ s = "TYFA";
n = READ_ONCE(mm_state->stats[hist][i]);
} else if (seq != max_seq && NR_HIST_GENS > 1) {
- s = "loynfa";
+ s = "tyfa";
n = READ_ONCE(mm_state->stats[hist][i]);
}
diff --git a/mm/vmstat.c b/mm/vmstat.c
index b5a4cea423e1..ac6a5aa34eab 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1415,6 +1415,8 @@ const char * const vmstat_text[] = {
#ifdef CONFIG_SWAP
"swap_ra",
"swap_ra_hit",
+ "swpin_zero",
+ "swpout_zero",
#ifdef CONFIG_KSM
"ksm_swpin_copy",
#endif
diff --git a/mm/zswap.c b/mm/zswap.c
index 162013952074..0030ce8fecfc 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1053,7 +1053,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
count_vm_event(ZSWPWB);
if (entry->objcg)
- count_objcg_event(entry->objcg, ZSWPWB);
+ count_objcg_events(entry->objcg, ZSWPWB, 1);
zswap_entry_free(entry);
@@ -1483,7 +1483,7 @@ bool zswap_store(struct folio *folio)
if (objcg) {
obj_cgroup_charge_zswap(objcg, entry->length);
- count_objcg_event(objcg, ZSWPOUT);
+ count_objcg_events(objcg, ZSWPOUT, 1);
}
/*
@@ -1577,7 +1577,7 @@ bool zswap_load(struct folio *folio)
count_vm_event(ZSWPIN);
if (entry->objcg)
- count_objcg_event(entry->objcg, ZSWPIN);
+ count_objcg_events(entry->objcg, ZSWPIN, 1);
if (swapcache) {
zswap_entry_free(entry);
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index cf5219df7903..134419667d59 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -161,10 +161,8 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
return -ENODEV;
}
- if (data[IFLA_VLAN_PROTOCOL])
- proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]);
- else
- proto = htons(ETH_P_8021Q);
+ proto = nla_get_be16_default(data[IFLA_VLAN_PROTOCOL],
+ htons(ETH_P_8021Q));
vlan->vlan_proto = proto;
vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index c4c74b82ed21..d097e308a755 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -952,6 +952,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
conn->tx_power = HCI_TX_POWER_INVALID;
conn->max_tx_power = HCI_TX_POWER_INVALID;
conn->sync_handle = HCI_SYNC_HANDLE_INVALID;
+ conn->sid = HCI_SID_INVALID;
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -1127,9 +1128,9 @@ void hci_conn_del(struct hci_conn *conn)
hci_conn_unlink(conn);
- cancel_delayed_work_sync(&conn->disc_work);
- cancel_delayed_work_sync(&conn->auto_accept_work);
- cancel_delayed_work_sync(&conn->idle_work);
+ disable_delayed_work_sync(&conn->disc_work);
+ disable_delayed_work_sync(&conn->auto_accept_work);
+ disable_delayed_work_sync(&conn->idle_work);
if (conn->type == ACL_LINK) {
/* Unacked frames */
@@ -2062,105 +2063,217 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
{
- struct hci_cp_le_pa_create_sync *cp = data;
-
bt_dev_dbg(hdev, "");
if (err)
bt_dev_err(hdev, "Unable to create PA: %d", err);
+}
- kfree(cp);
+static bool hci_conn_check_create_pa_sync(struct hci_conn *conn)
+{
+ if (conn->type != ISO_LINK || conn->sid == HCI_SID_INVALID)
+ return false;
+
+ return true;
}
static int create_pa_sync(struct hci_dev *hdev, void *data)
{
- struct hci_cp_le_pa_create_sync *cp = data;
- int err;
+ struct hci_cp_le_pa_create_sync cp = {0};
+ struct hci_conn *conn;
+ int err = 0;
- err = __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC,
- sizeof(*cp), cp, HCI_CMD_TIMEOUT);
- if (err) {
- hci_dev_clear_flag(hdev, HCI_PA_SYNC);
- return err;
+ hci_dev_lock(hdev);
+
+ rcu_read_lock();
+
+ /* The spec allows only one pending LE Periodic Advertising Create
+ * Sync command at a time. If the command is pending now, don't do
+ * anything. We check for pending connections after each PA Sync
+ * Established event.
+ *
+ * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
+ * page 2493:
+ *
+ * If the Host issues this command when another HCI_LE_Periodic_
+ * Advertising_Create_Sync command is pending, the Controller shall
+ * return the error code Command Disallowed (0x0C).
+ */
+ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+ if (test_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags))
+ goto unlock;
}
- return hci_update_passive_scan_sync(hdev);
+ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+ if (hci_conn_check_create_pa_sync(conn)) {
+ struct bt_iso_qos *qos = &conn->iso_qos;
+
+ cp.options = qos->bcast.options;
+ cp.sid = conn->sid;
+ cp.addr_type = conn->dst_type;
+ bacpy(&cp.addr, &conn->dst);
+ cp.skip = cpu_to_le16(qos->bcast.skip);
+ cp.sync_timeout = cpu_to_le16(qos->bcast.sync_timeout);
+ cp.sync_cte_type = qos->bcast.sync_cte_type;
+
+ break;
+ }
+ }
+
+unlock:
+ rcu_read_unlock();
+
+ hci_dev_unlock(hdev);
+
+ if (bacmp(&cp.addr, BDADDR_ANY)) {
+ hci_dev_set_flag(hdev, HCI_PA_SYNC);
+ set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
+
+ err = __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC,
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+ if (!err)
+ err = hci_update_passive_scan_sync(hdev);
+
+ if (err) {
+ hci_dev_clear_flag(hdev, HCI_PA_SYNC);
+ clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
+ }
+ }
+
+ return err;
+}
+
+int hci_pa_create_sync_pending(struct hci_dev *hdev)
+{
+ /* Queue start pa_create_sync and scan */
+ return hci_cmd_sync_queue(hdev, create_pa_sync,
+ NULL, create_pa_complete);
}
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, __u8 sid,
struct bt_iso_qos *qos)
{
- struct hci_cp_le_pa_create_sync *cp;
struct hci_conn *conn;
- int err;
-
- if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC))
- return ERR_PTR(-EBUSY);
conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_SLAVE);
if (IS_ERR(conn))
return conn;
conn->iso_qos = *qos;
+ conn->dst_type = dst_type;
+ conn->sid = sid;
conn->state = BT_LISTEN;
hci_conn_hold(conn);
- cp = kzalloc(sizeof(*cp), GFP_KERNEL);
- if (!cp) {
- hci_dev_clear_flag(hdev, HCI_PA_SYNC);
- hci_conn_drop(conn);
- return ERR_PTR(-ENOMEM);
+ hci_pa_create_sync_pending(hdev);
+
+ return conn;
+}
+
+static bool hci_conn_check_create_big_sync(struct hci_conn *conn)
+{
+ if (!conn->num_bis)
+ return false;
+
+ return true;
+}
+
+static void big_create_sync_complete(struct hci_dev *hdev, void *data, int err)
+{
+ bt_dev_dbg(hdev, "");
+
+ if (err)
+ bt_dev_err(hdev, "Unable to create BIG sync: %d", err);
+}
+
+static int big_create_sync(struct hci_dev *hdev, void *data)
+{
+ DEFINE_FLEX(struct hci_cp_le_big_create_sync, pdu, bis, num_bis, 0x11);
+ struct hci_conn *conn;
+
+ rcu_read_lock();
+
+ pdu->num_bis = 0;
+
+ /* The spec allows only one pending LE BIG Create Sync command at
+ * a time. If the command is pending now, don't do anything. We
+ * check for pending connections after each BIG Sync Established
+ * event.
+ *
+ * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
+ * page 2586:
+ *
+ * If the Host sends this command when the Controller is in the
+ * process of synchronizing to any BIG, i.e. the HCI_LE_BIG_Sync_
+ * Established event has not been generated, the Controller shall
+ * return the error code Command Disallowed (0x0C).
+ */
+ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+ if (test_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags))
+ goto unlock;
}
- cp->options = qos->bcast.options;
- cp->sid = sid;
- cp->addr_type = dst_type;
- bacpy(&cp->addr, dst);
- cp->skip = cpu_to_le16(qos->bcast.skip);
- cp->sync_timeout = cpu_to_le16(qos->bcast.sync_timeout);
- cp->sync_cte_type = qos->bcast.sync_cte_type;
+ list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+ if (hci_conn_check_create_big_sync(conn)) {
+ struct bt_iso_qos *qos = &conn->iso_qos;
- /* Queue start pa_create_sync and scan */
- err = hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
- if (err < 0) {
- hci_conn_drop(conn);
- kfree(cp);
- return ERR_PTR(err);
+ set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+
+ pdu->handle = qos->bcast.big;
+ pdu->sync_handle = cpu_to_le16(conn->sync_handle);
+ pdu->encryption = qos->bcast.encryption;
+ memcpy(pdu->bcode, qos->bcast.bcode,
+ sizeof(pdu->bcode));
+ pdu->mse = qos->bcast.mse;
+ pdu->timeout = cpu_to_le16(qos->bcast.timeout);
+ pdu->num_bis = conn->num_bis;
+ memcpy(pdu->bis, conn->bis, conn->num_bis);
+
+ break;
+ }
}
- return conn;
+unlock:
+ rcu_read_unlock();
+
+ if (!pdu->num_bis)
+ return 0;
+
+ return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC,
+ struct_size(pdu, bis, pdu->num_bis), pdu);
+}
+
+int hci_le_big_create_sync_pending(struct hci_dev *hdev)
+{
+ /* Queue big_create_sync */
+ return hci_cmd_sync_queue_once(hdev, big_create_sync,
+ NULL, big_create_sync_complete);
}
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
struct bt_iso_qos *qos,
__u16 sync_handle, __u8 num_bis, __u8 bis[])
{
- DEFINE_FLEX(struct hci_cp_le_big_create_sync, pdu, bis, num_bis, 0x11);
int err;
- if (num_bis < 0x01 || num_bis > pdu->num_bis)
+ if (num_bis < 0x01 || num_bis > ISO_MAX_NUM_BIS)
return -EINVAL;
err = qos_set_big(hdev, qos);
if (err)
return err;
- if (hcon)
- hcon->iso_qos.bcast.big = qos->bcast.big;
+ if (hcon) {
+ /* Update hcon QoS */
+ hcon->iso_qos = *qos;
- pdu->handle = qos->bcast.big;
- pdu->sync_handle = cpu_to_le16(sync_handle);
- pdu->encryption = qos->bcast.encryption;
- memcpy(pdu->bcode, qos->bcast.bcode, sizeof(pdu->bcode));
- pdu->mse = qos->bcast.mse;
- pdu->timeout = cpu_to_le16(qos->bcast.timeout);
- pdu->num_bis = num_bis;
- memcpy(pdu->bis, bis, num_bis);
+ hcon->num_bis = num_bis;
+ memcpy(hcon->bis, bis, num_bis);
+ }
- return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC,
- struct_size(pdu, bis, num_bis), pdu);
+ return hci_le_big_create_sync_pending(hdev);
}
static void create_big_complete(struct hci_dev *hdev, void *data, int err)
@@ -2224,13 +2337,9 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
conn->iso_qos.bcast.big);
if (parent && parent != conn) {
link = hci_conn_link(parent, conn);
- if (!link) {
- hci_conn_drop(conn);
- return ERR_PTR(-ENOLINK);
- }
-
- /* Link takes the refcount */
hci_conn_drop(conn);
+ if (!link)
+ return ERR_PTR(-ENOLINK);
}
return conn;
@@ -2320,15 +2429,12 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
}
link = hci_conn_link(le, cis);
+ hci_conn_drop(cis);
if (!link) {
hci_conn_drop(le);
- hci_conn_drop(cis);
return ERR_PTR(-ENOLINK);
}
- /* Link takes the refcount */
- hci_conn_drop(cis);
-
cis->state = BT_CONNECT;
hci_le_create_cis_pending(hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 96d097b21d13..f9e19f9cb5a3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3771,25 +3771,27 @@ static void hci_tx_work(struct work_struct *work)
/* ACL data packet */
static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_acl_hdr *hdr = (void *) skb->data;
+ struct hci_acl_hdr *hdr;
struct hci_conn *conn;
__u16 handle, flags;
- skb_pull(skb, HCI_ACL_HDR_SIZE);
+ hdr = skb_pull_data(skb, sizeof(*hdr));
+ if (!hdr) {
+ bt_dev_err(hdev, "ACL packet too small");
+ goto drop;
+ }
handle = __le16_to_cpu(hdr->handle);
flags = hci_flags(handle);
handle = hci_handle(handle);
- BT_DBG("%s len %d handle 0x%4.4x flags 0x%4.4x", hdev->name, skb->len,
- handle, flags);
+ bt_dev_dbg(hdev, "len %d handle 0x%4.4x flags 0x%4.4x", skb->len,
+ handle, flags);
hdev->stat.acl_rx++;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, handle);
- if (conn && hci_dev_test_flag(hdev, HCI_MGMT))
- mgmt_device_connected(hdev, conn, NULL, 0);
hci_dev_unlock(hdev);
if (conn) {
@@ -3803,24 +3805,29 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
handle);
}
+drop:
kfree_skb(skb);
}
/* SCO data packet */
static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
- struct hci_sco_hdr *hdr = (void *) skb->data;
+ struct hci_sco_hdr *hdr;
struct hci_conn *conn;
__u16 handle, flags;
- skb_pull(skb, HCI_SCO_HDR_SIZE);
+ hdr = skb_pull_data(skb, sizeof(*hdr));
+ if (!hdr) {
+ bt_dev_err(hdev, "SCO packet too small");
+ goto drop;
+ }
handle = __le16_to_cpu(hdr->handle);
flags = hci_flags(handle);
handle = hci_handle(handle);
- BT_DBG("%s len %d handle 0x%4.4x flags 0x%4.4x", hdev->name, skb->len,
- handle, flags);
+ bt_dev_dbg(hdev, "len %d handle 0x%4.4x flags 0x%4.4x", skb->len,
+ handle, flags);
hdev->stat.sco_rx++;
@@ -3838,6 +3845,7 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
handle);
}
+drop:
kfree_skb(skb);
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0bbad90ddd6f..aca121408369 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3626,6 +3626,13 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
goto unlock;
}
+ /* We skip the WRITE_AUTH_PAYLOAD_TIMEOUT for ATS2851 based controllers
+ * to avoid unexpected SMP command errors when pairing.
+ */
+ if (test_bit(HCI_QUIRK_BROKEN_WRITE_AUTH_PAYLOAD_TIMEOUT,
+ &hdev->quirks))
+ goto notify;
+
/* Set the default Authenticated Payload Timeout after
* an LE Link is established. As per Core Spec v5.0, Vol 2, Part B
* Section 3.3, the HCI command WRITE_AUTH_PAYLOAD_TIMEOUT should be
@@ -6345,7 +6352,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
struct hci_ev_le_pa_sync_established *ev = data;
int mask = hdev->link_mode;
__u8 flags = 0;
- struct hci_conn *pa_sync;
+ struct hci_conn *pa_sync, *conn;
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
@@ -6353,6 +6360,20 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
+ conn = hci_conn_hash_lookup_sid(hdev, ev->sid, &ev->bdaddr,
+ ev->bdaddr_type);
+ if (!conn) {
+ bt_dev_err(hdev,
+ "Unable to find connection for dst %pMR sid 0x%2.2x",
+ &ev->bdaddr, ev->sid);
+ goto unlock;
+ }
+
+ clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
+
+ conn->sync_handle = le16_to_cpu(ev->handle);
+ conn->sid = HCI_SID_INVALID;
+
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ISO_LINK, &flags);
if (!(mask & HCI_LM_ACCEPT)) {
hci_le_pa_term_sync(hdev, ev->handle);
@@ -6379,6 +6400,9 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
}
unlock:
+ /* Handle any other pending PA sync command */
+ hci_pa_create_sync_pending(hdev);
+
hci_dev_unlock(hdev);
}
@@ -6896,7 +6920,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_evt_le_big_sync_estabilished *ev = data;
- struct hci_conn *bis;
+ struct hci_conn *bis, *conn;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
@@ -6907,6 +6931,20 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
+ conn = hci_conn_hash_lookup_big_sync_pend(hdev, ev->handle,
+ ev->num_bis);
+ if (!conn) {
+ bt_dev_err(hdev,
+ "Unable to find connection for big 0x%2.2x",
+ ev->handle);
+ goto unlock;
+ }
+
+ clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+
+ conn->num_bis = 0;
+ memset(conn->bis, 0, sizeof(conn->num_bis));
+
for (i = 0; i < ev->num_bis; i++) {
u16 handle = le16_to_cpu(ev->bis[i]);
__le32 interval;
@@ -6927,6 +6965,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
/* Mark PA sync as established */
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
+ bis->sync_handle = conn->sync_handle;
bis->iso_qos.bcast.big = ev->handle;
memset(&interval, 0, sizeof(interval));
memcpy(&interval, ev->latency, sizeof(ev->latency));
@@ -6956,6 +6995,10 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
hci_connect_cfm(bis, ev->status);
}
+unlock:
+ /* Handle any other pending BIG sync command */
+ hci_le_big_create_sync_pending(hdev);
+
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index ae7a5817883a..c86f4e42e69c 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -206,6 +206,12 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
return ERR_PTR(err);
}
+ /* If command return a status event skb will be set to NULL as there are
+ * no parameters.
+ */
+ if (!skb)
+ return ERR_PTR(-ENODATA);
+
return skb;
}
EXPORT_SYMBOL(__hci_cmd_sync_sk);
@@ -255,6 +261,11 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
u8 status;
skb = __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout, sk);
+
+ /* If command return a status event, skb will be set to -ENODATA */
+ if (skb == ERR_PTR(-ENODATA))
+ return 0;
+
if (IS_ERR(skb)) {
if (!event)
bt_dev_err(hdev, "Opcode 0x%4.4x failed: %ld", opcode,
@@ -262,13 +273,6 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
return PTR_ERR(skb);
}
- /* If command return a status event skb will be set to NULL as there are
- * no parameters, in case of failure IS_ERR(skb) would have be set to
- * the actual error would be found with PTR_ERR(skb).
- */
- if (!skb)
- return 0;
-
status = skb->data[0];
kfree_skb(skb);
@@ -4838,6 +4842,13 @@ static const struct {
HCI_QUIRK_BROKEN(SET_RPA_TIMEOUT,
"HCI LE Set Random Private Address Timeout command is "
"advertised, but not supported."),
+ HCI_QUIRK_BROKEN(EXT_CREATE_CONN,
+ "HCI LE Extended Create Connection command is "
+ "advertised, but not supported."),
+ HCI_QUIRK_BROKEN(WRITE_AUTH_PAYLOAD_TIMEOUT,
+ "HCI WRITE AUTH PAYLOAD TIMEOUT command leads "
+ "to unexpected SMP errors when pairing "
+ "and will not be used."),
HCI_QUIRK_BROKEN(LE_CODED,
"HCI LE Coded PHY feature bit is set, "
"but its usage is not supported.")
@@ -6473,7 +6484,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
&own_addr_type);
if (err)
goto done;
-
+ /* Send command LE Extended Create Connection if supported */
if (use_ext_conn(hdev)) {
err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
goto done;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 367e32fe30eb..4b54dbbf0729 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -21,16 +21,6 @@ static const struct device_type bt_link = {
.release = bt_link_release,
};
-/*
- * The rfcomm tty device will possibly retain even when conn
- * is down, and sysfs doesn't support move zombie device,
- * so we should move the device before conn device is destroyed.
- */
-static int __match_tty(struct device *dev, void *data)
-{
- return !strncmp(dev_name(dev), "rfcomm", 6);
-}
-
void hci_conn_init_sysfs(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -73,10 +63,13 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
return;
}
+ /* If there are devices using the connection as parent reset it to NULL
+ * before unregistering the device.
+ */
while (1) {
struct device *dev;
- dev = device_find_child(&conn->dev, NULL, __match_tty);
+ dev = device_find_any_child(&conn->dev);
if (!dev)
break;
device_move(dev, NULL, DPM_ORDER_DEV_LAST);
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 7a83e400ac77..1b40fd2b2f02 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -35,6 +35,7 @@ struct iso_conn {
struct sk_buff *rx_skb;
__u32 rx_len;
__u16 tx_sn;
+ struct kref ref;
};
#define iso_conn_lock(c) spin_lock(&(c)->lock)
@@ -93,6 +94,49 @@ static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst,
#define ISO_CONN_TIMEOUT (HZ * 40)
#define ISO_DISCONN_TIMEOUT (HZ * 2)
+static void iso_conn_free(struct kref *ref)
+{
+ struct iso_conn *conn = container_of(ref, struct iso_conn, ref);
+
+ BT_DBG("conn %p", conn);
+
+ if (conn->sk)
+ iso_pi(conn->sk)->conn = NULL;
+
+ if (conn->hcon) {
+ conn->hcon->iso_data = NULL;
+ hci_conn_drop(conn->hcon);
+ }
+
+ /* Ensure no more work items will run since hci_conn has been dropped */
+ disable_delayed_work_sync(&conn->timeout_work);
+
+ kfree(conn);
+}
+
+static void iso_conn_put(struct iso_conn *conn)
+{
+ if (!conn)
+ return;
+
+ BT_DBG("conn %p refcnt %d", conn, kref_read(&conn->ref));
+
+ kref_put(&conn->ref, iso_conn_free);
+}
+
+static struct iso_conn *iso_conn_hold_unless_zero(struct iso_conn *conn)
+{
+ if (!conn)
+ return NULL;
+
+ BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref));
+
+ if (!kref_get_unless_zero(&conn->ref))
+ return NULL;
+
+ return conn;
+}
+
static struct sock *iso_sock_hold(struct iso_conn *conn)
{
if (!conn || !bt_sock_linked(&iso_sk_list, conn->sk))
@@ -109,9 +153,14 @@ static void iso_sock_timeout(struct work_struct *work)
timeout_work.work);
struct sock *sk;
+ conn = iso_conn_hold_unless_zero(conn);
+ if (!conn)
+ return;
+
iso_conn_lock(conn);
sk = iso_sock_hold(conn);
iso_conn_unlock(conn);
+ iso_conn_put(conn);
if (!sk)
return;
@@ -149,9 +198,14 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon)
{
struct iso_conn *conn = hcon->iso_data;
+ conn = iso_conn_hold_unless_zero(conn);
if (conn) {
- if (!conn->hcon)
+ if (!conn->hcon) {
+ iso_conn_lock(conn);
conn->hcon = hcon;
+ iso_conn_unlock(conn);
+ }
+ iso_conn_put(conn);
return conn;
}
@@ -159,6 +213,7 @@ static struct iso_conn *iso_conn_add(struct hci_conn *hcon)
if (!conn)
return NULL;
+ kref_init(&conn->ref);
spin_lock_init(&conn->lock);
INIT_DELAYED_WORK(&conn->timeout_work, iso_sock_timeout);
@@ -178,17 +233,15 @@ static void iso_chan_del(struct sock *sk, int err)
struct sock *parent;
conn = iso_pi(sk)->conn;
+ iso_pi(sk)->conn = NULL;
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
if (conn) {
iso_conn_lock(conn);
conn->sk = NULL;
- iso_pi(sk)->conn = NULL;
iso_conn_unlock(conn);
-
- if (conn->hcon)
- hci_conn_drop(conn->hcon);
+ iso_conn_put(conn);
}
sk->sk_state = BT_CLOSED;
@@ -210,6 +263,7 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
struct iso_conn *conn = hcon->iso_data;
struct sock *sk;
+ conn = iso_conn_hold_unless_zero(conn);
if (!conn)
return;
@@ -219,20 +273,18 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
iso_conn_lock(conn);
sk = iso_sock_hold(conn);
iso_conn_unlock(conn);
+ iso_conn_put(conn);
- if (sk) {
- lock_sock(sk);
- iso_sock_clear_timer(sk);
- iso_chan_del(sk, err);
- release_sock(sk);
- sock_put(sk);
+ if (!sk) {
+ iso_conn_put(conn);
+ return;
}
- /* Ensure no more work items will run before freeing conn. */
- cancel_delayed_work_sync(&conn->timeout_work);
-
- hcon->iso_data = NULL;
- kfree(conn);
+ lock_sock(sk);
+ iso_sock_clear_timer(sk);
+ iso_chan_del(sk, err);
+ release_sock(sk);
+ sock_put(sk);
}
static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,
@@ -652,6 +704,8 @@ static void iso_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
+ iso_conn_put(iso_pi(sk)->conn);
+
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
}
@@ -711,6 +765,7 @@ static void iso_sock_disconn(struct sock *sk)
*/
if (bis_sk) {
hcon->state = BT_OPEN;
+ hcon->iso_data = NULL;
iso_pi(sk)->conn->hcon = NULL;
iso_sock_clear_timer(sk);
iso_chan_del(sk, bt_to_errno(hcon->abort_reason));
@@ -720,7 +775,6 @@ static void iso_sock_disconn(struct sock *sk)
}
sk->sk_state = BT_DISCONN;
- iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
iso_conn_lock(iso_pi(sk)->conn);
hci_conn_drop(iso_pi(sk)->conn->hcon);
iso_pi(sk)->conn->hcon = NULL;
@@ -1338,6 +1392,13 @@ static void iso_conn_big_sync(struct sock *sk)
if (!hdev)
return;
+ /* hci_le_big_create_sync requires hdev lock to be held, since
+ * it enqueues the HCI LE BIG Create Sync command via
+ * hci_cmd_sync_queue_once, which checks hdev flags that might
+ * change.
+ */
+ hci_dev_lock(hdev);
+
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
&iso_pi(sk)->qos,
@@ -1348,6 +1409,8 @@ static void iso_conn_big_sync(struct sock *sk)
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
err);
}
+
+ hci_dev_unlock(hdev);
}
static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -1733,6 +1796,13 @@ static bool iso_match_big(struct sock *sk, void *data)
return ev->handle == iso_pi(sk)->qos.bcast.big;
}
+static bool iso_match_big_hcon(struct sock *sk, void *data)
+{
+ struct hci_conn *hcon = data;
+
+ return hcon->iso_qos.bcast.big == iso_pi(sk)->qos.bcast.big;
+}
+
static bool iso_match_pa_sync_flag(struct sock *sk, void *data)
{
return test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
@@ -1756,8 +1826,16 @@ static void iso_conn_ready(struct iso_conn *conn)
if (!hcon)
return;
- if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags) ||
- test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
+ if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags)) {
+ /* A BIS slave hcon is notified to the ISO layer
+ * after the Command Complete for the LE Setup
+ * ISO Data Path command is received. Get the
+ * parent socket that matches the hcon BIG handle.
+ */
+ parent = iso_get_sock(&hcon->src, &hcon->dst,
+ BT_LISTEN, iso_match_big_hcon,
+ hcon);
+ } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
ev = hci_recv_event_data(hcon->hdev,
HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
@@ -1824,7 +1902,6 @@ static void iso_conn_ready(struct iso_conn *conn)
if (!bacmp(&hcon->dst, BDADDR_ANY)) {
bacpy(&hcon->dst, &iso_pi(parent)->dst);
hcon->dst_type = iso_pi(parent)->dst_type;
- hcon->sync_handle = iso_pi(parent)->sync_handle;
}
if (ev3) {
@@ -1942,6 +2019,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (sk) {
int err;
+ struct hci_conn *hcon = iso_pi(sk)->conn->hcon;
iso_pi(sk)->qos.bcast.encryption = ev2->encryption;
@@ -1950,7 +2028,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (!test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags) &&
!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
- err = hci_le_big_create_sync(hdev, NULL,
+ err = hci_le_big_create_sync(hdev,
+ hcon,
&iso_pi(sk)->qos,
iso_pi(sk)->sync_handle,
iso_pi(sk)->bc_num_bis,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a429661b676a..1f6d083682b8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -132,6 +132,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_MESH_READ_FEATURES,
MGMT_OP_MESH_SEND,
MGMT_OP_MESH_SEND_CANCEL,
+ MGMT_OP_HCI_CMD_SYNC,
};
static const u16 mgmt_events[] = {
@@ -2515,6 +2516,64 @@ unlock:
return err;
}
+static int send_hci_cmd_sync(struct hci_dev *hdev, void *data)
+{
+ struct mgmt_pending_cmd *cmd = data;
+ struct mgmt_cp_hci_cmd_sync *cp = cmd->param;
+ struct sk_buff *skb;
+
+ skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
+ le16_to_cpu(cp->params_len), cp->params,
+ cp->event, cp->timeout ?
+ msecs_to_jiffies(cp->timeout * 1000) :
+ HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
+ mgmt_status(PTR_ERR(skb)));
+ goto done;
+ }
+
+ mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
+ skb->data, skb->len);
+
+ kfree_skb(skb);
+
+done:
+ mgmt_pending_free(cmd);
+
+ return 0;
+}
+
+static int mgmt_hci_cmd_sync(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 len)
+{
+ struct mgmt_cp_hci_cmd_sync *cp = data;
+ struct mgmt_pending_cmd *cmd;
+ int err;
+
+ if (len < sizeof(*cp))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ hci_dev_lock(hdev);
+ cmd = mgmt_pending_new(sk, MGMT_OP_HCI_CMD_SYNC, hdev, data, len);
+ if (!cmd)
+ err = -ENOMEM;
+ else
+ err = hci_cmd_sync_queue(hdev, send_hci_cmd_sync, cmd, NULL);
+
+ if (err < 0) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
+ MGMT_STATUS_FAILED);
+
+ if (cmd)
+ mgmt_pending_free(cmd);
+ }
+
+ hci_dev_unlock(hdev);
+ return err;
+}
+
/* This is a helper function to test for pending mgmt commands that can
* cause CoD or EIR HCI commands. We can only allow one such pending
* mgmt command at a time since otherwise we cannot easily track what
@@ -9371,6 +9430,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ mesh_send, MGMT_MESH_SEND_SIZE,
HCI_MGMT_VAR_LEN },
{ mesh_send_cancel, MGMT_MESH_SEND_CANCEL_SIZE },
+ { mgmt_hci_cmd_sync, MGMT_HCI_CMD_SYNC_SIZE, HCI_MGMT_VAR_LEN },
};
void mgmt_index_added(struct hci_dev *hdev)
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 355e1a1698f5..40766f8119ed 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -729,7 +729,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
struct sock *l2cap_sk;
struct l2cap_conn *conn;
struct rfcomm_conninfo cinfo;
- int len, err = 0;
+ int err = 0;
+ size_t len;
u32 opt;
BT_DBG("sk %p", sk);
@@ -783,7 +784,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
cinfo.hci_handle = conn->hcon->handle;
memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
- len = min_t(unsigned int, len, sizeof(cinfo));
+ len = min(len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT;
@@ -802,7 +803,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
{
struct sock *sk = sock->sk;
struct bt_security sec;
- int len, err = 0;
+ int err = 0;
+ size_t len;
BT_DBG("sk %p", sk);
@@ -827,7 +829,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
sec.level = rfcomm_pi(sk)->sec_level;
sec.key_size = 0;
- len = min_t(unsigned int, len, sizeof(sec));
+ len = min(len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 1c7252a36866..1b8e468d24cf 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -51,6 +51,7 @@ struct sco_conn {
struct delayed_work timeout_work;
unsigned int mtu;
+ struct kref ref;
};
#define sco_conn_lock(c) spin_lock(&c->lock)
@@ -76,6 +77,49 @@ struct sco_pinfo {
#define SCO_CONN_TIMEOUT (HZ * 40)
#define SCO_DISCONN_TIMEOUT (HZ * 2)
+static void sco_conn_free(struct kref *ref)
+{
+ struct sco_conn *conn = container_of(ref, struct sco_conn, ref);
+
+ BT_DBG("conn %p", conn);
+
+ if (conn->sk)
+ sco_pi(conn->sk)->conn = NULL;
+
+ if (conn->hcon) {
+ conn->hcon->sco_data = NULL;
+ hci_conn_drop(conn->hcon);
+ }
+
+ /* Ensure no more work items will run since hci_conn has been dropped */
+ disable_delayed_work_sync(&conn->timeout_work);
+
+ kfree(conn);
+}
+
+static void sco_conn_put(struct sco_conn *conn)
+{
+ if (!conn)
+ return;
+
+ BT_DBG("conn %p refcnt %d", conn, kref_read(&conn->ref));
+
+ kref_put(&conn->ref, sco_conn_free);
+}
+
+static struct sco_conn *sco_conn_hold_unless_zero(struct sco_conn *conn)
+{
+ if (!conn)
+ return NULL;
+
+ BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref));
+
+ if (!kref_get_unless_zero(&conn->ref))
+ return NULL;
+
+ return conn;
+}
+
static struct sock *sco_sock_hold(struct sco_conn *conn)
{
if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
@@ -92,6 +136,10 @@ static void sco_sock_timeout(struct work_struct *work)
timeout_work.work);
struct sock *sk;
+ conn = sco_conn_hold_unless_zero(conn);
+ if (!conn)
+ return;
+
sco_conn_lock(conn);
if (!conn->hcon) {
sco_conn_unlock(conn);
@@ -99,6 +147,7 @@ static void sco_sock_timeout(struct work_struct *work)
}
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
+ sco_conn_put(conn);
if (!sk)
return;
@@ -136,9 +185,14 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
{
struct sco_conn *conn = hcon->sco_data;
+ conn = sco_conn_hold_unless_zero(conn);
if (conn) {
- if (!conn->hcon)
+ if (!conn->hcon) {
+ sco_conn_lock(conn);
conn->hcon = hcon;
+ sco_conn_unlock(conn);
+ }
+ sco_conn_put(conn);
return conn;
}
@@ -146,6 +200,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
if (!conn)
return NULL;
+ kref_init(&conn->ref);
spin_lock_init(&conn->lock);
INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
@@ -170,17 +225,15 @@ static void sco_chan_del(struct sock *sk, int err)
struct sco_conn *conn;
conn = sco_pi(sk)->conn;
+ sco_pi(sk)->conn = NULL;
BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
if (conn) {
sco_conn_lock(conn);
conn->sk = NULL;
- sco_pi(sk)->conn = NULL;
sco_conn_unlock(conn);
-
- if (conn->hcon)
- hci_conn_drop(conn->hcon);
+ sco_conn_put(conn);
}
sk->sk_state = BT_CLOSED;
@@ -195,29 +248,28 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
struct sco_conn *conn = hcon->sco_data;
struct sock *sk;
+ conn = sco_conn_hold_unless_zero(conn);
if (!conn)
return;
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
- /* Kill socket */
sco_conn_lock(conn);
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
+ sco_conn_put(conn);
- if (sk) {
- lock_sock(sk);
- sco_sock_clear_timer(sk);
- sco_chan_del(sk, err);
- release_sock(sk);
- sock_put(sk);
+ if (!sk) {
+ sco_conn_put(conn);
+ return;
}
- /* Ensure no more work items will run before freeing conn. */
- cancel_delayed_work_sync(&conn->timeout_work);
-
- hcon->sco_data = NULL;
- kfree(conn);
+ /* Kill socket */
+ lock_sock(sk);
+ sco_sock_clear_timer(sk);
+ sco_chan_del(sk, err);
+ release_sock(sk);
+ sock_put(sk);
}
static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
@@ -401,6 +453,8 @@ static void sco_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
+ sco_conn_put(sco_pi(sk)->conn);
+
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
}
@@ -448,17 +502,6 @@ static void __sco_sock_close(struct sock *sk)
case BT_CONNECTED:
case BT_CONFIG:
- if (sco_pi(sk)->conn->hcon) {
- sk->sk_state = BT_DISCONN;
- sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
- sco_conn_lock(sco_pi(sk)->conn);
- hci_conn_drop(sco_pi(sk)->conn->hcon);
- sco_pi(sk)->conn->hcon = NULL;
- sco_conn_unlock(sco_pi(sk)->conn);
- } else
- sco_chan_del(sk, ECONNRESET);
- break;
-
case BT_CONNECT2:
case BT_CONNECT:
case BT_DISCONN:
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 6d7a442ceb89..501ec4249fed 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -246,6 +246,7 @@ static void reset_ctx(struct xdp_page_head *head)
head->ctx.data_meta = head->orig_ctx.data_meta;
head->ctx.data_end = head->orig_ctx.data_end;
xdp_update_frame_from_buff(&head->ctx, head->frame);
+ head->frame->mem = head->orig_ctx.rxq->mem;
}
static int xdp_recv_frames(struct xdp_frame **frames, int nframes,
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 1cd7bade9b3b..82bac2426631 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -1152,7 +1152,7 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
struct net_bridge_port *p, const unsigned char *addr,
u16 nlh_flags, u16 vid, struct nlattr *nfea_tb[],
- struct netlink_ext_ack *extack)
+ bool *notified, struct netlink_ext_ack *extack)
{
int err = 0;
@@ -1183,6 +1183,8 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge *br,
spin_unlock_bh(&br->hash_lock);
}
+ if (!err)
+ *notified = true;
return err;
}
@@ -1195,7 +1197,7 @@ static const struct nla_policy br_nda_fdb_pol[NFEA_MAX + 1] = {
int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid, u16 nlh_flags,
- struct netlink_ext_ack *extack)
+ bool *notified, struct netlink_ext_ack *extack)
{
struct nlattr *nfea_tb[NFEA_MAX + 1], *attr;
struct net_bridge_vlan_group *vg;
@@ -1258,10 +1260,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
/* VID was specified, so use it. */
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, vid, nfea_tb,
- extack);
+ notified, extack);
} else {
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, 0, nfea_tb,
- extack);
+ notified, extack);
if (err || !vg || !vg->num_vlans)
goto out;
@@ -1273,7 +1275,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (!br_vlan_should_use(v))
continue;
err = __br_fdb_add(ndm, br, p, addr, nlh_flags, v->vid,
- nfea_tb, extack);
+ nfea_tb, notified, extack);
if (err)
goto out;
}
@@ -1285,7 +1287,7 @@ out:
static int fdb_delete_by_addr_and_port(struct net_bridge *br,
const struct net_bridge_port *p,
- const u8 *addr, u16 vlan)
+ const u8 *addr, u16 vlan, bool *notified)
{
struct net_bridge_fdb_entry *fdb;
@@ -1294,18 +1296,19 @@ static int fdb_delete_by_addr_and_port(struct net_bridge *br,
return -ENOENT;
fdb_delete(br, fdb, true);
+ *notified = true;
return 0;
}
static int __br_fdb_delete(struct net_bridge *br,
const struct net_bridge_port *p,
- const unsigned char *addr, u16 vid)
+ const unsigned char *addr, u16 vid, bool *notified)
{
int err;
spin_lock_bh(&br->hash_lock);
- err = fdb_delete_by_addr_and_port(br, p, addr, vid);
+ err = fdb_delete_by_addr_and_port(br, p, addr, vid, notified);
spin_unlock_bh(&br->hash_lock);
return err;
@@ -1314,12 +1317,11 @@ static int __br_fdb_delete(struct net_bridge *br,
/* Remove neighbor entry with RTM_DELNEIGH */
int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
- const unsigned char *addr, u16 vid,
+ const unsigned char *addr, u16 vid, bool *notified,
struct netlink_ext_ack *extack)
{
struct net_bridge_vlan_group *vg;
struct net_bridge_port *p = NULL;
- struct net_bridge_vlan *v;
struct net_bridge *br;
int err;
@@ -1338,23 +1340,19 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
}
if (vid) {
- v = br_vlan_find(vg, vid);
- if (!v) {
- pr_info("bridge: RTM_DELNEIGH with unconfigured vlan %d on %s\n", vid, dev->name);
- return -EINVAL;
- }
-
- err = __br_fdb_delete(br, p, addr, vid);
+ err = __br_fdb_delete(br, p, addr, vid, notified);
} else {
+ struct net_bridge_vlan *v;
+
err = -ENOENT;
- err &= __br_fdb_delete(br, p, addr, 0);
+ err &= __br_fdb_delete(br, p, addr, 0, notified);
if (!vg || !vg->num_vlans)
return err;
list_for_each_entry(v, &vg->vlan_list, vlist) {
if (!br_vlan_should_use(v))
continue;
- err &= __br_fdb_delete(br, p, addr, v->vid);
+ err &= __br_fdb_delete(br, p, addr, v->vid, notified);
}
}
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 17a5f5923d61..451e45b9a6a5 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -373,8 +373,8 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
struct net_device *dev = skb->dev, *br_indev;
const struct iphdr *iph = ip_hdr(skb);
+ enum skb_drop_reason reason;
struct rtable *rt;
- int err;
br_indev = nf_bridge_get_physindev(skb, net);
if (!br_indev) {
@@ -390,9 +390,9 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
}
nf_bridge->in_prerouting = 0;
if (br_nf_ipv4_daddr_was_changed(skb, nf_bridge)) {
- err = ip_route_input(skb, iph->daddr, iph->saddr,
- ip4h_dscp(iph), dev);
- if (err) {
+ reason = ip_route_input(skb, iph->daddr, iph->saddr,
+ ip4h_dscp(iph), dev);
+ if (reason) {
struct in_device *in_dev = __in_dev_get_rcu(dev);
/* If err equals -EHOSTUNREACH the error is due to a
@@ -402,11 +402,12 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
* martian destinations: loopback destinations and destination
* 0.0.0.0. In both cases the packet will be dropped because the
* destination is the loopback device and not the bridge. */
- if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
+ if (reason != SKB_DROP_REASON_IP_INADDRERRORS || !in_dev ||
+ IN_DEV_FORWARD(in_dev))
goto free_skb;
rt = ip_route_output(net, iph->daddr, 0,
- iph->tos & INET_DSCP_MASK, 0,
+ ip4h_dscp(iph), 0,
RT_SCOPE_UNIVERSE);
if (!IS_ERR(rt)) {
/* - Bridged-and-DNAT'ed traffic doesn't
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 041f6e571a20..9853cfbb9d14 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -853,12 +853,12 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev, const unsigned char *addr, u16 vid,
- struct netlink_ext_ack *extack);
+ bool *notified, struct netlink_ext_ack *extack);
int br_fdb_delete_bulk(struct nlmsghdr *nlh, struct net_device *dev,
struct netlink_ext_ack *extack);
int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
const unsigned char *addr, u16 vid, u16 nlh_flags,
- struct netlink_ext_ack *extack);
+ bool *notified, struct netlink_ext_ack *extack);
int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev, struct net_device *fdev, int *idx);
int br_fdb_get(struct sk_buff *skb, struct nlattr *tb[], struct net_device *dev,
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index 104c0125e32e..f16bbbbb9481 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -41,7 +41,13 @@ config NF_CONNTRACK_BRIDGE
# old sockopt interface and eval loop
config BRIDGE_NF_EBTABLES_LEGACY
- tristate
+ tristate "Legacy EBTABLES support"
+ depends on BRIDGE && NETFILTER_XTABLES
+ default n
+ help
+ Legacy ebtables packet/frame classifier.
+ This is not needed if you are using ebtables over nftables
+ (iptables-nft).
menuconfig BRIDGE_NF_EBTABLES
tristate "Ethernet Bridge tables (ebtables) support"
diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c
index d12a221366d6..5adced1e7d0c 100644
--- a/net/bridge/netfilter/nft_meta_bridge.c
+++ b/net/bridge/netfilter/nft_meta_bridge.c
@@ -63,7 +63,7 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
return nft_meta_get_eval(expr, regs, pkt);
}
- strncpy((char *)dest, br_dev ? br_dev->name : "", IFNAMSIZ);
+ strscpy_pad((char *)dest, br_dev ? br_dev->name : "", IFNAMSIZ);
return;
err:
regs->verdict.code = NFT_BREAK;
diff --git a/net/core/Makefile b/net/core/Makefile
index 5a72a87ee0f1..d9326600e289 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -46,3 +46,4 @@ obj-$(CONFIG_OF) += of_net.o
obj-$(CONFIG_NET_TEST) += net_test.o
obj-$(CONFIG_NET_DEVMEM) += devmem.o
obj-$(CONFIG_DEBUG_NET_SMALL_RTNL) += rtnl_net_debug.o
+obj-$(CONFIG_FAIL_SKB_REALLOC) += skb_fault_injection.o
diff --git a/net/core/dev.c b/net/core/dev.c
index c682173a7642..13d00fc10f55 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3641,6 +3641,9 @@ int skb_csum_hwoffload_help(struct sk_buff *skb,
return 0;
if (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) {
+ if (vlan_get_protocol(skb) == htons(ETH_P_IPV6) &&
+ skb_network_header_len(skb) != sizeof(struct ipv6hdr))
+ goto sw_checksum;
switch (skb->csum_offset) {
case offsetof(struct tcphdr, check):
case offsetof(struct udphdr, check):
@@ -3648,6 +3651,7 @@ int skb_csum_hwoffload_help(struct sk_buff *skb,
}
}
+sw_checksum:
return skb_checksum_help(skb);
}
EXPORT_SYMBOL(skb_csum_hwoffload_help);
@@ -6503,6 +6507,43 @@ void napi_busy_loop(unsigned int napi_id,
}
EXPORT_SYMBOL(napi_busy_loop);
+void napi_suspend_irqs(unsigned int napi_id)
+{
+ struct napi_struct *napi;
+
+ rcu_read_lock();
+ napi = napi_by_id(napi_id);
+ if (napi) {
+ unsigned long timeout = napi_get_irq_suspend_timeout(napi);
+
+ if (timeout)
+ hrtimer_start(&napi->timer, ns_to_ktime(timeout),
+ HRTIMER_MODE_REL_PINNED);
+ }
+ rcu_read_unlock();
+}
+
+void napi_resume_irqs(unsigned int napi_id)
+{
+ struct napi_struct *napi;
+
+ rcu_read_lock();
+ napi = napi_by_id(napi_id);
+ if (napi) {
+ /* If irq_suspend_timeout is set to 0 between the call to
+ * napi_suspend_irqs and now, the original value still
+ * determines the safety timeout as intended and napi_watchdog
+ * will resume irq processing.
+ */
+ if (napi_get_irq_suspend_timeout(napi)) {
+ local_bh_disable();
+ napi_schedule(napi);
+ local_bh_enable();
+ }
+ }
+ rcu_read_unlock();
+}
+
#endif /* CONFIG_NET_RX_BUSY_POLL */
static void __napi_hash_add_with_id(struct napi_struct *napi,
@@ -6662,6 +6703,7 @@ static void napi_restore_config(struct napi_struct *n)
{
n->defer_hard_irqs = n->config->defer_hard_irqs;
n->gro_flush_timeout = n->config->gro_flush_timeout;
+ n->irq_suspend_timeout = n->config->irq_suspend_timeout;
/* a NAPI ID might be stored in the config, if so use it. if not, use
* napi_hash_add to generate one for us. It will be saved to the config
* in napi_disable.
@@ -6676,6 +6718,7 @@ static void napi_save_config(struct napi_struct *n)
{
n->config->defer_hard_irqs = n->defer_hard_irqs;
n->config->gro_flush_timeout = n->gro_flush_timeout;
+ n->config->irq_suspend_timeout = n->irq_suspend_timeout;
n->config->napi_id = n->napi_id;
napi_hash_del(n);
}
diff --git a/net/core/dev.h b/net/core/dev.h
index 7881bced70a9..d043dee25a68 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -236,6 +236,31 @@ static inline void netdev_set_gro_flush_timeout(struct net_device *netdev,
netdev->napi_config[i].gro_flush_timeout = timeout;
}
+/**
+ * napi_get_irq_suspend_timeout - get the irq_suspend_timeout
+ * @n: napi struct to get the irq_suspend_timeout from
+ *
+ * Return: the per-NAPI value of the irq_suspend_timeout field.
+ */
+static inline unsigned long
+napi_get_irq_suspend_timeout(const struct napi_struct *n)
+{
+ return READ_ONCE(n->irq_suspend_timeout);
+}
+
+/**
+ * napi_set_irq_suspend_timeout - set the irq_suspend_timeout for a napi
+ * @n: napi struct to set the irq_suspend_timeout
+ * @timeout: timeout value to set
+ *
+ * napi_set_irq_suspend_timeout sets the per-NAPI irq_suspend_timeout
+ */
+static inline void napi_set_irq_suspend_timeout(struct napi_struct *n,
+ unsigned long timeout)
+{
+ WRITE_ONCE(n->irq_suspend_timeout, timeout);
+}
+
int rps_cpumask_housekeeping(struct cpumask *mask);
#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_BPF_SYSCALL)
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index 473c437b6b53..46d43b950471 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -64,7 +64,7 @@ int dev_ifconf(struct net *net, struct ifconf __user *uifc)
}
/* Loop over the interfaces, and write an info block for each. */
- rtnl_lock();
+ rtnl_net_lock(net);
for_each_netdev(net, dev) {
if (!pos)
done = inet_gifconf(dev, NULL, 0, size);
@@ -72,12 +72,12 @@ int dev_ifconf(struct net *net, struct ifconf __user *uifc)
done = inet_gifconf(dev, pos + total,
len - total, size);
if (done < 0) {
- rtnl_unlock();
+ rtnl_net_unlock(net);
return -EFAULT;
}
total += done;
}
- rtnl_unlock();
+ rtnl_net_unlock(net);
return put_user(total, &uifc->ifc_len);
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index d0de9677f450..34185d138c95 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -558,8 +558,7 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh,
nlrule->pref = fib_default_rule_pref(ops);
}
- nlrule->proto = tb[FRA_PROTOCOL] ?
- nla_get_u8(tb[FRA_PROTOCOL]) : RTPROT_UNSPEC;
+ nlrule->proto = nla_get_u8_default(tb[FRA_PROTOCOL], RTPROT_UNSPEC);
if (tb[FRA_IIFNAME]) {
struct net_device *dev;
diff --git a/net/core/filter.c b/net/core/filter.c
index 58761263176c..6625b3f563a4 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1654,18 +1654,6 @@ void sk_reuseport_prog_free(struct bpf_prog *prog)
bpf_prog_destroy(prog);
}
-struct bpf_scratchpad {
- union {
- __be32 diff[MAX_BPF_STACK / sizeof(__be32)];
- u8 buff[MAX_BPF_STACK];
- };
- local_lock_t bh_lock;
-};
-
-static DEFINE_PER_CPU(struct bpf_scratchpad, bpf_sp) = {
- .bh_lock = INIT_LOCAL_LOCK(bh_lock),
-};
-
static inline int __bpf_try_make_writable(struct sk_buff *skb,
unsigned int write_len)
{
@@ -2022,11 +2010,6 @@ static const struct bpf_func_proto bpf_l4_csum_replace_proto = {
BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size,
__be32 *, to, u32, to_size, __wsum, seed)
{
- struct bpf_scratchpad *sp = this_cpu_ptr(&bpf_sp);
- u32 diff_size = from_size + to_size;
- int i, j = 0;
- __wsum ret;
-
/* This is quite flexible, some examples:
*
* from_size == 0, to_size > 0, seed := csum --> pushing data
@@ -2035,19 +2018,19 @@ BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size,
*
* Even for diffing, from_size and to_size don't need to be equal.
*/
- if (unlikely(((from_size | to_size) & (sizeof(__be32) - 1)) ||
- diff_size > sizeof(sp->diff)))
- return -EINVAL;
- local_lock_nested_bh(&bpf_sp.bh_lock);
- for (i = 0; i < from_size / sizeof(__be32); i++, j++)
- sp->diff[j] = ~from[i];
- for (i = 0; i < to_size / sizeof(__be32); i++, j++)
- sp->diff[j] = to[i];
+ __wsum ret = seed;
- ret = csum_partial(sp->diff, diff_size, seed);
- local_unlock_nested_bh(&bpf_sp.bh_lock);
- return ret;
+ if (from_size && to_size)
+ ret = csum_sub(csum_partial(to, to_size, ret),
+ csum_partial(from, from_size, 0));
+ else if (to_size)
+ ret = csum_partial(to, to_size, ret);
+
+ else if (from_size)
+ ret = ~csum_partial(from, from_size, ~ret);
+
+ return csum_from32to16((__force unsigned int)ret);
}
static const struct bpf_func_proto bpf_csum_diff_proto = {
@@ -2249,7 +2232,7 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
rcu_read_unlock();
return ret;
}
- rcu_read_unlock_bh();
+ rcu_read_unlock();
if (dst)
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
out_drop:
@@ -2372,7 +2355,7 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev,
struct flowi4 fl4 = {
.flowi4_flags = FLOWI_FLAG_ANYSRC,
.flowi4_mark = skb->mark,
- .flowi4_tos = ip4h->tos & INET_DSCP_MASK,
+ .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h)),
.flowi4_oif = dev->ifindex,
.flowi4_proto = ip4h->protocol,
.daddr = ip4h->daddr,
@@ -2621,18 +2604,16 @@ BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes)
static void sk_msg_reset_curr(struct sk_msg *msg)
{
- u32 i = msg->sg.start;
- u32 len = 0;
-
- do {
- len += sk_msg_elem(msg, i)->length;
- sk_msg_iter_var_next(i);
- if (len >= msg->sg.size)
- break;
- } while (i != msg->sg.end);
+ if (!msg->sg.size) {
+ msg->sg.curr = msg->sg.start;
+ msg->sg.copybreak = 0;
+ } else {
+ u32 i = msg->sg.end;
- msg->sg.curr = i;
- msg->sg.copybreak = 0;
+ sk_msg_iter_var_prev(i);
+ msg->sg.curr = i;
+ msg->sg.copybreak = msg->sg.data[i].length;
+ }
}
static const struct bpf_func_proto bpf_msg_cork_bytes_proto = {
@@ -2795,7 +2776,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
sk_msg_iter_var_next(i);
} while (i != msg->sg.end);
- if (start >= offset + l)
+ if (start > offset + l)
return -EINVAL;
space = MAX_MSG_FRAGS - sk_msg_elem_used(msg);
@@ -2820,6 +2801,8 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
raw = page_address(page);
+ if (i == msg->sg.end)
+ sk_msg_iter_var_prev(i);
psge = sk_msg_elem(msg, i);
front = start - offset;
back = psge->length - front;
@@ -2836,7 +2819,13 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
}
put_page(sg_page(psge));
- } else if (start - offset) {
+ new = i;
+ goto place_new;
+ }
+
+ if (start - offset) {
+ if (i == msg->sg.end)
+ sk_msg_iter_var_prev(i);
psge = sk_msg_elem(msg, i);
rsge = sk_msg_elem_cpy(msg, i);
@@ -2847,39 +2836,44 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
sk_msg_iter_var_next(i);
sg_unmark_end(psge);
sg_unmark_end(&rsge);
- sk_msg_iter_next(msg, end);
}
/* Slot(s) to place newly allocated data */
+ sk_msg_iter_next(msg, end);
new = i;
+ sk_msg_iter_var_next(i);
+
+ if (i == msg->sg.end) {
+ if (!rsge.length)
+ goto place_new;
+ sk_msg_iter_next(msg, end);
+ goto place_new;
+ }
/* Shift one or two slots as needed */
- if (!copy) {
- sge = sk_msg_elem_cpy(msg, i);
+ sge = sk_msg_elem_cpy(msg, new);
+ sg_unmark_end(&sge);
+ nsge = sk_msg_elem_cpy(msg, i);
+ if (rsge.length) {
sk_msg_iter_var_next(i);
- sg_unmark_end(&sge);
+ nnsge = sk_msg_elem_cpy(msg, i);
sk_msg_iter_next(msg, end);
+ }
- nsge = sk_msg_elem_cpy(msg, i);
+ while (i != msg->sg.end) {
+ msg->sg.data[i] = sge;
+ sge = nsge;
+ sk_msg_iter_var_next(i);
if (rsge.length) {
- sk_msg_iter_var_next(i);
+ nsge = nnsge;
nnsge = sk_msg_elem_cpy(msg, i);
- }
-
- while (i != msg->sg.end) {
- msg->sg.data[i] = sge;
- sge = nsge;
- sk_msg_iter_var_next(i);
- if (rsge.length) {
- nsge = nnsge;
- nnsge = sk_msg_elem_cpy(msg, i);
- } else {
- nsge = sk_msg_elem_cpy(msg, i);
- }
+ } else {
+ nsge = sk_msg_elem_cpy(msg, i);
}
}
+place_new:
/* Place newly allocated data buffer */
sk_mem_charge(msg->sk, len);
msg->sg.size += len;
@@ -2908,8 +2902,10 @@ static const struct bpf_func_proto bpf_msg_push_data_proto = {
static void sk_msg_shift_left(struct sk_msg *msg, int i)
{
+ struct scatterlist *sge = sk_msg_elem(msg, i);
int prev;
+ put_page(sg_page(sge));
do {
prev = i;
sk_msg_iter_var_next(i);
@@ -2946,6 +2942,9 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
if (unlikely(flags))
return -EINVAL;
+ if (unlikely(len == 0))
+ return 0;
+
/* First find the starting scatterlist element */
i = msg->sg.start;
do {
@@ -2958,7 +2957,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
} while (i != msg->sg.end);
/* Bounds checks: start and pop must be inside message */
- if (start >= offset + l || last >= msg->sg.size)
+ if (start >= offset + l || last > msg->sg.size)
return -EINVAL;
space = MAX_MSG_FRAGS - sk_msg_elem_used(msg);
@@ -2987,12 +2986,12 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
*/
if (start != offset) {
struct scatterlist *nsge, *sge = sk_msg_elem(msg, i);
- int a = start;
+ int a = start - offset;
int b = sge->length - pop - a;
sk_msg_iter_var_next(i);
- if (pop < sge->length - a) {
+ if (b > 0) {
if (space) {
sge->length = a;
sk_msg_shift_right(msg, i);
@@ -3011,7 +3010,6 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
if (unlikely(!page))
return -ENOMEM;
- sge->length = a;
orig = sg_page(sge);
from = sg_virt(sge);
to = page_address(page);
@@ -3021,7 +3019,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
put_page(orig);
}
pop = 0;
- } else if (pop >= sge->length - a) {
+ } else {
pop -= (sge->length - a);
sge->length = a;
}
@@ -3055,7 +3053,6 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
pop -= sge->length;
sk_msg_shift_left(msg, i);
}
- sk_msg_iter_var_next(i);
}
sk_mem_uncharge(msg->sk, len - pop);
@@ -6292,24 +6289,16 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb,
{
int ret = BPF_MTU_CHK_RET_FRAG_NEEDED;
struct net_device *dev = skb->dev;
- int skb_len, dev_len;
- int mtu = 0;
-
- if (unlikely(flags & ~(BPF_MTU_CHK_SEGS))) {
- ret = -EINVAL;
- goto out;
- }
+ int mtu, dev_len, skb_len;
- if (unlikely(flags & BPF_MTU_CHK_SEGS && (len_diff || *mtu_len))) {
- ret = -EINVAL;
- goto out;
- }
+ if (unlikely(flags & ~(BPF_MTU_CHK_SEGS)))
+ return -EINVAL;
+ if (unlikely(flags & BPF_MTU_CHK_SEGS && (len_diff || *mtu_len)))
+ return -EINVAL;
dev = __dev_via_ifindex(dev, ifindex);
- if (unlikely(!dev)) {
- ret = -ENODEV;
- goto out;
- }
+ if (unlikely(!dev))
+ return -ENODEV;
mtu = READ_ONCE(dev->mtu);
dev_len = mtu + dev->hard_header_len;
@@ -6344,19 +6333,15 @@ BPF_CALL_5(bpf_xdp_check_mtu, struct xdp_buff *, xdp,
struct net_device *dev = xdp->rxq->dev;
int xdp_len = xdp->data_end - xdp->data;
int ret = BPF_MTU_CHK_RET_SUCCESS;
- int mtu = 0, dev_len;
+ int mtu, dev_len;
/* XDP variant doesn't support multi-buffer segment check (yet) */
- if (unlikely(flags)) {
- ret = -EINVAL;
- goto out;
- }
+ if (unlikely(flags))
+ return -EINVAL;
dev = __dev_via_ifindex(dev, ifindex);
- if (unlikely(!dev)) {
- ret = -ENODEV;
- goto out;
- }
+ if (unlikely(!dev))
+ return -ENODEV;
mtu = READ_ONCE(dev->mtu);
dev_len = mtu + dev->hard_header_len;
@@ -6368,7 +6353,7 @@ BPF_CALL_5(bpf_xdp_check_mtu, struct xdp_buff *, xdp,
xdp_len += len_diff; /* minus result pass check */
if (xdp_len > dev_len)
ret = BPF_MTU_CHK_RET_FRAG_NEEDED;
-out:
+
*mtu_len = mtu;
return ret;
}
@@ -6379,7 +6364,7 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
.arg4_type = ARG_ANYTHING,
.arg5_type = ARG_ANYTHING,
@@ -6391,7 +6376,7 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
- .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
+ .arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_WRITE | MEM_ALIGNED,
.arg3_size = sizeof(u32),
.arg4_type = ARG_ANYTHING,
.arg5_type = ARG_ANYTHING,
diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
index e0ca24a58810..ae74634310a3 100644
--- a/net/core/lwt_bpf.c
+++ b/net/core/lwt_bpf.c
@@ -88,6 +88,7 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt,
static int bpf_lwt_input_reroute(struct sk_buff *skb)
{
+ enum skb_drop_reason reason;
int err = -EINVAL;
if (skb->protocol == htons(ETH_P_IP)) {
@@ -96,8 +97,9 @@ static int bpf_lwt_input_reroute(struct sk_buff *skb)
dev_hold(dev);
skb_dst_drop(skb);
- err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
- ip4h_dscp(iph), dev);
+ reason = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+ ip4h_dscp(iph), dev);
+ err = reason ? -EINVAL : 0;
dev_put(dev);
} else if (skb->protocol == htons(ETH_P_IPV6)) {
skb_dst_drop(skb);
@@ -207,7 +209,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb)
fl4.flowi4_oif = oif;
fl4.flowi4_mark = skb->mark;
fl4.flowi4_uid = sock_net_uid(net, sk);
- fl4.flowi4_tos = iph->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph));
fl4.flowi4_flags = FLOWI_FLAG_ANYSRC;
fl4.flowi4_proto = iph->protocol;
fl4.daddr = iph->daddr;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 4b871cecd2ce..5e572f6eaf2c 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -60,6 +60,25 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
static const struct seq_operations neigh_stat_seq_ops;
#endif
+static struct hlist_head *neigh_get_dev_table(struct net_device *dev, int family)
+{
+ int i;
+
+ switch (family) {
+ default:
+ DEBUG_NET_WARN_ON_ONCE(1);
+ fallthrough; /* to avoid panic by null-ptr-deref */
+ case AF_INET:
+ i = NEIGH_ARP_TABLE;
+ break;
+ case AF_INET6:
+ i = NEIGH_ND_TABLE;
+ break;
+ }
+
+ return &dev->neighbours[i];
+}
+
/*
Neighbour hash table buckets are protected with rwlock tbl->lock.
@@ -204,18 +223,14 @@ static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
}
}
-static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
- struct neigh_table *tbl)
+bool neigh_remove_one(struct neighbour *n)
{
bool retval = false;
write_lock(&n->lock);
if (refcount_read(&n->refcnt) == 1) {
- struct neighbour *neigh;
-
- neigh = rcu_dereference_protected(n->next,
- lockdep_is_held(&tbl->lock));
- rcu_assign_pointer(*np, neigh);
+ hlist_del_rcu(&n->hash);
+ hlist_del_rcu(&n->dev_list);
neigh_mark_dead(n);
retval = true;
}
@@ -225,29 +240,6 @@ static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
return retval;
}
-bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
-{
- struct neigh_hash_table *nht;
- void *pkey = ndel->primary_key;
- u32 hash_val;
- struct neighbour *n;
- struct neighbour __rcu **np;
-
- nht = rcu_dereference_protected(tbl->nht,
- lockdep_is_held(&tbl->lock));
- hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
- hash_val = hash_val >> (32 - nht->hash_shift);
-
- np = &nht->hash_buckets[hash_val];
- while ((n = rcu_dereference_protected(*np,
- lockdep_is_held(&tbl->lock)))) {
- if (n == ndel)
- return neigh_del(n, np, tbl);
- np = &n->next;
- }
- return false;
-}
-
static int neigh_forced_gc(struct neigh_table *tbl)
{
int max_clean = atomic_read(&tbl->gc_entries) -
@@ -275,7 +267,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
remove = true;
write_unlock(&n->lock);
- if (remove && neigh_remove_one(n, tbl))
+ if (remove && neigh_remove_one(n))
shrunk++;
if (shrunk >= max_clean)
break;
@@ -379,54 +371,42 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
bool skip_perm)
{
- int i;
- struct neigh_hash_table *nht;
+ struct hlist_head *dev_head;
+ struct hlist_node *tmp;
+ struct neighbour *n;
- nht = rcu_dereference_protected(tbl->nht,
- lockdep_is_held(&tbl->lock));
+ dev_head = neigh_get_dev_table(dev, tbl->family);
- for (i = 0; i < (1 << nht->hash_shift); i++) {
- struct neighbour *n;
- struct neighbour __rcu **np = &nht->hash_buckets[i];
+ hlist_for_each_entry_safe(n, tmp, dev_head, dev_list) {
+ if (skip_perm && n->nud_state & NUD_PERMANENT)
+ continue;
- while ((n = rcu_dereference_protected(*np,
- lockdep_is_held(&tbl->lock))) != NULL) {
- if (dev && n->dev != dev) {
- np = &n->next;
- continue;
- }
- if (skip_perm && n->nud_state & NUD_PERMANENT) {
- np = &n->next;
- continue;
- }
- rcu_assign_pointer(*np,
- rcu_dereference_protected(n->next,
- lockdep_is_held(&tbl->lock)));
- write_lock(&n->lock);
- neigh_del_timer(n);
- neigh_mark_dead(n);
- if (refcount_read(&n->refcnt) != 1) {
- /* The most unpleasant situation.
- We must destroy neighbour entry,
- but someone still uses it.
-
- The destroy will be delayed until
- the last user releases us, but
- we must kill timers etc. and move
- it to safe state.
- */
- __skb_queue_purge(&n->arp_queue);
- n->arp_queue_len_bytes = 0;
- WRITE_ONCE(n->output, neigh_blackhole);
- if (n->nud_state & NUD_VALID)
- n->nud_state = NUD_NOARP;
- else
- n->nud_state = NUD_NONE;
- neigh_dbg(2, "neigh %p is stray\n", n);
- }
- write_unlock(&n->lock);
- neigh_cleanup_and_release(n);
+ hlist_del_rcu(&n->hash);
+ hlist_del_rcu(&n->dev_list);
+ write_lock(&n->lock);
+ neigh_del_timer(n);
+ neigh_mark_dead(n);
+ if (refcount_read(&n->refcnt) != 1) {
+ /* The most unpleasant situation.
+ * We must destroy neighbour entry,
+ * but someone still uses it.
+ *
+ * The destroy will be delayed until
+ * the last user releases us, but
+ * we must kill timers etc. and move
+ * it to safe state.
+ */
+ __skb_queue_purge(&n->arp_queue);
+ n->arp_queue_len_bytes = 0;
+ WRITE_ONCE(n->output, neigh_blackhole);
+ if (n->nud_state & NUD_VALID)
+ n->nud_state = NUD_NOARP;
+ else
+ n->nud_state = NUD_NONE;
+ neigh_dbg(2, "neigh %p is stray\n", n);
}
+ write_unlock(&n->lock);
+ neigh_cleanup_and_release(n);
}
}
@@ -529,20 +509,21 @@ static void neigh_get_hash_rnd(u32 *x)
static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
{
- size_t size = (1 << shift) * sizeof(struct neighbour *);
+ size_t size = (1 << shift) * sizeof(struct hlist_head);
+ struct hlist_head *hash_heads;
struct neigh_hash_table *ret;
- struct neighbour __rcu **buckets;
int i;
ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
if (!ret)
return NULL;
- buckets = kvzalloc(size, GFP_ATOMIC);
- if (!buckets) {
+
+ hash_heads = kvzalloc(size, GFP_ATOMIC);
+ if (!hash_heads) {
kfree(ret);
return NULL;
}
- ret->hash_buckets = buckets;
+ ret->hash_heads = hash_heads;
ret->hash_shift = shift;
for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
neigh_get_hash_rnd(&ret->hash_rnd[i]);
@@ -555,7 +536,7 @@ static void neigh_hash_free_rcu(struct rcu_head *head)
struct neigh_hash_table,
rcu);
- kvfree(nht->hash_buckets);
+ kvfree(nht->hash_heads);
kfree(nht);
}
@@ -574,24 +555,17 @@ static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
return old_nht;
for (i = 0; i < (1 << old_nht->hash_shift); i++) {
- struct neighbour *n, *next;
+ struct hlist_node *tmp;
+ struct neighbour *n;
- for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
- lockdep_is_held(&tbl->lock));
- n != NULL;
- n = next) {
+ neigh_for_each_in_bucket_safe(n, tmp, &old_nht->hash_heads[i]) {
hash = tbl->hash(n->primary_key, n->dev,
new_nht->hash_rnd);
hash >>= (32 - new_nht->hash_shift);
- next = rcu_dereference_protected(n->next,
- lockdep_is_held(&tbl->lock));
- rcu_assign_pointer(n->next,
- rcu_dereference_protected(
- new_nht->hash_buckets[hash],
- lockdep_is_held(&tbl->lock)));
- rcu_assign_pointer(new_nht->hash_buckets[hash], n);
+ hlist_del_rcu(&n->hash);
+ hlist_add_head_rcu(&n->hash, &new_nht->hash_heads[hash]);
}
}
@@ -678,11 +652,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
goto out_tbl_unlock;
}
- for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
- lockdep_is_held(&tbl->lock));
- n1 != NULL;
- n1 = rcu_dereference_protected(n1->next,
- lockdep_is_held(&tbl->lock))) {
+ neigh_for_each_in_bucket(n1, &nht->hash_heads[hash_val]) {
if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
if (want_ref)
neigh_hold(n1);
@@ -698,10 +668,11 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
list_add_tail(&n->managed_list, &n->tbl->managed_list);
if (want_ref)
neigh_hold(n);
- rcu_assign_pointer(n->next,
- rcu_dereference_protected(nht->hash_buckets[hash_val],
- lockdep_is_held(&tbl->lock)));
- rcu_assign_pointer(nht->hash_buckets[hash_val], n);
+ hlist_add_head_rcu(&n->hash, &nht->hash_heads[hash_val]);
+
+ hlist_add_head_rcu(&n->dev_list,
+ neigh_get_dev_table(dev, tbl->family));
+
write_unlock_bh(&tbl->lock);
neigh_dbg(2, "neigh %p is created\n", n);
rc = n;
@@ -933,10 +904,10 @@ static void neigh_connect(struct neighbour *neigh)
static void neigh_periodic_work(struct work_struct *work)
{
struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
+ struct neigh_hash_table *nht;
+ struct hlist_node *tmp;
struct neighbour *n;
- struct neighbour __rcu **np;
unsigned int i;
- struct neigh_hash_table *nht;
NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
@@ -961,10 +932,7 @@ static void neigh_periodic_work(struct work_struct *work)
goto out;
for (i = 0 ; i < (1 << nht->hash_shift); i++) {
- np = &nht->hash_buckets[i];
-
- while ((n = rcu_dereference_protected(*np,
- lockdep_is_held(&tbl->lock))) != NULL) {
+ neigh_for_each_in_bucket_safe(n, tmp, &nht->hash_heads[i]) {
unsigned int state;
write_lock(&n->lock);
@@ -973,7 +941,7 @@ static void neigh_periodic_work(struct work_struct *work)
if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
(n->flags & NTF_EXT_LEARNED)) {
write_unlock(&n->lock);
- goto next_elt;
+ continue;
}
if (time_before(n->used, n->confirmed) &&
@@ -984,18 +952,14 @@ static void neigh_periodic_work(struct work_struct *work)
(state == NUD_FAILED ||
!time_in_range_open(jiffies, n->used,
n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
- rcu_assign_pointer(*np,
- rcu_dereference_protected(n->next,
- lockdep_is_held(&tbl->lock)));
+ hlist_del_rcu(&n->hash);
+ hlist_del_rcu(&n->dev_list);
neigh_mark_dead(n);
write_unlock(&n->lock);
neigh_cleanup_and_release(n);
continue;
}
write_unlock(&n->lock);
-
-next_elt:
- np = &n->next;
}
/*
* It's fine to release lock here, even if hash table
@@ -1942,7 +1906,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
NETLINK_CB(skb).portid, extack);
write_lock_bh(&tbl->lock);
neigh_release(neigh);
- neigh_remove_one(neigh, tbl);
+ neigh_remove_one(neigh);
write_unlock_bh(&tbl->lock);
out:
@@ -2713,9 +2677,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
for (h = s_h; h < (1 << nht->hash_shift); h++) {
if (h > s_h)
s_idx = 0;
- for (n = rcu_dereference(nht->hash_buckets[h]), idx = 0;
- n != NULL;
- n = rcu_dereference(n->next)) {
+ idx = 0;
+ neigh_for_each_in_bucket_rcu(n, &nht->hash_heads[h]) {
if (idx < s_idx || !net_eq(dev_net(n->dev), net))
goto next;
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
@@ -3082,9 +3045,7 @@ void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
struct neighbour *n;
- for (n = rcu_dereference(nht->hash_buckets[chain]);
- n != NULL;
- n = rcu_dereference(n->next))
+ neigh_for_each_in_bucket(n, &nht->hash_heads[chain])
cb(n, cookie);
}
read_unlock_bh(&tbl->lock);
@@ -3096,29 +3057,25 @@ EXPORT_SYMBOL(neigh_for_each);
void __neigh_for_each_release(struct neigh_table *tbl,
int (*cb)(struct neighbour *))
{
- int chain;
struct neigh_hash_table *nht;
+ int chain;
nht = rcu_dereference_protected(tbl->nht,
lockdep_is_held(&tbl->lock));
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
+ struct hlist_node *tmp;
struct neighbour *n;
- struct neighbour __rcu **np;
- np = &nht->hash_buckets[chain];
- while ((n = rcu_dereference_protected(*np,
- lockdep_is_held(&tbl->lock))) != NULL) {
+ neigh_for_each_in_bucket_safe(n, tmp, &nht->hash_heads[chain]) {
int release;
write_lock(&n->lock);
release = cb(n);
if (release) {
- rcu_assign_pointer(*np,
- rcu_dereference_protected(n->next,
- lockdep_is_held(&tbl->lock)));
+ hlist_del_rcu(&n->hash);
+ hlist_del_rcu(&n->dev_list);
neigh_mark_dead(n);
- } else
- np = &n->next;
+ }
write_unlock(&n->lock);
if (release)
neigh_cleanup_and_release(n);
@@ -3175,43 +3132,53 @@ EXPORT_SYMBOL(neigh_xmit);
#ifdef CONFIG_PROC_FS
-static struct neighbour *neigh_get_first(struct seq_file *seq)
+static struct neighbour *neigh_get_valid(struct seq_file *seq,
+ struct neighbour *n,
+ loff_t *pos)
{
struct neigh_seq_state *state = seq->private;
struct net *net = seq_file_net(seq);
+
+ if (!net_eq(dev_net(n->dev), net))
+ return NULL;
+
+ if (state->neigh_sub_iter) {
+ loff_t fakep = 0;
+ void *v;
+
+ v = state->neigh_sub_iter(state, n, pos ? pos : &fakep);
+ if (!v)
+ return NULL;
+ if (pos)
+ return v;
+ }
+
+ if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
+ return n;
+
+ if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
+ return n;
+
+ return NULL;
+}
+
+static struct neighbour *neigh_get_first(struct seq_file *seq)
+{
+ struct neigh_seq_state *state = seq->private;
struct neigh_hash_table *nht = state->nht;
- struct neighbour *n = NULL;
- int bucket;
+ struct neighbour *n, *tmp;
state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
- for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
- n = rcu_dereference(nht->hash_buckets[bucket]);
-
- while (n) {
- if (!net_eq(dev_net(n->dev), net))
- goto next;
- if (state->neigh_sub_iter) {
- loff_t fakep = 0;
- void *v;
- v = state->neigh_sub_iter(state, n, &fakep);
- if (!v)
- goto next;
- }
- if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
- break;
- if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
- break;
-next:
- n = rcu_dereference(n->next);
+ while (++state->bucket < (1 << nht->hash_shift)) {
+ neigh_for_each_in_bucket(n, &nht->hash_heads[state->bucket]) {
+ tmp = neigh_get_valid(seq, n, NULL);
+ if (tmp)
+ return tmp;
}
-
- if (n)
- break;
}
- state->bucket = bucket;
- return n;
+ return NULL;
}
static struct neighbour *neigh_get_next(struct seq_file *seq,
@@ -3219,46 +3186,28 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
loff_t *pos)
{
struct neigh_seq_state *state = seq->private;
- struct net *net = seq_file_net(seq);
- struct neigh_hash_table *nht = state->nht;
+ struct neighbour *tmp;
if (state->neigh_sub_iter) {
void *v = state->neigh_sub_iter(state, n, pos);
+
if (v)
return n;
}
- n = rcu_dereference(n->next);
- while (1) {
- while (n) {
- if (!net_eq(dev_net(n->dev), net))
- goto next;
- if (state->neigh_sub_iter) {
- void *v = state->neigh_sub_iter(state, n, pos);
- if (v)
- return n;
- goto next;
- }
- if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
- break;
-
- if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
- break;
-next:
- n = rcu_dereference(n->next);
+ hlist_for_each_entry_continue(n, hash) {
+ tmp = neigh_get_valid(seq, n, pos);
+ if (tmp) {
+ n = tmp;
+ goto out;
}
-
- if (n)
- break;
-
- if (++state->bucket >= (1 << nht->hash_shift))
- break;
-
- n = rcu_dereference(nht->hash_buckets[state->bucket]);
}
+ n = neigh_get_first(seq);
+out:
if (n && pos)
--(*pos);
+
return n;
}
@@ -3361,7 +3310,7 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
struct neigh_seq_state *state = seq->private;
state->tbl = tbl;
- state->bucket = 0;
+ state->bucket = -1;
state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
rcu_read_lock();
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 809b48c0a528..157021ced442 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -56,7 +56,6 @@ static bool init_net_initialized;
* outside.
*/
DECLARE_RWSEM(pernet_ops_rwsem);
-EXPORT_SYMBOL_GPL(pernet_ops_rwsem);
#define MIN_PERNET_OPS_ID \
((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *))
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index 21de7e10be16..a89cbd8d87c3 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -92,10 +92,11 @@ static const struct nla_policy netdev_bind_rx_nl_policy[NETDEV_A_DMABUF_FD + 1]
};
/* NETDEV_CMD_NAPI_SET - do */
-static const struct nla_policy netdev_napi_set_nl_policy[NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT + 1] = {
+static const struct nla_policy netdev_napi_set_nl_policy[NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT + 1] = {
[NETDEV_A_NAPI_ID] = { .type = NLA_U32, },
[NETDEV_A_NAPI_DEFER_HARD_IRQS] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_napi_defer_hard_irqs_range),
[NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT] = { .type = NLA_UINT, },
+ [NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT] = { .type = NLA_UINT, },
};
/* Ops table for netdev */
@@ -186,7 +187,7 @@ static const struct genl_split_ops netdev_nl_ops[] = {
.cmd = NETDEV_CMD_NAPI_SET,
.doit = netdev_nl_napi_set_doit,
.policy = netdev_napi_set_nl_policy,
- .maxattr = NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT,
+ .maxattr = NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT,
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
},
};
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index b49c3b4e5fbe..fa119ff68698 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -161,6 +161,7 @@ static int
netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi,
const struct genl_info *info)
{
+ unsigned long irq_suspend_timeout;
unsigned long gro_flush_timeout;
u32 napi_defer_hard_irqs;
void *hdr;
@@ -196,6 +197,11 @@ netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi,
napi_defer_hard_irqs))
goto nla_put_failure;
+ irq_suspend_timeout = napi_get_irq_suspend_timeout(napi);
+ if (nla_put_uint(rsp, NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT,
+ irq_suspend_timeout))
+ goto nla_put_failure;
+
gro_flush_timeout = napi_get_gro_flush_timeout(napi);
if (nla_put_uint(rsp, NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT,
gro_flush_timeout))
@@ -306,6 +312,7 @@ int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
static int
netdev_nl_napi_set_config(struct napi_struct *napi, struct genl_info *info)
{
+ u64 irq_suspend_timeout = 0;
u64 gro_flush_timeout = 0;
u32 defer = 0;
@@ -314,6 +321,11 @@ netdev_nl_napi_set_config(struct napi_struct *napi, struct genl_info *info)
napi_set_defer_hard_irqs(napi, defer);
}
+ if (info->attrs[NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT]) {
+ irq_suspend_timeout = nla_get_uint(info->attrs[NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT]);
+ napi_set_irq_suspend_timeout(napi, irq_suspend_timeout);
+ }
+
if (info->attrs[NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT]) {
gro_flush_timeout = nla_get_uint(info->attrs[NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT]);
napi_set_gro_flush_timeout(napi, gro_flush_timeout);
@@ -334,6 +346,7 @@ int netdev_nl_napi_set_doit(struct sk_buff *skb, struct genl_info *info)
napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_ID]);
rtnl_lock();
+ rcu_read_lock();
napi = napi_by_id(napi_id);
if (napi) {
@@ -343,6 +356,7 @@ int netdev_nl_napi_set_doit(struct sk_buff *skb, struct genl_info *info)
err = -ENOENT;
}
+ rcu_read_unlock();
rtnl_unlock();
return err;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 94b7f07a952f..00e1e4a32902 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -45,9 +45,6 @@
#define MAX_UDP_CHUNK 1460
#define MAX_SKBS 32
-
-static struct sk_buff_head skb_pool;
-
#define USEC_PER_POLL 50
#define MAX_SKB_SIZE \
@@ -234,20 +231,23 @@ void netpoll_poll_enable(struct net_device *dev)
up(&ni->dev_lock);
}
-static void refill_skbs(void)
+static void refill_skbs(struct netpoll *np)
{
+ struct sk_buff_head *skb_pool;
struct sk_buff *skb;
unsigned long flags;
- spin_lock_irqsave(&skb_pool.lock, flags);
- while (skb_pool.qlen < MAX_SKBS) {
+ skb_pool = &np->skb_pool;
+
+ spin_lock_irqsave(&skb_pool->lock, flags);
+ while (skb_pool->qlen < MAX_SKBS) {
skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
if (!skb)
break;
- __skb_queue_tail(&skb_pool, skb);
+ __skb_queue_tail(skb_pool, skb);
}
- spin_unlock_irqrestore(&skb_pool.lock, flags);
+ spin_unlock_irqrestore(&skb_pool->lock, flags);
}
static void zap_completion_queue(void)
@@ -284,12 +284,12 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
struct sk_buff *skb;
zap_completion_queue();
- refill_skbs();
+ refill_skbs(np);
repeat:
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb)
- skb = skb_dequeue(&skb_pool);
+ skb = skb_dequeue(&np->skb_pool);
if (!skb) {
if (++count < 10) {
@@ -531,6 +531,14 @@ static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
return -1;
}
+static void skb_pool_flush(struct netpoll *np)
+{
+ struct sk_buff_head *skb_pool;
+
+ skb_pool = &np->skb_pool;
+ skb_queue_purge_reason(skb_pool, SKB_CONSUMED);
+}
+
int netpoll_parse_options(struct netpoll *np, char *opt)
{
char *cur=opt, *delim;
@@ -673,6 +681,8 @@ int netpoll_setup(struct netpoll *np)
struct in_device *in_dev;
int err;
+ skb_queue_head_init(&np->skb_pool);
+
rtnl_lock();
if (np->dev_name[0]) {
struct net *net = current->nsproxy->net_ns;
@@ -773,14 +783,16 @@ put_noaddr:
}
/* fill up the skb queue */
- refill_skbs();
+ refill_skbs(np);
err = __netpoll_setup(np, ndev);
if (err)
- goto put;
+ goto flush;
rtnl_unlock();
return 0;
+flush:
+ skb_pool_flush(np);
put:
DEBUG_NET_WARN_ON_ONCE(np->dev);
if (ip_overwritten)
@@ -792,13 +804,6 @@ unlock:
}
EXPORT_SYMBOL(netpoll_setup);
-static int __init netpoll_init(void)
-{
- skb_queue_head_init(&skb_pool);
- return 0;
-}
-core_initcall(netpoll_init);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
@@ -835,6 +840,8 @@ void __netpoll_cleanup(struct netpoll *np)
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
} else
RCU_INIT_POINTER(np->dev->npinfo, NULL);
+
+ skb_pool_flush(np);
}
EXPORT_SYMBOL_GPL(__netpoll_cleanup);
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index a813d30d2135..f89cf93f6eb4 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -950,6 +950,7 @@ netmem_ref page_pool_alloc_frag_netmem(struct page_pool *pool,
if (netmem && *offset + size > max_size) {
netmem = page_pool_drain_frag(pool, netmem);
if (netmem) {
+ recycle_stat_inc(pool, cached);
alloc_stat_inc(pool, fast);
goto frag_reset;
}
@@ -974,7 +975,6 @@ frag_reset:
pool->frag_users++;
pool->frag_offset = *offset + size;
- alloc_stat_inc(pool, fast);
return netmem;
}
EXPORT_SYMBOL(page_pool_alloc_frag_netmem);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 194a81e5f608..dd142f444659 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -210,6 +210,17 @@ void rtnl_net_unlock(struct net *net)
}
EXPORT_SYMBOL(rtnl_net_unlock);
+int rtnl_net_trylock(struct net *net)
+{
+ int ret = rtnl_trylock();
+
+ if (ret)
+ __rtnl_net_lock(net);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtnl_net_trylock);
+
static int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b)
{
if (net_eq(net_a, net_b))
@@ -247,8 +258,87 @@ bool lockdep_rtnl_net_is_held(struct net *net)
return lockdep_rtnl_is_held() && lockdep_is_held(&net->rtnl_mutex);
}
EXPORT_SYMBOL(lockdep_rtnl_net_is_held);
+#else
+static int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b)
+{
+ /* No need to swap */
+ return -1;
+}
#endif
+struct rtnl_nets {
+ /* ->newlink() needs to freeze 3 netns at most;
+ * 2 for the new device, 1 for its peer.
+ */
+ struct net *net[3];
+ unsigned char len;
+};
+
+static void rtnl_nets_init(struct rtnl_nets *rtnl_nets)
+{
+ memset(rtnl_nets, 0, sizeof(*rtnl_nets));
+}
+
+static void rtnl_nets_destroy(struct rtnl_nets *rtnl_nets)
+{
+ int i;
+
+ for (i = 0; i < rtnl_nets->len; i++) {
+ put_net(rtnl_nets->net[i]);
+ rtnl_nets->net[i] = NULL;
+ }
+
+ rtnl_nets->len = 0;
+}
+
+/**
+ * rtnl_nets_add - Add netns to be locked before ->newlink().
+ *
+ * @rtnl_nets: rtnl_nets pointer passed to ->get_peer_net().
+ * @net: netns pointer with an extra refcnt held.
+ *
+ * The extra refcnt is released in rtnl_nets_destroy().
+ */
+static void rtnl_nets_add(struct rtnl_nets *rtnl_nets, struct net *net)
+{
+ int i;
+
+ DEBUG_NET_WARN_ON_ONCE(rtnl_nets->len == ARRAY_SIZE(rtnl_nets->net));
+
+ for (i = 0; i < rtnl_nets->len; i++) {
+ switch (rtnl_net_cmp_locks(rtnl_nets->net[i], net)) {
+ case 0:
+ put_net(net);
+ return;
+ case 1:
+ swap(rtnl_nets->net[i], net);
+ }
+ }
+
+ rtnl_nets->net[i] = net;
+ rtnl_nets->len++;
+}
+
+static void rtnl_nets_lock(struct rtnl_nets *rtnl_nets)
+{
+ int i;
+
+ rtnl_lock();
+
+ for (i = 0; i < rtnl_nets->len; i++)
+ __rtnl_net_lock(rtnl_nets->net[i]);
+}
+
+static void rtnl_nets_unlock(struct rtnl_nets *rtnl_nets)
+{
+ int i;
+
+ for (i = 0; i < rtnl_nets->len; i++)
+ __rtnl_net_unlock(rtnl_nets->net[i]);
+
+ rtnl_unlock();
+}
+
static struct rtnl_link __rcu *__rcu *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];
static inline int rtm_msgindex(int msgtype)
@@ -455,6 +545,7 @@ void __rtnl_unregister_many(const struct rtnl_msg_handler *handlers, int n)
}
EXPORT_SYMBOL_GPL(__rtnl_unregister_many);
+static DEFINE_MUTEX(link_ops_mutex);
static LIST_HEAD(link_ops);
static struct rtnl_link_ops *rtnl_link_ops_get(const char *kind, int *srcu_index)
@@ -483,27 +574,20 @@ static void rtnl_link_ops_put(struct rtnl_link_ops *ops, int srcu_index)
}
/**
- * __rtnl_link_register - Register rtnl_link_ops with rtnetlink.
+ * rtnl_link_register - Register rtnl_link_ops with rtnetlink.
* @ops: struct rtnl_link_ops * to register
*
- * The caller must hold the rtnl_mutex. This function should be used
- * by drivers that create devices during module initialization. It
- * must be called before registering the devices.
- *
* Returns 0 on success or a negative error code.
*/
-int __rtnl_link_register(struct rtnl_link_ops *ops)
+int rtnl_link_register(struct rtnl_link_ops *ops)
{
struct rtnl_link_ops *tmp;
int err;
- /* When RTNL is removed, add lock for link_ops. */
- ASSERT_RTNL();
-
- list_for_each_entry(tmp, &link_ops, list) {
- if (!strcmp(ops->kind, tmp->kind))
- return -EEXIST;
- }
+ /* Sanity-check max sizes to avoid stack buffer overflow. */
+ if (WARN_ON(ops->maxtype > RTNL_MAX_TYPE ||
+ ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE))
+ return -EINVAL;
/* The check for alloc/setup is here because if ops
* does not have that filled up, it is not possible
@@ -517,30 +601,19 @@ int __rtnl_link_register(struct rtnl_link_ops *ops)
if (err)
return err;
- list_add_tail_rcu(&ops->list, &link_ops);
+ mutex_lock(&link_ops_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(__rtnl_link_register);
-
-/**
- * rtnl_link_register - Register rtnl_link_ops with rtnetlink.
- * @ops: struct rtnl_link_ops * to register
- *
- * Returns 0 on success or a negative error code.
- */
-int rtnl_link_register(struct rtnl_link_ops *ops)
-{
- int err;
+ list_for_each_entry(tmp, &link_ops, list) {
+ if (!strcmp(ops->kind, tmp->kind)) {
+ err = -EEXIST;
+ goto unlock;
+ }
+ }
- /* Sanity-check max sizes to avoid stack buffer overflow. */
- if (WARN_ON(ops->maxtype > RTNL_MAX_TYPE ||
- ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE))
- return -EINVAL;
+ list_add_tail_rcu(&ops->list, &link_ops);
+unlock:
+ mutex_unlock(&link_ops_mutex);
- rtnl_lock();
- err = __rtnl_link_register(ops);
- rtnl_unlock();
return err;
}
EXPORT_SYMBOL_GPL(rtnl_link_register);
@@ -557,27 +630,6 @@ static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
unregister_netdevice_many(&list_kill);
}
-/**
- * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
- * @ops: struct rtnl_link_ops * to unregister
- *
- * The caller must hold the rtnl_mutex and guarantee net_namespace_list
- * integrity (hold pernet_ops_rwsem for writing to close the race
- * with setup_net() and cleanup_net()).
- */
-void __rtnl_link_unregister(struct rtnl_link_ops *ops)
-{
- struct net *net;
-
- list_del_rcu(&ops->list);
- synchronize_srcu(&ops->srcu);
- cleanup_srcu_struct(&ops->srcu);
-
- for_each_net(net)
- __rtnl_kill_links(net, ops);
-}
-EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
-
/* Return with the rtnl_lock held when there are no network
* devices unregistering in any network namespace.
*/
@@ -606,10 +658,22 @@ static void rtnl_lock_unregistering_all(void)
*/
void rtnl_link_unregister(struct rtnl_link_ops *ops)
{
+ struct net *net;
+
+ mutex_lock(&link_ops_mutex);
+ list_del_rcu(&ops->list);
+ mutex_unlock(&link_ops_mutex);
+
+ synchronize_srcu(&ops->srcu);
+ cleanup_srcu_struct(&ops->srcu);
+
/* Close the race with setup_net() and cleanup_net() */
down_write(&pernet_ops_rwsem);
rtnl_lock_unregistering_all();
- __rtnl_link_unregister(ops);
+
+ for_each_net(net)
+ __rtnl_kill_links(net, ops);
+
rtnl_unlock();
up_write(&pernet_ops_rwsem);
}
@@ -697,7 +761,7 @@ static void rtnl_af_put(struct rtnl_af_ops *ops, int srcu_index)
* rtnl_af_register - Register rtnl_af_ops with rtnetlink.
* @ops: struct rtnl_af_ops * to register
*
- * Returns 0 on success or a negative error code.
+ * Return: 0 on success or a negative error code.
*/
int rtnl_af_register(struct rtnl_af_ops *ops)
{
@@ -2129,7 +2193,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
[IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
[IFLA_GSO_MAX_SEGS] = { .type = NLA_U32 },
- [IFLA_GSO_MAX_SIZE] = { .type = NLA_U32 },
+ [IFLA_GSO_MAX_SIZE] = NLA_POLICY_MIN(NLA_U32, MAX_TCP_HEADER + 1),
[IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
[IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */
[IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
@@ -2154,7 +2218,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_TSO_MAX_SIZE] = { .type = NLA_REJECT },
[IFLA_TSO_MAX_SEGS] = { .type = NLA_REJECT },
[IFLA_ALLMULTI] = { .type = NLA_REJECT },
- [IFLA_GSO_IPV4_MAX_SIZE] = { .type = NLA_U32 },
+ [IFLA_GSO_IPV4_MAX_SIZE] = NLA_POLICY_MIN(NLA_U32, MAX_TCP_HEADER + 1),
[IFLA_GRO_IPV4_MAX_SIZE] = { .type = NLA_U32 },
};
@@ -2448,9 +2512,10 @@ int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer,
}
EXPORT_SYMBOL(rtnl_nla_parse_ifinfomsg);
-struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
+static struct net *rtnl_link_get_net_ifla(struct nlattr *tb[])
{
- struct net *net;
+ struct net *net = NULL;
+
/* Examine the link attributes and figure out which
* network namespace we are talking about.
*/
@@ -2458,8 +2523,17 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
else if (tb[IFLA_NET_NS_FD])
net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
- else
+
+ return net;
+}
+
+struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
+{
+ struct net *net = rtnl_link_get_net_ifla(tb);
+
+ if (!net)
net = get_net(src_net);
+
return net;
}
EXPORT_SYMBOL(rtnl_link_get_net);
@@ -2929,10 +3003,7 @@ static int do_setlink(const struct sk_buff *skb, struct net_device *dev,
const char *pat = ifname[0] ? ifname : NULL;
int new_ifindex;
- if (tb[IFLA_NEW_IFINDEX])
- new_ifindex = nla_get_s32(tb[IFLA_NEW_IFINDEX]);
- else
- new_ifindex = 0;
+ new_ifindex = nla_get_s32_default(tb[IFLA_NEW_IFINDEX], 0);
err = __dev_change_net_namespace(dev, tgt_net, pat, new_ifindex);
if (err)
@@ -3308,6 +3379,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFLA_MAX+1];
struct net_device *dev = NULL;
+ struct rtnl_nets rtnl_nets;
struct net *tgt_net;
int err;
@@ -3326,6 +3398,12 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
goto errout;
}
+ rtnl_nets_init(&rtnl_nets);
+ rtnl_nets_add(&rtnl_nets, get_net(net));
+ rtnl_nets_add(&rtnl_nets, tgt_net);
+
+ rtnl_nets_lock(&rtnl_nets);
+
if (ifm->ifi_index > 0)
dev = __dev_get_by_index(net, ifm->ifi_index);
else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME])
@@ -3338,7 +3416,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
else if (!err)
err = -ENODEV;
- put_net(tgt_net);
+ rtnl_nets_unlock(&rtnl_nets);
errout:
return err;
}
@@ -3423,6 +3501,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
return PTR_ERR(tgt_net);
}
+ rtnl_net_lock(tgt_net);
+
if (ifm->ifi_index > 0)
dev = __dev_get_by_index(tgt_net, ifm->ifi_index);
else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME])
@@ -3437,6 +3517,8 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
else
err = -EINVAL;
+ rtnl_net_unlock(tgt_net);
+
if (netnsid >= 0)
put_net(tgt_net);
@@ -3724,6 +3806,37 @@ out_unregister:
goto out;
}
+static int rtnl_add_peer_net(struct rtnl_nets *rtnl_nets,
+ const struct rtnl_link_ops *ops,
+ struct nlattr *data[],
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *tb[IFLA_MAX + 1];
+ struct net *net;
+ int err;
+
+ if (!data || !data[ops->peer_type])
+ return 0;
+
+ err = rtnl_nla_parse_ifinfomsg(tb, data[ops->peer_type], extack);
+ if (err < 0)
+ return err;
+
+ if (ops->validate) {
+ err = ops->validate(tb, NULL, extack);
+ if (err < 0)
+ return err;
+ }
+
+ net = rtnl_link_get_net_ifla(tb);
+ if (IS_ERR(net))
+ return PTR_ERR(net);
+ if (net)
+ rtnl_nets_add(rtnl_nets, net);
+
+ return 0;
+}
+
static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
const struct rtnl_link_ops *ops,
struct net *tgt_net, struct net *link_net,
@@ -3785,6 +3898,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct net *tgt_net, *link_net = NULL;
struct rtnl_link_ops *ops = NULL;
struct rtnl_newlink_tbs *tbs;
+ struct rtnl_nets rtnl_nets;
int ops_srcu_index;
int ret;
@@ -3820,17 +3934,19 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
ops = rtnl_link_ops_get(kind, &ops_srcu_index);
#ifdef CONFIG_MODULES
if (!ops) {
- __rtnl_unlock();
request_module("rtnl-link-%s", kind);
- rtnl_lock();
ops = rtnl_link_ops_get(kind, &ops_srcu_index);
}
#endif
}
+ rtnl_nets_init(&rtnl_nets);
+
if (ops) {
- if (ops->maxtype > RTNL_MAX_TYPE)
- return -EINVAL;
+ if (ops->maxtype > RTNL_MAX_TYPE) {
+ ret = -EINVAL;
+ goto put_ops;
+ }
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
ret = nla_parse_nested_deprecated(tbs->attr, ops->maxtype,
@@ -3847,14 +3963,22 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
if (ret < 0)
goto put_ops;
}
+
+ if (ops->peer_type) {
+ ret = rtnl_add_peer_net(&rtnl_nets, ops, data, extack);
+ if (ret < 0)
+ goto put_ops;
+ }
}
tgt_net = rtnl_link_get_net_capable(skb, sock_net(skb->sk), tb, CAP_NET_ADMIN);
if (IS_ERR(tgt_net)) {
ret = PTR_ERR(tgt_net);
- goto put_ops;
+ goto put_net;
}
+ rtnl_nets_add(&rtnl_nets, tgt_net);
+
if (tb[IFLA_LINK_NETNSID]) {
int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
@@ -3865,18 +3989,20 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
goto put_net;
}
+ rtnl_nets_add(&rtnl_nets, link_net);
+
if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
goto put_net;
}
}
+ rtnl_nets_lock(&rtnl_nets);
ret = __rtnl_newlink(skb, nlh, ops, tgt_net, link_net, tbs, data, extack);
+ rtnl_nets_unlock(&rtnl_nets);
put_net:
- if (link_net)
- put_net(link_net);
- put_net(tgt_net);
+ rtnl_nets_destroy(&rtnl_nets);
put_ops:
if (ops)
rtnl_link_ops_put(ops, ops_srcu_index);
@@ -4452,9 +4578,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
netif_is_bridge_port(dev)) {
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
const struct net_device_ops *ops = br_dev->netdev_ops;
+ bool notified = false;
err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid,
- nlh->nlmsg_flags, extack);
+ nlh->nlmsg_flags, &notified, extack);
if (err)
goto out;
else
@@ -4463,16 +4590,18 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
/* Embedded bridge, macvlan, and any other device support */
if ((ndm->ndm_flags & NTF_SELF)) {
+ bool notified = false;
+
if (dev->netdev_ops->ndo_fdb_add)
err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
vid,
nlh->nlmsg_flags,
- extack);
+ &notified, extack);
else
err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid,
nlh->nlmsg_flags);
- if (!err) {
+ if (!err && !notified) {
rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH,
ndm->ndm_state);
ndm->ndm_flags &= ~NTF_SELF;
@@ -4572,11 +4701,13 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) &&
netif_is_bridge_port(dev)) {
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+ bool notified = false;
ops = br_dev->netdev_ops;
if (!del_bulk) {
if (ops->ndo_fdb_del)
- err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid, extack);
+ err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid,
+ &notified, extack);
} else {
if (ops->ndo_fdb_del_bulk)
err = ops->ndo_fdb_del_bulk(nlh, dev, extack);
@@ -4590,10 +4721,13 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
/* Embedded bridge, macvlan, and any other device support */
if (ndm->ndm_flags & NTF_SELF) {
+ bool notified = false;
+
ops = dev->netdev_ops;
if (!del_bulk) {
if (ops->ndo_fdb_del)
- err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid, extack);
+ err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid,
+ &notified, extack);
else
err = ndo_dflt_fdb_del(ndm, tb, dev, addr, vid);
} else {
@@ -4604,7 +4738,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
}
if (!err) {
- if (!del_bulk)
+ if (!del_bulk && !notified)
rtnl_fdb_notify(dev, addr, vid, RTM_DELNEIGH,
ndm->ndm_state);
ndm->ndm_flags &= ~NTF_SELF;
@@ -6877,11 +7011,14 @@ static struct pernet_operations rtnetlink_net_ops = {
};
static const struct rtnl_msg_handler rtnetlink_rtnl_msg_handlers[] __initconst = {
- {.msgtype = RTM_NEWLINK, .doit = rtnl_newlink},
- {.msgtype = RTM_DELLINK, .doit = rtnl_dellink},
+ {.msgtype = RTM_NEWLINK, .doit = rtnl_newlink,
+ .flags = RTNL_FLAG_DOIT_PERNET},
+ {.msgtype = RTM_DELLINK, .doit = rtnl_dellink,
+ .flags = RTNL_FLAG_DOIT_PERNET_WIP},
{.msgtype = RTM_GETLINK, .doit = rtnl_getlink,
.dumpit = rtnl_dump_ifinfo, .flags = RTNL_FLAG_DUMP_SPLIT_NLM_DONE},
- {.msgtype = RTM_SETLINK, .doit = rtnl_setlink},
+ {.msgtype = RTM_SETLINK, .doit = rtnl_setlink,
+ .flags = RTNL_FLAG_DOIT_PERNET_WIP},
{.msgtype = RTM_GETADDR, .dumpit = rtnl_dump_all},
{.msgtype = RTM_GETROUTE, .dumpit = rtnl_dump_all},
{.msgtype = RTM_GETNETCONF, .dumpit = rtnl_dump_all},
diff --git a/net/core/skb_fault_injection.c b/net/core/skb_fault_injection.c
new file mode 100644
index 000000000000..4235db6bdfad
--- /dev/null
+++ b/net/core/skb_fault_injection.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/debugfs.h>
+#include <linux/fault-inject.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+static struct {
+ struct fault_attr attr;
+ char devname[IFNAMSIZ];
+ bool filtered;
+} skb_realloc = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .filtered = false,
+};
+
+static bool should_fail_net_realloc_skb(struct sk_buff *skb)
+{
+ struct net_device *net = skb->dev;
+
+ if (skb_realloc.filtered &&
+ strncmp(net->name, skb_realloc.devname, IFNAMSIZ))
+ /* device name filter set, but names do not match */
+ return false;
+
+ if (!should_fail(&skb_realloc.attr, 1))
+ return false;
+
+ return true;
+}
+ALLOW_ERROR_INJECTION(should_fail_net_realloc_skb, TRUE);
+
+void skb_might_realloc(struct sk_buff *skb)
+{
+ if (!should_fail_net_realloc_skb(skb))
+ return;
+
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(skb_might_realloc);
+
+static int __init fail_skb_realloc_setup(char *str)
+{
+ return setup_fault_attr(&skb_realloc.attr, str);
+}
+__setup("fail_skb_realloc=", fail_skb_realloc_setup);
+
+static void reset_settings(void)
+{
+ skb_realloc.filtered = false;
+ memset(&skb_realloc.devname, 0, IFNAMSIZ);
+}
+
+static ssize_t devname_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+
+ reset_settings();
+ ret = simple_write_to_buffer(&skb_realloc.devname, IFNAMSIZ,
+ ppos, buffer, count);
+ if (ret < 0)
+ return ret;
+
+ skb_realloc.devname[IFNAMSIZ - 1] = '\0';
+ /* Remove a possible \n at the end of devname */
+ strim(skb_realloc.devname);
+
+ if (strnlen(skb_realloc.devname, IFNAMSIZ))
+ skb_realloc.filtered = true;
+
+ return count;
+}
+
+static ssize_t devname_read(struct file *file,
+ char __user *buffer,
+ size_t size, loff_t *ppos)
+{
+ if (!skb_realloc.filtered)
+ return 0;
+
+ return simple_read_from_buffer(buffer, size, ppos, &skb_realloc.devname,
+ strlen(skb_realloc.devname));
+}
+
+static const struct file_operations devname_ops = {
+ .write = devname_write,
+ .read = devname_read,
+};
+
+static int __init fail_skb_realloc_debugfs(void)
+{
+ umode_t mode = S_IFREG | 0600;
+ struct dentry *dir;
+
+ dir = fault_create_debugfs_attr("fail_skb_realloc", NULL,
+ &skb_realloc.attr);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ debugfs_create_file("devname", mode, dir, NULL, &devname_ops);
+
+ return 0;
+}
+
+late_initcall(fail_skb_realloc_debugfs);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 00afeb90c23a..6841e61a6bd0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -753,14 +753,14 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
if (in_hardirq() || irqs_disabled()) {
nc = this_cpu_ptr(&netdev_alloc_cache);
data = page_frag_alloc(nc, len, gfp_mask);
- pfmemalloc = nc->pfmemalloc;
+ pfmemalloc = page_frag_cache_is_pfmemalloc(nc);
} else {
local_bh_disable();
local_lock_nested_bh(&napi_alloc_cache.bh_lock);
nc = this_cpu_ptr(&napi_alloc_cache.page);
data = page_frag_alloc(nc, len, gfp_mask);
- pfmemalloc = nc->pfmemalloc;
+ pfmemalloc = page_frag_cache_is_pfmemalloc(nc);
local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
local_bh_enable();
@@ -850,7 +850,7 @@ struct sk_buff *napi_alloc_skb(struct napi_struct *napi, unsigned int len)
len = SKB_HEAD_ALIGN(len);
data = page_frag_alloc(&nc->page, len, gfp_mask);
- pfmemalloc = nc->page.pfmemalloc;
+ pfmemalloc = page_frag_cache_is_pfmemalloc(&nc->page);
}
local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
diff --git a/net/core/sock.c b/net/core/sock.c
index 7f398bd07fb7..74729d20cd00 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1047,32 +1047,34 @@ static int sock_reserve_memory(struct sock *sk, int bytes)
#ifdef CONFIG_PAGE_POOL
-/* This is the number of tokens that the user can SO_DEVMEM_DONTNEED in
- * 1 syscall. The limit exists to limit the amount of memory the kernel
- * allocates to copy these tokens.
+/* This is the number of tokens and frags that the user can SO_DEVMEM_DONTNEED
+ * in 1 syscall. The limit exists to limit the amount of memory the kernel
+ * allocates to copy these tokens, and to prevent looping over the frags for
+ * too long.
*/
#define MAX_DONTNEED_TOKENS 128
+#define MAX_DONTNEED_FRAGS 1024
static noinline_for_stack int
sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen)
{
unsigned int num_tokens, i, j, k, netmem_num = 0;
struct dmabuf_token *tokens;
+ int ret = 0, num_frags = 0;
netmem_ref netmems[16];
- int ret = 0;
if (!sk_is_tcp(sk))
return -EBADF;
- if (optlen % sizeof(struct dmabuf_token) ||
+ if (optlen % sizeof(*tokens) ||
optlen > sizeof(*tokens) * MAX_DONTNEED_TOKENS)
return -EINVAL;
- tokens = kvmalloc_array(optlen, sizeof(*tokens), GFP_KERNEL);
+ num_tokens = optlen / sizeof(*tokens);
+ tokens = kvmalloc_array(num_tokens, sizeof(*tokens), GFP_KERNEL);
if (!tokens)
return -ENOMEM;
- num_tokens = optlen / sizeof(struct dmabuf_token);
if (copy_from_sockptr(tokens, optval, optlen)) {
kvfree(tokens);
return -EFAULT;
@@ -1081,24 +1083,28 @@ sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen)
xa_lock_bh(&sk->sk_user_frags);
for (i = 0; i < num_tokens; i++) {
for (j = 0; j < tokens[i].token_count; j++) {
+ if (++num_frags > MAX_DONTNEED_FRAGS)
+ goto frag_limit_reached;
+
netmem_ref netmem = (__force netmem_ref)__xa_erase(
&sk->sk_user_frags, tokens[i].token_start + j);
- if (netmem &&
- !WARN_ON_ONCE(!netmem_is_net_iov(netmem))) {
- netmems[netmem_num++] = netmem;
- if (netmem_num == ARRAY_SIZE(netmems)) {
- xa_unlock_bh(&sk->sk_user_frags);
- for (k = 0; k < netmem_num; k++)
- WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
- netmem_num = 0;
- xa_lock_bh(&sk->sk_user_frags);
- }
- ret++;
+ if (!netmem || WARN_ON_ONCE(!netmem_is_net_iov(netmem)))
+ continue;
+
+ netmems[netmem_num++] = netmem;
+ if (netmem_num == ARRAY_SIZE(netmems)) {
+ xa_unlock_bh(&sk->sk_user_frags);
+ for (k = 0; k < netmem_num; k++)
+ WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
+ netmem_num = 0;
+ xa_lock_bh(&sk->sk_user_frags);
}
+ ret++;
}
}
+frag_limit_reached:
xa_unlock_bh(&sk->sk_user_frags);
for (k = 0; k < netmem_num; k++)
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 07d6aa4e39ef..78347d7d25ef 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1760,6 +1760,10 @@ static int sock_map_link_update_prog(struct bpf_link *link,
ret = -EINVAL;
goto out;
}
+ if (!sockmap_link->map) {
+ ret = -ENOLINK;
+ goto out;
+ }
ret = sock_map_prog_link_lookup(sockmap_link->map, &pprog, &plink,
sockmap_link->attach_type);
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index da5dba120bc9..d6649246188d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -618,7 +618,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
by tcp. Feel free to propose better solution.
--ANK (980728)
*/
- if (np->rxopt.all)
+ if (np->rxopt.all && sk->sk_state != DCCP_LISTEN)
opt_skb = skb_clone_and_charge_r(skb, sk);
if (sk->sk_state == DCCP_OPEN) { /* Fast path */
diff --git a/net/devlink/dev.c b/net/devlink/dev.c
index 13c73f50da3d..d6e3db300acb 100644
--- a/net/devlink/dev.c
+++ b/net/devlink/dev.c
@@ -531,10 +531,8 @@ int devlink_nl_reload_doit(struct sk_buff *skb, struct genl_info *info)
return err;
}
- if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
- action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
- else
- action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
+ action = nla_get_u8_default(info->attrs[DEVLINK_ATTR_RELOAD_ACTION],
+ DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
if (!devlink_reload_action_is_supported(devlink, action)) {
NL_SET_ERR_MSG(info->extack, "Requested reload action is not supported by the driver");
@@ -971,14 +969,14 @@ static int devlink_nl_flash_update_fill(struct sk_buff *msg,
nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
params->component))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
- params->done, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
+ params->done))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
- params->total, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
+ params->total))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
- params->timeout, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
+ params->timeout))
goto nla_put_failure;
out:
diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h
index a9f064ab9ed9..14eaad9cfe35 100644
--- a/net/devlink/devl_internal.h
+++ b/net/devlink/devl_internal.h
@@ -181,6 +181,11 @@ devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
return 0;
}
+static inline int devlink_nl_put_u64(struct sk_buff *msg, int attrtype, u64 val)
+{
+ return nla_put_u64_64bit(msg, attrtype, val, DEVLINK_ATTR_PAD);
+}
+
int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
struct devlink *devlink, int attrtype);
int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info);
diff --git a/net/devlink/dpipe.c b/net/devlink/dpipe.c
index 55009b377447..e55701b007f0 100644
--- a/net/devlink/dpipe.c
+++ b/net/devlink/dpipe.c
@@ -165,18 +165,17 @@ static int devlink_dpipe_table_put(struct sk_buff *skb,
return -EMSGSIZE;
if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
- DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size))
goto nla_put_failure;
if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
table->counters_enabled))
goto nla_put_failure;
if (table->resource_valid) {
- if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
- table->resource_id, DEVLINK_ATTR_PAD) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
- table->resource_units, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
+ table->resource_id) ||
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
+ table->resource_units))
goto nla_put_failure;
}
if (devlink_dpipe_matches_put(table, skb))
@@ -403,12 +402,11 @@ static int devlink_dpipe_entry_put(struct sk_buff *skb,
if (!entry_attr)
return -EMSGSIZE;
- if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index))
goto nla_put_failure;
if (entry->counter_valid)
- if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
- entry->counter, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
+ entry->counter))
goto nla_put_failure;
matches_attr = nla_nest_start_noflag(skb,
diff --git a/net/devlink/health.c b/net/devlink/health.c
index acb8c0e174bb..b8d3084e6fe0 100644
--- a/net/devlink/health.c
+++ b/net/devlink/health.c
@@ -287,29 +287,27 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
reporter->health_state))
goto reporter_nest_cancel;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
- reporter->error_count, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
+ reporter->error_count))
goto reporter_nest_cancel;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
- reporter->recovery_count, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
+ reporter->recovery_count))
goto reporter_nest_cancel;
if (reporter->ops->recover &&
- nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
- reporter->graceful_period,
- DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
+ reporter->graceful_period))
goto reporter_nest_cancel;
if (reporter->ops->recover &&
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
reporter->auto_recover))
goto reporter_nest_cancel;
if (reporter->dump_fmsg &&
- nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
- jiffies_to_msecs(reporter->dump_ts),
- DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
+ jiffies_to_msecs(reporter->dump_ts)))
goto reporter_nest_cancel;
if (reporter->dump_fmsg &&
- nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
- reporter->dump_real_ts, DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
+ reporter->dump_real_ts))
goto reporter_nest_cancel;
if (reporter->ops->dump &&
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
@@ -963,8 +961,7 @@ devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
case NLA_U32:
return nla_put_u32(skb, attrtype, *(u32 *)msg->value);
case NLA_U64:
- return nla_put_u64_64bit(skb, attrtype, *(u64 *)msg->value,
- DEVLINK_ATTR_PAD);
+ return devlink_nl_put_u64(skb, attrtype, *(u64 *)msg->value);
case NLA_NUL_STRING:
return nla_put_string(skb, attrtype, (char *)&msg->value);
case NLA_BINARY:
diff --git a/net/devlink/rate.c b/net/devlink/rate.c
index 7139e67e93ae..8828ffaf6cbc 100644
--- a/net/devlink/rate.c
+++ b/net/devlink/rate.c
@@ -108,12 +108,12 @@ static int devlink_nl_rate_fill(struct sk_buff *msg,
goto nla_put_failure;
}
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
- devlink_rate->tx_share, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_RATE_TX_SHARE,
+ devlink_rate->tx_share))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX,
- devlink_rate->tx_max, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_RATE_TX_MAX,
+ devlink_rate->tx_max))
goto nla_put_failure;
if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_PRIORITY,
diff --git a/net/devlink/region.c b/net/devlink/region.c
index 7319127c5913..63fb297f6d67 100644
--- a/net/devlink/region.c
+++ b/net/devlink/region.c
@@ -77,7 +77,7 @@ static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
if (!snap_attr)
- return -EINVAL;
+ return -EMSGSIZE;
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
if (err)
@@ -102,7 +102,7 @@ static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
snapshots_attr = nla_nest_start_noflag(msg,
DEVLINK_ATTR_REGION_SNAPSHOTS);
if (!snapshots_attr)
- return -EINVAL;
+ return -EMSGSIZE;
list_for_each_entry(snapshot, &region->snapshot_list, list) {
err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
@@ -145,9 +145,7 @@ static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
if (err)
goto nla_put_failure;
- err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
- region->size,
- DEVLINK_ATTR_PAD);
+ err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_SIZE, region->size);
if (err)
goto nla_put_failure;
@@ -210,8 +208,8 @@ devlink_nl_region_notify_build(struct devlink_region *region,
if (err)
goto out_cancel_msg;
} else {
- err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
- region->size, DEVLINK_ATTR_PAD);
+ err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_SIZE,
+ region->size);
if (err)
goto out_cancel_msg;
}
@@ -773,8 +771,7 @@ static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
if (err)
goto nla_put_failure;
- err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
- DEVLINK_ATTR_PAD);
+ err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr);
if (err)
goto nla_put_failure;
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index 594c8aeb3bfa..2d6324f3d91f 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -141,12 +141,12 @@ devlink_resource_size_params_put(struct devlink_resource *resource,
struct devlink_resource_size_params *size_params;
size_params = &resource->size_params;
- if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
- size_params->size_granularity, DEVLINK_ATTR_PAD) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
- size_params->size_max, DEVLINK_ATTR_PAD) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
- size_params->size_min, DEVLINK_ATTR_PAD) ||
+ if (devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
+ size_params->size_granularity) ||
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
+ size_params->size_max) ||
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
+ size_params->size_min) ||
nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
return -EMSGSIZE;
return 0;
@@ -157,9 +157,8 @@ static int devlink_resource_occ_put(struct devlink_resource *resource,
{
if (!resource->occ_get)
return 0;
- return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
- resource->occ_get(resource->occ_get_priv),
- DEVLINK_ATTR_PAD);
+ return devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_OCC,
+ resource->occ_get(resource->occ_get_priv));
}
static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
@@ -174,14 +173,12 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
return -EMSGSIZE;
if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
- DEVLINK_ATTR_PAD) ||
- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
- DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size) ||
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id))
goto nla_put_failure;
if (resource->size != resource->size_new &&
- nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
- resource->size_new, DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
+ resource->size_new))
goto nla_put_failure;
if (devlink_resource_occ_put(resource, skb))
goto nla_put_failure;
@@ -348,7 +345,7 @@ int devl_resource_register(struct devlink *devlink,
resource = devlink_resource_find(devlink, NULL, resource_id);
if (resource)
- return -EINVAL;
+ return -EEXIST;
resource = kzalloc(sizeof(*resource), GFP_KERNEL);
if (!resource)
@@ -384,39 +381,6 @@ int devl_resource_register(struct devlink *devlink,
}
EXPORT_SYMBOL_GPL(devl_resource_register);
-/**
- * devlink_resource_register - devlink resource register
- *
- * @devlink: devlink
- * @resource_name: resource's name
- * @resource_size: resource's size
- * @resource_id: resource's id
- * @parent_resource_id: resource's parent id
- * @size_params: size parameters
- *
- * Generic resources should reuse the same names across drivers.
- * Please see the generic resources list at:
- * Documentation/networking/devlink/devlink-resource.rst
- *
- * Context: Takes and release devlink->lock <mutex>.
- */
-int devlink_resource_register(struct devlink *devlink,
- const char *resource_name,
- u64 resource_size,
- u64 resource_id,
- u64 parent_resource_id,
- const struct devlink_resource_size_params *size_params)
-{
- int err;
-
- devl_lock(devlink);
- err = devl_resource_register(devlink, resource_name, resource_size,
- resource_id, parent_resource_id, size_params);
- devl_unlock(devlink);
- return err;
-}
-EXPORT_SYMBOL_GPL(devlink_resource_register);
-
static void devlink_resource_unregister(struct devlink *devlink,
struct devlink_resource *resource)
{
@@ -517,28 +481,6 @@ void devl_resource_occ_get_register(struct devlink *devlink,
EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
/**
- * devlink_resource_occ_get_register - register occupancy getter
- *
- * @devlink: devlink
- * @resource_id: resource id
- * @occ_get: occupancy getter callback
- * @occ_get_priv: occupancy getter callback priv
- *
- * Context: Takes and release devlink->lock <mutex>.
- */
-void devlink_resource_occ_get_register(struct devlink *devlink,
- u64 resource_id,
- devlink_resource_occ_get_t *occ_get,
- void *occ_get_priv)
-{
- devl_lock(devlink);
- devl_resource_occ_get_register(devlink, resource_id,
- occ_get, occ_get_priv);
- devl_unlock(devlink);
-}
-EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
-
-/**
* devl_resource_occ_get_unregister - unregister occupancy getter
*
* @devlink: devlink
@@ -560,20 +502,3 @@ void devl_resource_occ_get_unregister(struct devlink *devlink,
resource->occ_get_priv = NULL;
}
EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
-
-/**
- * devlink_resource_occ_get_unregister - unregister occupancy getter
- *
- * @devlink: devlink
- * @resource_id: resource id
- *
- * Context: Takes and release devlink->lock <mutex>.
- */
-void devlink_resource_occ_get_unregister(struct devlink *devlink,
- u64 resource_id)
-{
- devl_lock(devlink);
- devl_resource_occ_get_unregister(devlink, resource_id);
- devl_unlock(devlink);
-}
-EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
diff --git a/net/devlink/trap.c b/net/devlink/trap.c
index 5d18c7424df1..f36087f90db5 100644
--- a/net/devlink/trap.c
+++ b/net/devlink/trap.c
@@ -189,14 +189,12 @@ devlink_trap_group_stats_put(struct sk_buff *msg,
if (!attr)
return -EMSGSIZE;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
- u64_stats_read(&stats.rx_packets),
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
+ u64_stats_read(&stats.rx_packets)))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
- u64_stats_read(&stats.rx_bytes),
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
+ u64_stats_read(&stats.rx_bytes)))
goto nla_put_failure;
nla_nest_end(msg, attr);
@@ -231,18 +229,15 @@ static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
return -EMSGSIZE;
if (devlink->ops->trap_drop_counter_get &&
- nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
- DEVLINK_ATTR_PAD))
+ devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
- u64_stats_read(&stats.rx_packets),
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
+ u64_stats_read(&stats.rx_packets)))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
- u64_stats_read(&stats.rx_bytes),
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_BYTES,
+ u64_stats_read(&stats.rx_bytes)))
goto nla_put_failure;
nla_nest_end(msg, attr);
@@ -750,8 +745,7 @@ devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
if (!attr)
return -EMSGSIZE;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
- DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops))
goto nla_put_failure;
nla_nest_end(msg, attr);
@@ -783,12 +777,12 @@ devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
policer_item->policer->id))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
- policer_item->rate, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
+ policer_item->rate))
goto nla_put_failure;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
- policer_item->burst, DEVLINK_ATTR_PAD))
+ if (devlink_nl_put_u64(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
+ policer_item->burst))
goto nla_put_failure;
err = devlink_trap_policer_stats_put(msg, devlink,
diff --git a/net/dsa/devlink.c b/net/dsa/devlink.c
index 0aac887d0098..f41f9fc2194e 100644
--- a/net/dsa/devlink.c
+++ b/net/dsa/devlink.c
@@ -229,10 +229,15 @@ int dsa_devlink_resource_register(struct dsa_switch *ds,
u64 parent_resource_id,
const struct devlink_resource_size_params *size_params)
{
- return devlink_resource_register(ds->devlink, resource_name,
- resource_size, resource_id,
- parent_resource_id,
- size_params);
+ int ret;
+
+ devl_lock(ds->devlink);
+ ret = devl_resource_register(ds->devlink, resource_name, resource_size,
+ resource_id, parent_resource_id,
+ size_params);
+ devl_unlock(ds->devlink);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(dsa_devlink_resource_register);
@@ -247,15 +252,19 @@ void dsa_devlink_resource_occ_get_register(struct dsa_switch *ds,
devlink_resource_occ_get_t *occ_get,
void *occ_get_priv)
{
- return devlink_resource_occ_get_register(ds->devlink, resource_id,
- occ_get, occ_get_priv);
+ devl_lock(ds->devlink);
+ devl_resource_occ_get_register(ds->devlink, resource_id, occ_get,
+ occ_get_priv);
+ devl_unlock(ds->devlink);
}
EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_register);
void dsa_devlink_resource_occ_get_unregister(struct dsa_switch *ds,
u64 resource_id)
{
- devlink_resource_occ_get_unregister(ds->devlink, resource_id);
+ devl_lock(ds->devlink);
+ devl_resource_occ_get_unregister(ds->devlink, resource_id);
+ devl_unlock(ds->devlink);
}
EXPORT_SYMBOL_GPL(dsa_devlink_resource_occ_get_unregister);
diff --git a/net/dsa/user.c b/net/dsa/user.c
index 91a1fa5f8ab0..06c30a9e29ff 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -1042,15 +1042,12 @@ static void dsa_user_get_strings(struct net_device *dev,
struct dsa_switch *ds = dp->ds;
if (stringset == ETH_SS_STATS) {
- int len = ETH_GSTRING_LEN;
-
- strscpy_pad(data, "tx_packets", len);
- strscpy_pad(data + len, "tx_bytes", len);
- strscpy_pad(data + 2 * len, "rx_packets", len);
- strscpy_pad(data + 3 * len, "rx_bytes", len);
+ ethtool_puts(&data, "tx_packets");
+ ethtool_puts(&data, "tx_bytes");
+ ethtool_puts(&data, "rx_packets");
+ ethtool_puts(&data, "rx_bytes");
if (ds->ops->get_strings)
- ds->ops->get_strings(ds, dp->index, stringset,
- data + 4 * len);
+ ds->ops->get_strings(ds, dp->index, stringset, data);
} else if (stringset == ETH_SS_TEST) {
net_selftest_get_strings(data);
}
@@ -1364,7 +1361,7 @@ dsa_user_mall_tc_entry_find(struct net_device *dev, unsigned long cookie)
static int
dsa_user_add_cls_matchall_mirred(struct net_device *dev,
struct tc_cls_matchall_offload *cls,
- bool ingress)
+ bool ingress, bool ingress_target)
{
struct netlink_ext_ack *extack = cls->common.extack;
struct dsa_port *dp = dsa_user_to_port(dev);
@@ -1376,11 +1373,19 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
struct dsa_port *to_dp;
int err;
- if (!ds->ops->port_mirror_add)
+ if (cls->common.protocol != htons(ETH_P_ALL)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can only offload \"protocol all\" matchall filter");
+ return -EOPNOTSUPP;
+ }
+
+ if (!ds->ops->port_mirror_add) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Switch does not support mirroring operation");
return -EOPNOTSUPP;
+ }
- if (!flow_action_basic_hw_stats_check(&cls->rule->action,
- cls->common.extack))
+ if (!flow_action_basic_hw_stats_check(&cls->rule->action, extack))
return -EOPNOTSUPP;
act = &cls->rule->action.entries[0];
@@ -1388,10 +1393,30 @@ dsa_user_add_cls_matchall_mirred(struct net_device *dev,
if (!act->dev)
return -EINVAL;
- if (!dsa_user_dev_check(act->dev))
- return -EOPNOTSUPP;
-
- to_dp = dsa_user_to_port(act->dev);
+ if (dsa_user_dev_check(act->dev)) {
+ if (ingress_target) {
+ /* We can only fulfill this using software assist */
+ if (cls->common.skip_sw) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can only mirred to ingress of DSA user port if filter also runs in software");
+ return -EOPNOTSUPP;
+ }
+ to_dp = dp->cpu_dp;
+ } else {
+ to_dp = dsa_user_to_port(act->dev);
+ }
+ } else {
+ /* Handle mirroring to foreign target ports as a mirror towards
+ * the CPU. The software tc rule will take the packets from
+ * there.
+ */
+ if (cls->common.skip_sw) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can only mirred to CPU if filter also runs in software");
+ return -EOPNOTSUPP;
+ }
+ to_dp = dp->cpu_dp;
+ }
if (dp->ds != to_dp->ds) {
NL_SET_ERR_MSG_MOD(extack,
@@ -1446,8 +1471,7 @@ dsa_user_add_cls_matchall_police(struct net_device *dev,
return -EOPNOTSUPP;
}
- if (!flow_action_basic_hw_stats_check(&cls->rule->action,
- cls->common.extack))
+ if (!flow_action_basic_hw_stats_check(&cls->rule->action, extack))
return -EOPNOTSUPP;
list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) {
@@ -1485,17 +1509,30 @@ static int dsa_user_add_cls_matchall(struct net_device *dev,
struct tc_cls_matchall_offload *cls,
bool ingress)
{
- int err = -EOPNOTSUPP;
+ const struct flow_action *action = &cls->rule->action;
+ struct netlink_ext_ack *extack = cls->common.extack;
- if (cls->common.protocol == htons(ETH_P_ALL) &&
- flow_offload_has_one_action(&cls->rule->action) &&
- cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED)
- err = dsa_user_add_cls_matchall_mirred(dev, cls, ingress);
- else if (flow_offload_has_one_action(&cls->rule->action) &&
- cls->rule->action.entries[0].id == FLOW_ACTION_POLICE)
- err = dsa_user_add_cls_matchall_police(dev, cls, ingress);
+ if (!flow_offload_has_one_action(action)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Cannot offload matchall filter with more than one action");
+ return -EOPNOTSUPP;
+ }
- return err;
+ switch (action->entries[0].id) {
+ case FLOW_ACTION_MIRRED:
+ return dsa_user_add_cls_matchall_mirred(dev, cls, ingress,
+ false);
+ case FLOW_ACTION_MIRRED_INGRESS:
+ return dsa_user_add_cls_matchall_mirred(dev, cls, ingress,
+ true);
+ case FLOW_ACTION_POLICE:
+ return dsa_user_add_cls_matchall_police(dev, cls, ingress);
+ default:
+ NL_SET_ERR_MSG_MOD(extack, "Unknown action");
+ break;
+ }
+
+ return -EOPNOTSUPP;
}
static void dsa_user_del_cls_matchall(struct net_device *dev,
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 0d62363dbd9d..05ce4f8080b3 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -538,6 +538,20 @@ static int ethtool_get_rxnfc_rule_count(struct net_device *dev)
return info.rule_cnt;
}
+/* Max offset for one RSS context */
+static u32 ethtool_get_rss_ctx_max_channel(struct ethtool_rxfh_context *ctx)
+{
+ u32 max_ring = 0;
+ u32 i, *tbl;
+
+ if (WARN_ON_ONCE(!ctx))
+ return 0;
+ tbl = ethtool_rxfh_context_indir(ctx);
+ for (i = 0; i < ctx->indir_size; i++)
+ max_ring = max(max_ring, tbl[i]);
+ return max_ring;
+}
+
static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -574,10 +588,18 @@ static int ethtool_get_max_rxnfc_channel(struct net_device *dev, u64 *max)
if (rule_info.fs.ring_cookie != RX_CLS_FLOW_DISC &&
rule_info.fs.ring_cookie != RX_CLS_FLOW_WAKE &&
- !(rule_info.flow_type & FLOW_RSS) &&
- !ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie))
- max_ring =
- max_t(u64, max_ring, rule_info.fs.ring_cookie);
+ !ethtool_get_flow_spec_ring_vf(rule_info.fs.ring_cookie)) {
+ u64 ring = rule_info.fs.ring_cookie;
+
+ if (rule_info.flow_type & FLOW_RSS) {
+ struct ethtool_rxfh_context *ctx;
+
+ ctx = xa_load(&dev->ethtool->rss_ctx,
+ rule_info.rss_context);
+ ring += ethtool_get_rss_ctx_max_channel(ctx);
+ }
+ max_ring = max_t(u64, max_ring, ring);
+ }
}
kvfree(info);
@@ -589,6 +611,7 @@ err_free_info:
return err;
}
+/* Max offset across all of a device's RSS contexts */
static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
{
struct ethtool_rxfh_context *ctx;
@@ -596,13 +619,8 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
u32 max_ring = 0;
mutex_lock(&dev->ethtool->rss_lock);
- xa_for_each(&dev->ethtool->rss_ctx, context, ctx) {
- u32 i, *tbl;
-
- tbl = ethtool_rxfh_context_indir(ctx);
- for (i = 0; i < ctx->indir_size; i++)
- max_ring = max(max_ring, tbl[i]);
- }
+ xa_for_each(&dev->ethtool->rss_ctx, context, ctx)
+ max_ring = max(max_ring, ethtool_get_rss_ctx_max_channel(ctx));
mutex_unlock(&dev->ethtool->rss_lock);
return max_ring;
@@ -611,7 +629,7 @@ static u32 ethtool_get_max_rss_ctx_channel(struct net_device *dev)
static u32 ethtool_get_max_rxfh_channel(struct net_device *dev)
{
struct ethtool_rxfh_param rxfh = {};
- u32 dev_size, current_max;
+ u32 dev_size, current_max = 0;
int ret;
/* While we do track whether RSS context has an indirection
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 5cc131cdb1bc..d86399bcf223 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -425,7 +425,7 @@ convert_link_ksettings_to_legacy_settings(
/* layout of the struct passed from/to userland */
struct ethtool_link_usettings {
- struct ethtool_link_settings base;
+ struct ethtool_link_settings_hdr base;
struct {
__u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
__u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
@@ -992,6 +992,11 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
if (rc)
return rc;
+ /* Nonzero ring with RSS only makes sense if NIC adds them together */
+ if (info.flow_type & FLOW_RSS && !ops->cap_rss_rxnfc_adds &&
+ ethtool_get_flow_spec_ring(info.fs.ring_cookie))
+ return -EINVAL;
+
if (ops->get_rxfh) {
struct ethtool_rxfh_param rxfh = {};
diff --git a/net/ethtool/linkinfo.c b/net/ethtool/linkinfo.c
index 30b8ce275159..2d5bc57160be 100644
--- a/net/ethtool/linkinfo.c
+++ b/net/ethtool/linkinfo.c
@@ -8,9 +8,9 @@ struct linkinfo_req_info {
};
struct linkinfo_reply_data {
- struct ethnl_reply_data base;
- struct ethtool_link_ksettings ksettings;
- struct ethtool_link_settings *lsettings;
+ struct ethnl_reply_data base;
+ struct ethtool_link_ksettings ksettings;
+ struct ethtool_link_settings_hdr *lsettings;
};
#define LINKINFO_REPDATA(__reply_base) \
@@ -98,7 +98,7 @@ static int
ethnl_set_linkinfo(struct ethnl_req_info *req_info, struct genl_info *info)
{
struct ethtool_link_ksettings ksettings = {};
- struct ethtool_link_settings *lsettings;
+ struct ethtool_link_settings_hdr *lsettings;
struct net_device *dev = req_info->dev;
struct nlattr **tb = info->attrs;
bool mod = false;
diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c
index 259cd9ef1f2a..17e49cf89f03 100644
--- a/net/ethtool/linkmodes.c
+++ b/net/ethtool/linkmodes.c
@@ -11,10 +11,10 @@ struct linkmodes_req_info {
};
struct linkmodes_reply_data {
- struct ethnl_reply_data base;
- struct ethtool_link_ksettings ksettings;
- struct ethtool_link_settings *lsettings;
- bool peer_empty;
+ struct ethnl_reply_data base;
+ struct ethtool_link_ksettings ksettings;
+ struct ethtool_link_settings_hdr *lsettings;
+ bool peer_empty;
};
#define LINKMODES_REPDATA(__reply_base) \
@@ -62,10 +62,12 @@ static int linkmodes_reply_size(const struct ethnl_req_info *req_base,
{
const struct linkmodes_reply_data *data = LINKMODES_REPDATA(reply_base);
const struct ethtool_link_ksettings *ksettings = &data->ksettings;
- const struct ethtool_link_settings *lsettings = &ksettings->base;
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+ const struct ethtool_link_settings_hdr *lsettings;
int len, ret;
+ lsettings = &ksettings->base;
+
len = nla_total_size(sizeof(u8)) /* LINKMODES_AUTONEG */
+ nla_total_size(sizeof(u32)) /* LINKMODES_SPEED */
+ nla_total_size(sizeof(u32)) /* LINKMODES_LANES */
@@ -103,10 +105,12 @@ static int linkmodes_fill_reply(struct sk_buff *skb,
{
const struct linkmodes_reply_data *data = LINKMODES_REPDATA(reply_base);
const struct ethtool_link_ksettings *ksettings = &data->ksettings;
- const struct ethtool_link_settings *lsettings = &ksettings->base;
bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
+ const struct ethtool_link_settings_hdr *lsettings;
int ret;
+ lsettings = &ksettings->base;
+
if (nla_put_u8(skb, ETHTOOL_A_LINKMODES_AUTONEG, lsettings->autoneg))
return -EMSGSIZE;
@@ -237,7 +241,7 @@ static int ethnl_update_linkmodes(struct genl_info *info, struct nlattr **tb,
struct ethtool_link_ksettings *ksettings,
bool *mod, const struct net_device *dev)
{
- struct ethtool_link_settings *lsettings = &ksettings->base;
+ struct ethtool_link_settings_hdr *lsettings = &ksettings->base;
bool req_speed, req_lanes, req_duplex;
const struct nlattr *master_slave_cfg, *lanes_cfg;
int ret;
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index ebdfd5b64e17..9e64496a5c1c 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -515,6 +515,77 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
}
}
+static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ bool is_slave_a_added = false;
+ bool is_slave_b_added = false;
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+ int ret = 0;
+
+ hsr = netdev_priv(dev);
+
+ hsr_for_each_port(hsr, port) {
+ if (port->type == HSR_PT_MASTER ||
+ port->type == HSR_PT_INTERLINK)
+ continue;
+
+ ret = vlan_vid_add(port->dev, proto, vid);
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ if (ret) {
+ /* clean up Slave-B */
+ netdev_err(dev, "add vid failed for Slave-A\n");
+ if (is_slave_b_added)
+ vlan_vid_del(port->dev, proto, vid);
+ return ret;
+ }
+
+ is_slave_a_added = true;
+ break;
+
+ case HSR_PT_SLAVE_B:
+ if (ret) {
+ /* clean up Slave-A */
+ netdev_err(dev, "add vid failed for Slave-B\n");
+ if (is_slave_a_added)
+ vlan_vid_del(port->dev, proto, vid);
+ return ret;
+ }
+
+ is_slave_b_added = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
+{
+ struct hsr_port *port;
+ struct hsr_priv *hsr;
+
+ hsr = netdev_priv(dev);
+
+ hsr_for_each_port(hsr, port) {
+ switch (port->type) {
+ case HSR_PT_SLAVE_A:
+ case HSR_PT_SLAVE_B:
+ vlan_vid_del(port->dev, proto, vid);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops hsr_device_ops = {
.ndo_change_mtu = hsr_dev_change_mtu,
.ndo_open = hsr_dev_open,
@@ -523,6 +594,8 @@ static const struct net_device_ops hsr_device_ops = {
.ndo_change_rx_flags = hsr_change_rx_flags,
.ndo_fix_features = hsr_fix_features,
.ndo_set_rx_mode = hsr_set_rx_mode,
+ .ndo_vlan_rx_add_vid = hsr_ndo_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = hsr_ndo_vlan_rx_kill_vid,
};
static const struct device_type hsr_type = {
@@ -569,14 +642,10 @@ void hsr_dev_setup(struct net_device *dev)
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_CTAG_TX;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
dev->features = dev->hw_features;
-
- /* VLAN on top of HSR needs testing and probably some work on
- * hsr_header_create() etc.
- */
- dev->features |= NETIF_F_VLAN_CHALLENGED;
}
/* Return true if dev is a HSR master; return false otherwise.
@@ -652,6 +721,10 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
(slave[1]->features & NETIF_F_HW_HSR_FWD))
hsr->fwd_offloaded = true;
+ if ((slave[0]->features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+ (slave[1]->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+ hsr_dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
res = register_netdevice(hsr_dev);
if (res)
goto err_unregister;
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index b38060246e62..aa6acebc7c1e 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -280,6 +280,7 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
struct hsr_port *port, u8 proto_version)
{
struct hsr_ethhdr *hsr_ethhdr;
+ unsigned char *pc;
int lsdu_size;
/* pad to minimum packet size which is 60 + 6 (HSR tag) */
@@ -290,7 +291,18 @@ static struct sk_buff *hsr_fill_tag(struct sk_buff *skb,
if (frame->is_vlan)
lsdu_size -= 4;
- hsr_ethhdr = (struct hsr_ethhdr *)skb_mac_header(skb);
+ pc = skb_mac_header(skb);
+ if (frame->is_vlan)
+ /* This 4-byte shift (size of a vlan tag) does not
+ * mean that the ethhdr starts there. But rather it
+ * provides the proper environment for accessing
+ * the fields, such as hsr_tag etc., just like
+ * when the vlan tag is not there. This is because
+ * the hsr tag is after the vlan tag.
+ */
+ hsr_ethhdr = (struct hsr_ethhdr *)(pc + VLAN_HLEN);
+ else
+ hsr_ethhdr = (struct hsr_ethhdr *)pc;
hsr_set_path_id(hsr_ethhdr, port);
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
@@ -368,7 +380,7 @@ struct sk_buff *prp_create_tagged_frame(struct hsr_frame_info *frame,
return skb_clone(frame->skb_std, GFP_ATOMIC);
}
- skb = skb_copy_expand(frame->skb_std, 0,
+ skb = skb_copy_expand(frame->skb_std, skb_headroom(frame->skb_std),
skb_tailroom(frame->skb_std) + HSR_HLEN,
GFP_ATOMIC);
return prp_fill_rct(skb, frame, port);
@@ -690,9 +702,6 @@ static int fill_frame_info(struct hsr_frame_info *frame,
if (frame->is_vlan) {
vlan_hdr = (struct hsr_vlan_ethhdr *)ethhdr;
proto = vlan_hdr->vlanhdr.h_vlan_encapsulated_proto;
- /* FIXME: */
- netdev_warn_once(skb->dev, "VLAN not yet supported");
- return -EINVAL;
}
frame->is_from_san = false;
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 6f09b9512484..b68f2f71d0e1 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -82,10 +82,7 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
return -EINVAL;
}
- if (!data[IFLA_HSR_MULTICAST_SPEC])
- multicast_spec = 0;
- else
- multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]);
+ multicast_spec = nla_get_u8_default(data[IFLA_HSR_MULTICAST_SPEC], 0);
if (data[IFLA_HSR_PROTOCOL])
proto = nla_get_u8(data[IFLA_HSR_PROTOCOL]);
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 29bf97640166..74ef0a310afb 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -202,10 +202,7 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
addr.pan_id = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
- if (info->attrs[IEEE802154_ATTR_PAGE])
- page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
- else
- page = 0;
+ page = nla_get_u8_default(info->attrs[IEEE802154_ATTR_PAGE], 0);
ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
@@ -338,10 +335,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
- if (info->attrs[IEEE802154_ATTR_PAGE])
- page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
- else
- page = 0;
+ page = nla_get_u8_default(info->attrs[IEEE802154_ATTR_PAGE], 0);
if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
@@ -388,10 +382,7 @@ int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
- if (info->attrs[IEEE802154_ATTR_PAGE])
- page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
- else
- page = 0;
+ page = nla_get_u8_default(info->attrs[IEEE802154_ATTR_PAGE], 0);
ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels,
page, duration);
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 7eb37de3add2..5a024ca60d35 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -1438,22 +1438,18 @@ static int nl802154_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
/* Use current page by default */
- if (info->attrs[NL802154_ATTR_PAGE])
- request->page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
- else
- request->page = wpan_phy->current_page;
+ request->page = nla_get_u8_default(info->attrs[NL802154_ATTR_PAGE],
+ wpan_phy->current_page);
/* Scan all supported channels by default */
- if (info->attrs[NL802154_ATTR_SCAN_CHANNELS])
- request->channels = nla_get_u32(info->attrs[NL802154_ATTR_SCAN_CHANNELS]);
- else
- request->channels = wpan_phy->supported.channels[request->page];
+ request->channels =
+ nla_get_u32_default(info->attrs[NL802154_ATTR_SCAN_CHANNELS],
+ wpan_phy->supported.channels[request->page]);
/* Use maximum duration order by default */
- if (info->attrs[NL802154_ATTR_SCAN_DURATION])
- request->duration = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_DURATION]);
- else
- request->duration = IEEE802154_MAX_SCAN_DURATION;
+ request->duration =
+ nla_get_u8_default(info->attrs[NL802154_ATTR_SCAN_DURATION],
+ IEEE802154_MAX_SCAN_DURATION);
err = rdev_trigger_scan(rdev, request);
if (err) {
@@ -1598,10 +1594,8 @@ nl802154_send_beacons(struct sk_buff *skb, struct genl_info *info)
request->wpan_phy = wpan_phy;
/* Use maximum duration order by default */
- if (info->attrs[NL802154_ATTR_BEACON_INTERVAL])
- request->interval = nla_get_u8(info->attrs[NL802154_ATTR_BEACON_INTERVAL]);
- else
- request->interval = IEEE802154_MAX_SCAN_DURATION;
+ request->interval = nla_get_u8_default(info->attrs[NL802154_ATTR_BEACON_INTERVAL],
+ IEEE802154_MAX_SCAN_DURATION);
err = rdev_send_beacons(rdev, request);
if (err) {
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 11c1519b3699..cb9a7ed8abd3 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1215,7 +1215,7 @@ int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
NEIGH_UPDATE_F_ADMIN, 0);
write_lock_bh(&tbl->lock);
neigh_release(neigh);
- neigh_remove_one(neigh, tbl);
+ neigh_remove_one(neigh);
write_unlock_bh(&tbl->lock);
}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 5f859d01cbbe..c8b3cf5fba4c 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -508,11 +508,6 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
ASSERT_RTNL();
- if (!ifa->ifa_local) {
- inet_free_ifa(ifa);
- return 0;
- }
-
ifa->ifa_flags &= ~IFA_F_SECONDARY;
last_primary = &in_dev->ifa_list;
@@ -584,14 +579,17 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
static int inet_insert_ifa(struct in_ifaddr *ifa)
{
+ if (!ifa->ifa_local) {
+ inet_free_ifa(ifa);
+ return 0;
+ }
+
return __inet_insert_ifa(ifa, NULL, 0, NULL);
}
static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
{
- struct in_device *in_dev = __in_dev_get_rtnl(dev);
-
- ASSERT_RTNL();
+ struct in_device *in_dev = __in_dev_get_rtnl_net(dev);
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
@@ -645,7 +643,7 @@ static int ip_mc_autojoin_config(struct net *net, bool join,
struct sock *sk = net->ipv4.mc_autojoin_sk;
int ret;
- ASSERT_RTNL();
+ ASSERT_RTNL_NET(net);
lock_sock(sk);
if (join)
@@ -671,22 +669,24 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
struct in_ifaddr *ifa;
int err;
- ASSERT_RTNL();
-
err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
ifa_ipv4_policy, extack);
if (err < 0)
- goto errout;
+ goto out;
ifm = nlmsg_data(nlh);
+
+ rtnl_net_lock(net);
+
in_dev = inetdev_by_index(net, ifm->ifa_index);
if (!in_dev) {
NL_SET_ERR_MSG(extack, "ipv4: Device not found");
err = -ENODEV;
- goto errout;
+ goto unlock;
}
- for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL;
+ for (ifap = &in_dev->ifa_list;
+ (ifa = rtnl_net_dereference(net, *ifap)) != NULL;
ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] &&
ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
@@ -702,13 +702,16 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
if (ipv4_is_multicast(ifa->ifa_address))
ip_mc_autojoin_config(net, false, ifa);
+
__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
- return 0;
+ goto unlock;
}
NL_SET_ERR_MSG(extack, "ipv4: Address not found");
err = -EADDRNOTAVAIL;
-errout:
+unlock:
+ rtnl_net_unlock(net);
+out:
return err;
}
@@ -766,7 +769,8 @@ static void check_lifetime(struct work_struct *work)
rcu_read_unlock();
if (!change_needed)
continue;
- rtnl_lock();
+
+ rtnl_net_lock(net);
hlist_for_each_entry_safe(ifa, n, head, addr_lst) {
unsigned long age;
@@ -783,7 +787,7 @@ static void check_lifetime(struct work_struct *work)
struct in_ifaddr *tmp;
ifap = &ifa->ifa_dev->ifa_list;
- tmp = rtnl_dereference(*ifap);
+ tmp = rtnl_net_dereference(net, *ifap);
while (tmp) {
if (tmp == ifa) {
inet_del_ifa(ifa->ifa_dev,
@@ -791,7 +795,7 @@ static void check_lifetime(struct work_struct *work)
break;
}
ifap = &tmp->ifa_next;
- tmp = rtnl_dereference(*ifap);
+ tmp = rtnl_net_dereference(net, *ifap);
}
} else if (ifa->ifa_preferred_lft !=
INFINITY_LIFE_TIME &&
@@ -801,7 +805,7 @@ static void check_lifetime(struct work_struct *work)
rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
}
}
- rtnl_unlock();
+ rtnl_net_unlock(net);
}
next_sec = round_jiffies_up(next);
@@ -846,35 +850,54 @@ static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
WRITE_ONCE(ifa->ifa_cstamp, ifa->ifa_tstamp);
}
-static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
- __u32 *pvalid_lft, __u32 *pprefered_lft,
- struct netlink_ext_ack *extack)
+static int inet_validate_rtm(struct nlmsghdr *nlh, struct nlattr **tb,
+ struct netlink_ext_ack *extack,
+ __u32 *valid_lft, __u32 *prefered_lft)
{
- struct nlattr *tb[IFA_MAX+1];
- struct in_ifaddr *ifa;
- struct ifaddrmsg *ifm;
- struct net_device *dev;
- struct in_device *in_dev;
+ struct ifaddrmsg *ifm = nlmsg_data(nlh);
int err;
err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
ifa_ipv4_policy, extack);
if (err < 0)
- goto errout;
-
- ifm = nlmsg_data(nlh);
- err = -EINVAL;
+ return err;
if (ifm->ifa_prefixlen > 32) {
NL_SET_ERR_MSG(extack, "ipv4: Invalid prefix length");
- goto errout;
+ return -EINVAL;
}
if (!tb[IFA_LOCAL]) {
NL_SET_ERR_MSG(extack, "ipv4: Local address is not supplied");
- goto errout;
+ return -EINVAL;
}
+ if (tb[IFA_CACHEINFO]) {
+ struct ifa_cacheinfo *ci;
+
+ ci = nla_data(tb[IFA_CACHEINFO]);
+ if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
+ NL_SET_ERR_MSG(extack, "ipv4: address lifetime invalid");
+ return -EINVAL;
+ }
+
+ *valid_lft = ci->ifa_valid;
+ *prefered_lft = ci->ifa_prefered;
+ }
+
+ return 0;
+}
+
+static struct in_ifaddr *inet_rtm_to_ifa(struct net *net, struct nlmsghdr *nlh,
+ struct nlattr **tb,
+ struct netlink_ext_ack *extack)
+{
+ struct ifaddrmsg *ifm = nlmsg_data(nlh);
+ struct in_device *in_dev;
+ struct net_device *dev;
+ struct in_ifaddr *ifa;
+ int err;
+
dev = __dev_get_by_index(net, ifm->ifa_index);
err = -ENODEV;
if (!dev) {
@@ -882,7 +905,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
goto errout;
}
- in_dev = __in_dev_get_rtnl(dev);
+ in_dev = __in_dev_get_rtnl_net(dev);
err = -ENOBUFS;
if (!in_dev)
goto errout;
@@ -903,8 +926,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
ifa->ifa_prefixlen = ifm->ifa_prefixlen;
ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
- ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
- ifm->ifa_flags;
+ ifa->ifa_flags = nla_get_u32_default(tb[IFA_FLAGS], ifm->ifa_flags);
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
@@ -923,76 +945,69 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
if (tb[IFA_PROTO])
ifa->ifa_proto = nla_get_u8(tb[IFA_PROTO]);
- if (tb[IFA_CACHEINFO]) {
- struct ifa_cacheinfo *ci;
-
- ci = nla_data(tb[IFA_CACHEINFO]);
- if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
- NL_SET_ERR_MSG(extack, "ipv4: address lifetime invalid");
- err = -EINVAL;
- goto errout_free;
- }
- *pvalid_lft = ci->ifa_valid;
- *pprefered_lft = ci->ifa_prefered;
- }
-
return ifa;
-errout_free:
- inet_free_ifa(ifa);
errout:
return ERR_PTR(err);
}
-static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
+static struct in_ifaddr *find_matching_ifa(struct net *net, struct in_ifaddr *ifa)
{
struct in_device *in_dev = ifa->ifa_dev;
struct in_ifaddr *ifa1;
- if (!ifa->ifa_local)
- return NULL;
-
- in_dev_for_each_ifa_rtnl(ifa1, in_dev) {
+ in_dev_for_each_ifa_rtnl_net(net, ifa1, in_dev) {
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa) &&
ifa1->ifa_local == ifa->ifa_local)
return ifa1;
}
+
return NULL;
}
static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
+ __u32 prefered_lft = INFINITY_LIFE_TIME;
+ __u32 valid_lft = INFINITY_LIFE_TIME;
struct net *net = sock_net(skb->sk);
- struct in_ifaddr *ifa;
struct in_ifaddr *ifa_existing;
- __u32 valid_lft = INFINITY_LIFE_TIME;
- __u32 prefered_lft = INFINITY_LIFE_TIME;
+ struct nlattr *tb[IFA_MAX + 1];
+ struct in_ifaddr *ifa;
+ int ret;
- ASSERT_RTNL();
+ ret = inet_validate_rtm(nlh, tb, extack, &valid_lft, &prefered_lft);
+ if (ret < 0)
+ return ret;
+
+ if (!nla_get_in_addr(tb[IFA_LOCAL]))
+ return 0;
+
+ rtnl_net_lock(net);
- ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack);
- if (IS_ERR(ifa))
- return PTR_ERR(ifa);
+ ifa = inet_rtm_to_ifa(net, nlh, tb, extack);
+ if (IS_ERR(ifa)) {
+ ret = PTR_ERR(ifa);
+ goto unlock;
+ }
- ifa_existing = find_matching_ifa(ifa);
+ ifa_existing = find_matching_ifa(net, ifa);
if (!ifa_existing) {
/* It would be best to check for !NLM_F_CREATE here but
* userspace already relies on not having to provide this.
*/
set_ifa_lifetime(ifa, valid_lft, prefered_lft);
if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
- int ret = ip_mc_autojoin_config(net, true, ifa);
-
+ ret = ip_mc_autojoin_config(net, true, ifa);
if (ret < 0) {
NL_SET_ERR_MSG(extack, "ipv4: Multicast auto join failed");
inet_free_ifa(ifa);
- return ret;
+ goto unlock;
}
}
- return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
- extack);
+
+ ret = __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid, extack);
} else {
u32 new_metric = ifa->ifa_rt_priority;
u8 new_proto = ifa->ifa_proto;
@@ -1002,7 +1017,8 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
if (nlh->nlmsg_flags & NLM_F_EXCL ||
!(nlh->nlmsg_flags & NLM_F_REPLACE)) {
NL_SET_ERR_MSG(extack, "ipv4: Address already assigned");
- return -EEXIST;
+ ret = -EEXIST;
+ goto unlock;
}
ifa = ifa_existing;
@@ -1019,7 +1035,11 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
&net->ipv4.addr_chk_work, 0);
rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
}
- return 0;
+
+unlock:
+ rtnl_net_unlock(net);
+
+ return ret;
}
/*
@@ -1106,7 +1126,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
goto out;
}
- rtnl_lock();
+ rtnl_net_lock(net);
ret = -ENODEV;
dev = __dev_get_by_name(net, ifr->ifr_name);
@@ -1116,7 +1136,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
if (colon)
*colon = ':';
- in_dev = __in_dev_get_rtnl(dev);
+ in_dev = __in_dev_get_rtnl_net(dev);
if (in_dev) {
if (tryaddrmatch) {
/* Matthias Andree */
@@ -1126,7 +1146,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
This is checked above. */
for (ifap = &in_dev->ifa_list;
- (ifa = rtnl_dereference(*ifap)) != NULL;
+ (ifa = rtnl_net_dereference(net, *ifap)) != NULL;
ifap = &ifa->ifa_next) {
if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
sin_orig.sin_addr.s_addr ==
@@ -1140,7 +1160,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
comparing just the label */
if (!ifa) {
for (ifap = &in_dev->ifa_list;
- (ifa = rtnl_dereference(*ifap)) != NULL;
+ (ifa = rtnl_net_dereference(net, *ifap)) != NULL;
ifap = &ifa->ifa_next)
if (!strcmp(ifr->ifr_name, ifa->ifa_label))
break;
@@ -1182,6 +1202,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
inet_del_ifa(in_dev, ifap, 1);
break;
}
+
+ /* NETDEV_UP/DOWN/CHANGE could touch a peer dev */
+ ASSERT_RTNL();
ret = dev_change_flags(dev, ifr->ifr_flags, NULL);
break;
@@ -1283,14 +1306,14 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
break;
}
done:
- rtnl_unlock();
+ rtnl_net_unlock(net);
out:
return ret;
}
int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
{
- struct in_device *in_dev = __in_dev_get_rtnl(dev);
+ struct in_device *in_dev = __in_dev_get_rtnl_net(dev);
const struct in_ifaddr *ifa;
struct ifreq ifr;
int done = 0;
@@ -1301,7 +1324,7 @@ int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
if (!in_dev)
goto out;
- in_dev_for_each_ifa_rtnl(ifa, in_dev) {
+ in_dev_for_each_ifa_rtnl_net(dev_net(dev), ifa, in_dev) {
if (!buf) {
done += size;
continue;
@@ -2372,7 +2395,7 @@ static void inet_forward_change(struct net *net)
if (on)
dev_disable_lro(dev);
- in_dev = __in_dev_get_rtnl(dev);
+ in_dev = __in_dev_get_rtnl_net(dev);
if (in_dev) {
IN_DEV_CONF_SET(in_dev, FORWARDING, on);
inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
@@ -2463,7 +2486,7 @@ static int devinet_sysctl_forward(const struct ctl_table *ctl, int write,
if (write && *valp != val) {
if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
- if (!rtnl_trylock()) {
+ if (!rtnl_net_trylock(net)) {
/* Restore the original values before restarting */
*valp = val;
*ppos = pos;
@@ -2482,7 +2505,7 @@ static int devinet_sysctl_forward(const struct ctl_table *ctl, int write,
idev->dev->ifindex,
cnf);
}
- rtnl_unlock();
+ rtnl_net_unlock(net);
rt_cache_flush(net);
} else
inet_netconf_notify_devconf(net, RTM_NEWNETCONF,
@@ -2813,8 +2836,10 @@ static struct rtnl_af_ops inet_af_ops __read_mostly = {
};
static const struct rtnl_msg_handler devinet_rtnl_msg_handlers[] __initconst = {
- {.protocol = PF_INET, .msgtype = RTM_NEWADDR, .doit = inet_rtm_newaddr},
- {.protocol = PF_INET, .msgtype = RTM_DELADDR, .doit = inet_rtm_deladdr},
+ {.protocol = PF_INET, .msgtype = RTM_NEWADDR, .doit = inet_rtm_newaddr,
+ .flags = RTNL_FLAG_DOIT_PERNET},
+ {.protocol = PF_INET, .msgtype = RTM_DELADDR, .doit = inet_rtm_deladdr,
+ .flags = RTNL_FLAG_DOIT_PERNET},
{.protocol = PF_INET, .msgtype = RTM_GETADDR, .dumpit = inet_dump_ifaddr,
.flags = RTNL_FLAG_DUMP_UNLOCKED | RTNL_FLAG_DUMP_SPLIT_NLM_DONE},
{.protocol = PF_INET, .msgtype = RTM_GETNETCONF,
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 53bd26315df5..87bb36a5bdec 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -293,7 +293,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
.flowi4_iif = LOOPBACK_IFINDEX,
.flowi4_l3mdev = l3mdev_master_ifindex_rcu(dev),
.daddr = ip_hdr(skb)->saddr,
- .flowi4_tos = ip_hdr(skb)->tos & INET_DSCP_MASK,
+ .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip_hdr(skb))),
.flowi4_scope = scope,
.flowi4_mark = vmark ? skb->mark : 0,
};
@@ -346,6 +346,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
int rpf, struct in_device *idev, u32 *itag)
{
struct net *net = dev_net(dev);
+ enum skb_drop_reason reason;
struct flow_keys flkeys;
int ret, no_addr;
struct fib_result res;
@@ -377,9 +378,15 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
if (fib_lookup(net, &fl4, &res, 0))
goto last_resort;
- if (res.type != RTN_UNICAST &&
- (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
- goto e_inval;
+ if (res.type != RTN_UNICAST) {
+ if (res.type != RTN_LOCAL) {
+ reason = SKB_DROP_REASON_IP_INVALID_SOURCE;
+ goto e_inval;
+ } else if (!IN_DEV_ACCEPT_LOCAL(idev)) {
+ reason = SKB_DROP_REASON_IP_LOCAL_SOURCE;
+ goto e_inval;
+ }
+ }
fib_combine_itag(itag, &res);
dev_match = fib_info_nh_uses_dev(res.fi, dev);
@@ -412,9 +419,9 @@ last_resort:
return 0;
e_inval:
- return -EINVAL;
+ return -reason;
e_rpf:
- return -EXDEV;
+ return -SKB_DROP_REASON_IP_RPFILTER;
}
/* Ignore rp_filter for packets protected by IPsec. */
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 23664434922e..4f088fa1c2f2 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -445,7 +445,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
fl4.saddr = saddr;
fl4.flowi4_mark = mark;
fl4.flowi4_uid = sock_net_uid(net, NULL);
- fl4.flowi4_tos = ip_hdr(skb)->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip_hdr(skb)));
fl4.flowi4_proto = IPPROTO_ICMP;
fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev);
security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4));
@@ -545,7 +545,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
orefdst = skb_in->_skb_refdst; /* save old refdst */
skb_dst_set(skb_in, NULL);
err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr,
- dscp, rt2->dst.dev);
+ dscp, rt2->dst.dev) ? -EINVAL : 0;
dst_release(&rt2->dst);
rt2 = skb_rtable(skb_in);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 48e2810f1f27..07036a2943c1 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -132,12 +132,12 @@ static bool frag_expire_skip_icmp(u32 user)
*/
static void ip_expire(struct timer_list *t)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT;
struct inet_frag_queue *frag = from_timer(frag, t, timer);
const struct iphdr *iph;
struct sk_buff *head = NULL;
struct net *net;
struct ipq *qp;
- int err;
qp = container_of(frag, struct ipq, q);
net = qp->q.fqdir->net;
@@ -175,14 +175,15 @@ static void ip_expire(struct timer_list *t)
/* skb has no dst, perform route lookup again */
iph = ip_hdr(head);
- err = ip_route_input_noref(head, iph->daddr, iph->saddr, ip4h_dscp(iph),
- head->dev);
- if (err)
+ reason = ip_route_input_noref(head, iph->daddr, iph->saddr,
+ ip4h_dscp(iph), head->dev);
+ if (reason)
goto out;
/* Only an end host needs to send an ICMP
* "Fragment Reassembly Timeout" message, per RFC792.
*/
+ reason = SKB_DROP_REASON_FRAG_REASM_TIMEOUT;
if (frag_expire_skip_icmp(qp->q.key.v4.user) &&
(skb_rtable(head)->rt_type != RTN_LOCAL))
goto out;
@@ -195,7 +196,7 @@ out:
spin_unlock(&qp->q.lock);
out_rcu_unlock:
rcu_read_unlock();
- kfree_skb_reason(head, SKB_DROP_REASON_FRAG_REASM_TIMEOUT);
+ kfree_skb_reason(head, reason);
ipq_put(qp);
}
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 89bb63da6852..f0a4dda246ab 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -322,15 +322,14 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
int err, drop_reason;
struct rtable *rt;
- drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
-
if (ip_can_use_hint(skb, iph, hint)) {
- err = ip_route_use_hint(skb, iph->daddr, iph->saddr,
- ip4h_dscp(iph), dev, hint);
- if (unlikely(err))
+ drop_reason = ip_route_use_hint(skb, iph->daddr, iph->saddr,
+ ip4h_dscp(iph), dev, hint);
+ if (unlikely(drop_reason))
goto drop_error;
}
+ drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) &&
!skb_dst(skb) &&
!skb->sk &&
@@ -362,10 +361,11 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
* how the packet travels inside Linux networking.
*/
if (!skb_valid_dst(skb)) {
- err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
- ip4h_dscp(iph), dev);
- if (unlikely(err))
+ drop_reason = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+ ip4h_dscp(iph), dev);
+ if (unlikely(drop_reason))
goto drop_error;
+ drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
} else {
struct in_device *in_dev = __in_dev_get_rcu(dev);
@@ -425,10 +425,8 @@ drop:
return NET_RX_DROP;
drop_error:
- if (err == -EXDEV) {
- drop_reason = SKB_DROP_REASON_IP_RPFILTER;
+ if (drop_reason == SKB_DROP_REASON_IP_RPFILTER)
__NET_INC_STATS(net, LINUX_MIB_IPRPFILTER);
- }
goto drop;
}
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 81e86e5defee..e3321932bec0 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -618,7 +618,7 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
orefdst = skb->_skb_refdst;
skb_dst_set(skb, NULL);
err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph),
- dev);
+ dev) ? -EINVAL : 0;
rt2 = skb_rtable(skb);
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
skb_dst_drop(skb);
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index d591c73e2c0e..25505f9b724c 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -218,7 +218,7 @@ static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
ip_tunnel_flags_copy(flags, parms->i_flags);
- hlist_for_each_entry_rcu(t, head, hash_node) {
+ hlist_for_each_entry_rcu(t, head, hash_node, lockdep_rtnl_is_held()) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
link == READ_ONCE(t->parms.link) &&
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index b4fc443481ce..c58dd78509a2 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2081,7 +2081,7 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
struct flowi4 fl4 = {
.daddr = iph->daddr,
.saddr = iph->saddr,
- .flowi4_tos = iph->tos & INET_DSCP_MASK,
+ .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph)),
.flowi4_oif = (rt_is_output_route(rt) ?
skb->dev->ifindex : 0),
.flowi4_iif = (rt_is_output_route(rt) ?
@@ -2546,9 +2546,9 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (err < 0)
goto errout;
- src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0;
- grp = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
- tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
+ src = nla_get_in_addr_default(tb[RTA_SRC], 0);
+ grp = nla_get_in_addr_default(tb[RTA_DST], 0);
+ tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
mrt = ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
if (!mrt) {
diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c
index 271dc03fc6db..f0af12a2f70b 100644
--- a/net/ipv4/ipmr_base.c
+++ b/net/ipv4/ipmr_base.c
@@ -310,7 +310,8 @@ int mr_table_dump(struct mr_table *mrt, struct sk_buff *skb,
if (filter->filter_set)
flags |= NLM_F_DUMP_FILTERED;
- list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
+ list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list,
+ lockdep_rtnl_is_held()) {
if (e < s_e)
goto next_entry;
if (filter->dev &&
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index e0aab66cd925..08bc3f2c0078 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -44,7 +44,7 @@ int ip_route_me_harder(struct net *net, struct sock *sk, struct sk_buff *skb, un
*/
fl4.daddr = iph->daddr;
fl4.saddr = saddr;
- fl4.flowi4_tos = iph->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph));
fl4.flowi4_oif = sk ? sk->sk_bound_dev_if : 0;
fl4.flowi4_l3mdev = l3mdev_master_ifindex(dev);
fl4.flowi4_mark = skb->mark;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1b991b889506..ef8009281da5 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -12,7 +12,13 @@ config NF_DEFRAG_IPV4
# old sockopt interface and eval loop
config IP_NF_IPTABLES_LEGACY
- tristate
+ tristate "Legacy IP tables support"
+ default n
+ select NETFILTER_XTABLES
+ help
+ iptables is a legacy packet classifier.
+ This is not needed if you are using iptables over nftables
+ (iptables-nft).
config NF_SOCKET_IPV4
tristate "IPv4 socket lookup support"
@@ -318,7 +324,13 @@ endif # IP_NF_IPTABLES
# ARP tables
config IP_NF_ARPTABLES
- tristate
+ tristate "Legacy ARPTABLES support"
+ depends on NETFILTER_XTABLES
+ default n
+ help
+ arptables is a legacy packet classifier.
+ This is not needed if you are using arptables over nftables
+ (iptables-nft).
config NFT_COMPAT_ARP
tristate
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index 1ce7a1655b97..a27782d7653e 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -76,7 +76,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
flow.daddr = iph->saddr;
flow.saddr = rpfilter_get_saddr(iph->daddr);
flow.flowi4_mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
- flow.flowi4_tos = iph->tos & INET_DSCP_MASK;
+ flow.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph));
flow.flowi4_scope = RT_SCOPE_UNIVERSE;
flow.flowi4_l3mdev = l3mdev_master_ifindex_rcu(xt_in(par));
flow.flowi4_uid = sock_net_uid(xt_net(par), NULL);
diff --git a/net/ipv4/netfilter/nf_dup_ipv4.c b/net/ipv4/netfilter/nf_dup_ipv4.c
index ec94ee1051c7..25e1e8eb18dd 100644
--- a/net/ipv4/netfilter/nf_dup_ipv4.c
+++ b/net/ipv4/netfilter/nf_dup_ipv4.c
@@ -33,7 +33,7 @@ static bool nf_dup_ipv4_route(struct net *net, struct sk_buff *skb,
fl4.flowi4_oif = oif;
fl4.daddr = gw->s_addr;
- fl4.flowi4_tos = iph->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph));
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
rt = ip_route_output_key(net, &fl4);
diff --git a/net/ipv4/netfilter/nft_fib_ipv4.c b/net/ipv4/netfilter/nft_fib_ipv4.c
index 09fff5d424ef..625adbc42037 100644
--- a/net/ipv4/netfilter/nft_fib_ipv4.c
+++ b/net/ipv4/netfilter/nft_fib_ipv4.c
@@ -11,6 +11,7 @@
#include <net/netfilter/nft_fib.h>
#include <net/inet_dscp.h>
+#include <net/ip.h>
#include <net/ip_fib.h>
#include <net/route.h>
@@ -107,7 +108,7 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
if (priv->flags & NFTA_FIB_F_MARK)
fl4.flowi4_mark = pkt->skb->mark;
- fl4.flowi4_tos = iph->tos & INET_DSCP_MASK;
+ fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph));
if (priv->flags & NFTA_FIB_F_DADDR) {
fl4.daddr = iph->daddr;
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 570e450e008c..09a3d73b45ba 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -3247,12 +3247,8 @@ static int nh_valid_get_del_req(const struct nlmsghdr *nlh,
return -EINVAL;
}
- if (op_flags) {
- if (tb[NHA_OP_FLAGS])
- *op_flags = nla_get_u32(tb[NHA_OP_FLAGS]);
- else
- *op_flags = 0;
- }
+ if (op_flags)
+ *op_flags = nla_get_u32_default(tb[NHA_OP_FLAGS], 0);
return 0;
}
@@ -3433,10 +3429,7 @@ static int nh_valid_dump_req(const struct nlmsghdr *nlh,
if (err < 0)
return err;
- if (tb[NHA_OP_FLAGS])
- filter->op_flags = nla_get_u32(tb[NHA_OP_FLAGS]);
- else
- filter->op_flags = 0;
+ filter->op_flags = nla_get_u32_default(tb[NHA_OP_FLAGS], 0);
return __nh_valid_dump_req(nlh, tb, filter, cb->extack);
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 18a08b4f4a5a..e5603e84b20d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1027,6 +1027,19 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
struct fib_nh_common *nhc;
fib_select_path(net, &res, fl4, NULL);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (fib_info_num_path(res.fi) > 1) {
+ int nhsel;
+
+ for (nhsel = 0; nhsel < fib_info_num_path(res.fi); nhsel++) {
+ nhc = fib_info_nhc(res.fi, nhsel);
+ update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock,
+ jiffies + net->ipv4.ip_rt_mtu_expires);
+ }
+ rcu_read_unlock();
+ return;
+ }
+#endif /* CONFIG_IP_ROUTE_MULTIPATH */
nhc = FIB_RES_NHC(res);
update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock,
jiffies + net->ipv4.ip_rt_mtu_expires);
@@ -1263,7 +1276,7 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt)
struct flowi4 fl4 = {
.daddr = iph->daddr,
.saddr = iph->saddr,
- .flowi4_tos = iph->tos & INET_DSCP_MASK,
+ .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(iph)),
.flowi4_oif = rt->dst.dev->ifindex,
.flowi4_iif = skb->dev->ifindex,
.flowi4_mark = skb->mark,
@@ -1665,50 +1678,54 @@ struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt)
EXPORT_SYMBOL(rt_dst_clone);
/* called in rcu_read_lock() section */
-int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev,
- struct in_device *in_dev, u32 *itag)
+enum skb_drop_reason
+ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev,
+ struct in_device *in_dev, u32 *itag)
{
- int err;
+ enum skb_drop_reason reason;
/* Primary sanity checks. */
if (!in_dev)
- return -EINVAL;
+ return SKB_DROP_REASON_NOT_SPECIFIED;
- if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
- skb->protocol != htons(ETH_P_IP))
- return -EINVAL;
+ if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
+ return SKB_DROP_REASON_IP_INVALID_SOURCE;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ return SKB_DROP_REASON_INVALID_PROTO;
if (ipv4_is_loopback(saddr) && !IN_DEV_ROUTE_LOCALNET(in_dev))
- return -EINVAL;
+ return SKB_DROP_REASON_IP_LOCALNET;
if (ipv4_is_zeronet(saddr)) {
if (!ipv4_is_local_multicast(daddr) &&
ip_hdr(skb)->protocol != IPPROTO_IGMP)
- return -EINVAL;
+ return SKB_DROP_REASON_IP_INVALID_SOURCE;
} else {
- err = fib_validate_source(skb, saddr, 0, dscp, 0, dev, in_dev,
- itag);
- if (err < 0)
- return err;
+ reason = fib_validate_source_reason(skb, saddr, 0, dscp, 0,
+ dev, in_dev, itag);
+ if (reason)
+ return reason;
}
- return 0;
+ return SKB_NOT_DROPPED_YET;
}
/* called in rcu_read_lock() section */
-static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev, int our)
+static enum skb_drop_reason
+ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev, int our)
{
struct in_device *in_dev = __in_dev_get_rcu(dev);
unsigned int flags = RTCF_MULTICAST;
+ enum skb_drop_reason reason;
struct rtable *rth;
u32 itag = 0;
- int err;
- err = ip_mc_validate_source(skb, daddr, saddr, dscp, dev, in_dev,
- &itag);
- if (err)
- return err;
+ reason = ip_mc_validate_source(skb, daddr, saddr, dscp, dev, in_dev,
+ &itag);
+ if (reason)
+ return reason;
if (our)
flags |= RTCF_LOCAL;
@@ -1719,7 +1736,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST,
false);
if (!rth)
- return -ENOBUFS;
+ return SKB_DROP_REASON_NOMEM;
#ifdef CONFIG_IP_ROUTE_CLASSID
rth->dst.tclassid = itag;
@@ -1735,7 +1752,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
skb_dst_drop(skb);
skb_dst_set(skb, &rth->dst);
- return 0;
+ return SKB_NOT_DROPPED_YET;
}
@@ -1765,10 +1782,12 @@ static void ip_handle_martian_source(struct net_device *dev,
}
/* called in rcu_read_lock() section */
-static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res,
- struct in_device *in_dev, __be32 daddr,
- __be32 saddr, dscp_t dscp)
+static enum skb_drop_reason
+__mkroute_input(struct sk_buff *skb, const struct fib_result *res,
+ struct in_device *in_dev, __be32 daddr,
+ __be32 saddr, dscp_t dscp)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct fib_nh_common *nhc = FIB_RES_NHC(*res);
struct net_device *dev = nhc->nhc_dev;
struct fib_nh_exception *fnhe;
@@ -1782,12 +1801,13 @@ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res,
out_dev = __in_dev_get_rcu(dev);
if (!out_dev) {
net_crit_ratelimited("Bug in ip_route_input_slow(). Please report.\n");
- return -EINVAL;
+ return reason;
}
err = fib_validate_source(skb, saddr, daddr, dscp, FIB_RES_OIF(*res),
in_dev->dev, in_dev, &itag);
if (err < 0) {
+ reason = -err;
ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
saddr);
@@ -1815,7 +1835,7 @@ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res,
*/
if (out_dev == in_dev &&
IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) {
- err = -EINVAL;
+ reason = SKB_DROP_REASON_ARP_PVLAN_DISABLE;
goto cleanup;
}
}
@@ -1838,7 +1858,7 @@ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res,
rth = rt_dst_alloc(out_dev->dev, 0, res->type,
IN_DEV_ORCONF(out_dev, NOXFRM));
if (!rth) {
- err = -ENOBUFS;
+ reason = SKB_DROP_REASON_NOMEM;
goto cleanup;
}
@@ -1852,9 +1872,9 @@ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res,
lwtunnel_set_redirect(&rth->dst);
skb_dst_set(skb, &rth->dst);
out:
- err = 0;
- cleanup:
- return err;
+ reason = SKB_NOT_DROPPED_YET;
+cleanup:
+ return reason;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -2112,9 +2132,10 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
}
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
-static int ip_mkroute_input(struct sk_buff *skb, struct fib_result *res,
- struct in_device *in_dev, __be32 daddr,
- __be32 saddr, dscp_t dscp, struct flow_keys *hkeys)
+static enum skb_drop_reason
+ip_mkroute_input(struct sk_buff *skb, struct fib_result *res,
+ struct in_device *in_dev, __be32 daddr,
+ __be32 saddr, dscp_t dscp, struct flow_keys *hkeys)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res->fi && fib_info_num_path(res->fi) > 1) {
@@ -2133,43 +2154,50 @@ static int ip_mkroute_input(struct sk_buff *skb, struct fib_result *res,
* assuming daddr is valid and the destination is not a local broadcast one.
* Uses the provided hint instead of performing a route lookup.
*/
-int ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev,
- const struct sk_buff *hint)
+enum skb_drop_reason
+ip_route_use_hint(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev,
+ const struct sk_buff *hint)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct in_device *in_dev = __in_dev_get_rcu(dev);
struct rtable *rt = skb_rtable(hint);
struct net *net = dev_net(dev);
- int err = -EINVAL;
u32 tag = 0;
if (!in_dev)
- return -EINVAL;
+ return reason;
- if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
+ if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) {
+ reason = SKB_DROP_REASON_IP_INVALID_SOURCE;
goto martian_source;
+ }
- if (ipv4_is_zeronet(saddr))
+ if (ipv4_is_zeronet(saddr)) {
+ reason = SKB_DROP_REASON_IP_INVALID_SOURCE;
goto martian_source;
+ }
- if (ipv4_is_loopback(saddr) && !IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
+ if (ipv4_is_loopback(saddr) && !IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) {
+ reason = SKB_DROP_REASON_IP_LOCALNET;
goto martian_source;
+ }
if (rt->rt_type != RTN_LOCAL)
goto skip_validate_source;
- err = fib_validate_source(skb, saddr, daddr, dscp, 0, dev, in_dev,
- &tag);
- if (err < 0)
+ reason = fib_validate_source_reason(skb, saddr, daddr, dscp, 0, dev,
+ in_dev, &tag);
+ if (reason)
goto martian_source;
skip_validate_source:
skb_dst_copy(skb, hint);
- return 0;
+ return SKB_NOT_DROPPED_YET;
martian_source:
ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
- return err;
+ return reason;
}
/* get device for dst_alloc with local routes */
@@ -2198,10 +2226,12 @@ static struct net_device *ip_rt_get_dev(struct net *net,
* called with rcu_read_lock()
*/
-static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev,
- struct fib_result *res)
+static enum skb_drop_reason
+ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev,
+ struct fib_result *res)
{
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct in_device *in_dev = __in_dev_get_rcu(dev);
struct flow_keys *flkeys = NULL, _flkeys;
struct net *net = dev_net(dev);
@@ -2229,8 +2259,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
fl4.flowi4_tun_key.tun_id = 0;
skb_dst_drop(skb);
- if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
+ if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) {
+ reason = SKB_DROP_REASON_IP_INVALID_SOURCE;
goto martian_source;
+ }
res->fi = NULL;
res->table = NULL;
@@ -2240,21 +2272,29 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
/* Accept zero addresses only to limited broadcast;
* I even do not know to fix it or not. Waiting for complains :-)
*/
- if (ipv4_is_zeronet(saddr))
+ if (ipv4_is_zeronet(saddr)) {
+ reason = SKB_DROP_REASON_IP_INVALID_SOURCE;
goto martian_source;
+ }
- if (ipv4_is_zeronet(daddr))
+ if (ipv4_is_zeronet(daddr)) {
+ reason = SKB_DROP_REASON_IP_INVALID_DEST;
goto martian_destination;
+ }
/* Following code try to avoid calling IN_DEV_NET_ROUTE_LOCALNET(),
* and call it once if daddr or/and saddr are loopback addresses
*/
if (ipv4_is_loopback(daddr)) {
- if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
+ if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) {
+ reason = SKB_DROP_REASON_IP_LOCALNET;
goto martian_destination;
+ }
} else if (ipv4_is_loopback(saddr)) {
- if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
+ if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) {
+ reason = SKB_DROP_REASON_IP_LOCALNET;
goto martian_source;
+ }
}
/*
@@ -2296,10 +2336,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto brd_input;
}
+ err = -EINVAL;
if (res->type == RTN_LOCAL) {
- err = fib_validate_source(skb, saddr, daddr, dscp, 0, dev,
- in_dev, &itag);
- if (err < 0)
+ reason = fib_validate_source_reason(skb, saddr, daddr, dscp,
+ 0, dev, in_dev, &itag);
+ if (reason)
goto martian_source;
goto local_input;
}
@@ -2308,21 +2349,28 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
err = -EHOSTUNREACH;
goto no_route;
}
- if (res->type != RTN_UNICAST)
+ if (res->type != RTN_UNICAST) {
+ reason = SKB_DROP_REASON_IP_INVALID_DEST;
goto martian_destination;
+ }
make_route:
- err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, dscp, flkeys);
-out: return err;
+ reason = ip_mkroute_input(skb, res, in_dev, daddr, saddr, dscp,
+ flkeys);
+
+out:
+ return reason;
brd_input:
- if (skb->protocol != htons(ETH_P_IP))
- goto e_inval;
+ if (skb->protocol != htons(ETH_P_IP)) {
+ reason = SKB_DROP_REASON_INVALID_PROTO;
+ goto out;
+ }
if (!ipv4_is_zeronet(saddr)) {
- err = fib_validate_source(skb, saddr, 0, dscp, 0, dev, in_dev,
- &itag);
- if (err < 0)
+ reason = fib_validate_source_reason(skb, saddr, 0, dscp, 0,
+ dev, in_dev, &itag);
+ if (reason)
goto martian_source;
}
flags |= RTCF_BROADCAST;
@@ -2340,7 +2388,7 @@ local_input:
rth = rcu_dereference(nhc->nhc_rth_input);
if (rt_cache_valid(rth)) {
skb_dst_set_noref(skb, &rth->dst);
- err = 0;
+ reason = SKB_NOT_DROPPED_YET;
goto out;
}
}
@@ -2377,7 +2425,7 @@ local_input:
rt_add_uncached_list(rth);
}
skb_dst_set(skb, &rth->dst);
- err = 0;
+ reason = SKB_NOT_DROPPED_YET;
goto out;
no_route:
@@ -2398,12 +2446,8 @@ martian_destination:
&daddr, &saddr, dev->name);
#endif
-e_inval:
- err = -EINVAL;
- goto out;
-
e_nobufs:
- err = -ENOBUFS;
+ reason = SKB_DROP_REASON_NOMEM;
goto out;
martian_source:
@@ -2412,9 +2456,10 @@ martian_source:
}
/* called with rcu_read_lock held */
-static int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev,
- struct fib_result *res)
+static enum skb_drop_reason
+ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ dscp_t dscp, struct net_device *dev,
+ struct fib_result *res)
{
/* Multicast recognition logic is moved from route cache to here.
* The problem was that too many Ethernet cards have broken/missing
@@ -2428,12 +2473,12 @@ static int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
* route cache entry is created eventually.
*/
if (ipv4_is_multicast(daddr)) {
+ enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
struct in_device *in_dev = __in_dev_get_rcu(dev);
int our = 0;
- int err = -EINVAL;
if (!in_dev)
- return err;
+ return -EINVAL;
our = ip_check_mc_rcu(in_dev, daddr, saddr,
ip_hdr(skb)->protocol);
@@ -2454,26 +2499,27 @@ static int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
IN_DEV_MFORWARD(in_dev))
#endif
) {
- err = ip_route_input_mc(skb, daddr, saddr, dscp, dev,
- our);
+ reason = ip_route_input_mc(skb, daddr, saddr, dscp,
+ dev, our);
}
- return err;
+ return reason;
}
return ip_route_input_slow(skb, daddr, saddr, dscp, dev, res);
}
-int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
- dscp_t dscp, struct net_device *dev)
+enum skb_drop_reason ip_route_input_noref(struct sk_buff *skb, __be32 daddr,
+ __be32 saddr, dscp_t dscp,
+ struct net_device *dev)
{
+ enum skb_drop_reason reason;
struct fib_result res;
- int err;
rcu_read_lock();
- err = ip_route_input_rcu(skb, daddr, saddr, dscp, dev, &res);
+ reason = ip_route_input_rcu(skb, daddr, saddr, dscp, dev, &res);
rcu_read_unlock();
- return err;
+ return reason;
}
EXPORT_SYMBOL(ip_route_input_noref);
@@ -3231,10 +3277,10 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
return err;
rtm = nlmsg_data(nlh);
- src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0;
- dst = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
- iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
- mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0;
+ src = nla_get_in_addr_default(tb[RTA_SRC], 0);
+ dst = nla_get_in_addr_default(tb[RTA_DST], 0);
+ iif = nla_get_u32_default(tb[RTA_IIF], 0);
+ mark = nla_get_u32_default(tb[RTA_MARK], 0);
if (tb[RTA_UID])
uid = make_kuid(current_user_ns(), nla_get_u32(tb[RTA_UID]));
else
@@ -3260,7 +3306,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
fl4.daddr = dst;
fl4.saddr = src;
fl4.flowi4_tos = rtm->rtm_tos & INET_DSCP_MASK;
- fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0;
+ fl4.flowi4_oif = nla_get_u32_default(tb[RTA_OIF], 0);
fl4.flowi4_mark = mark;
fl4.flowi4_uid = uid;
if (sport)
@@ -3285,7 +3331,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
skb->mark = mark;
err = ip_route_input_rcu(skb, dst, src,
inet_dsfield_to_dscp(rtm->rtm_tos),
- dev, &res);
+ dev, &res) ? -EINVAL : 0;
rt = skb_rtable(skb);
if (err == 0 && rt->dst.error)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 82cc4a5633ce..0d704bda6c41 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3336,7 +3336,7 @@ int tcp_disconnect(struct sock *sk, int flags)
tp->window_clamp = 0;
tp->delivered = 0;
tp->delivered_ce = 0;
- if (icsk->icsk_ca_ops->release)
+ if (icsk->icsk_ca_initialized && icsk->icsk_ca_ops->release)
icsk->icsk_ca_ops->release(sk);
memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv));
icsk->icsk_ca_initialized = 0;
diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c
index db6516092daf..bbb8d5f0eae7 100644
--- a/net/ipv4/tcp_ao.c
+++ b/net/ipv4/tcp_ao.c
@@ -109,12 +109,13 @@ bool tcp_ao_ignore_icmp(const struct sock *sk, int family, int type, int code)
* it's known that the keys in ao_info are matching peer's
* family/address/VRF/etc.
*/
-struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao,
+struct tcp_ao_key *tcp_ao_established_key(const struct sock *sk,
+ struct tcp_ao_info *ao,
int sndid, int rcvid)
{
struct tcp_ao_key *key;
- hlist_for_each_entry_rcu(key, &ao->head, node) {
+ hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) {
if ((sndid >= 0 && key->sndid != sndid) ||
(rcvid >= 0 && key->rcvid != rcvid))
continue;
@@ -205,7 +206,7 @@ static struct tcp_ao_key *__tcp_ao_do_lookup(const struct sock *sk, int l3index,
if (!ao)
return NULL;
- hlist_for_each_entry_rcu(key, &ao->head, node) {
+ hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk)) {
u8 prefixlen = min(prefix, key->prefixlen);
if (!tcp_ao_key_cmp(key, l3index, addr, prefixlen,
@@ -793,7 +794,7 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
if (!ao_info)
return -ENOENT;
- *key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1);
+ *key = tcp_ao_established_key(sk, ao_info, aoh->rnext_keyid, -1);
if (!*key)
return -ENOENT;
*traffic_key = snd_other_key(*key);
@@ -979,7 +980,7 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
*/
key = READ_ONCE(info->rnext_key);
if (key->rcvid != aoh->keyid) {
- key = tcp_ao_established_key(info, -1, aoh->keyid);
+ key = tcp_ao_established_key(sk, info, -1, aoh->keyid);
if (!key)
goto key_not_found;
}
@@ -1003,7 +1004,7 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
aoh->rnext_keyid,
tcp_ao_hdr_maclen(aoh));
/* If the key is not found we do nothing. */
- key = tcp_ao_established_key(info, aoh->rnext_keyid, -1);
+ key = tcp_ao_established_key(sk, info, aoh->rnext_keyid, -1);
if (key)
/* pairs with tcp_ao_del_cmd */
WRITE_ONCE(info->current_key, key);
@@ -1163,7 +1164,7 @@ void tcp_ao_established(struct sock *sk)
if (!ao)
return;
- hlist_for_each_entry_rcu(key, &ao->head, node)
+ hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk))
tcp_ao_cache_traffic_keys(sk, ao, key);
}
@@ -1180,7 +1181,7 @@ void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb)
WRITE_ONCE(ao->risn, tcp_hdr(skb)->seq);
ao->rcv_sne = 0;
- hlist_for_each_entry_rcu(key, &ao->head, node)
+ hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk))
tcp_ao_cache_traffic_keys(sk, ao, key);
}
@@ -1256,14 +1257,14 @@ int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk,
key_head = rcu_dereference(hlist_first_rcu(&new_ao->head));
first_key = hlist_entry_safe(key_head, struct tcp_ao_key, node);
- key = tcp_ao_established_key(new_ao, tcp_rsk(req)->ao_keyid, -1);
+ key = tcp_ao_established_key(req_to_sk(req), new_ao, tcp_rsk(req)->ao_keyid, -1);
if (key)
new_ao->current_key = key;
else
new_ao->current_key = first_key;
/* set rnext_key */
- key = tcp_ao_established_key(new_ao, -1, tcp_rsk(req)->ao_rcv_next);
+ key = tcp_ao_established_key(req_to_sk(req), new_ao, -1, tcp_rsk(req)->ao_rcv_next);
if (key)
new_ao->rnext_key = key;
else
@@ -1857,12 +1858,12 @@ static int tcp_ao_del_cmd(struct sock *sk, unsigned short int family,
* if there's any.
*/
if (cmd.set_current) {
- new_current = tcp_ao_established_key(ao_info, cmd.current_key, -1);
+ new_current = tcp_ao_established_key(sk, ao_info, cmd.current_key, -1);
if (!new_current)
return -ENOENT;
}
if (cmd.set_rnext) {
- new_rnext = tcp_ao_established_key(ao_info, -1, cmd.rnext);
+ new_rnext = tcp_ao_established_key(sk, ao_info, -1, cmd.rnext);
if (!new_rnext)
return -ENOENT;
}
@@ -1902,7 +1903,8 @@ static int tcp_ao_del_cmd(struct sock *sk, unsigned short int family,
* "It is presumed that an MKT affecting a particular
* connection cannot be destroyed during an active connection"
*/
- hlist_for_each_entry_rcu(key, &ao_info->head, node) {
+ hlist_for_each_entry_rcu(key, &ao_info->head, node,
+ lockdep_sock_is_held(sk)) {
if (cmd.sndid != key->sndid ||
cmd.rcvid != key->rcvid)
continue;
@@ -2000,14 +2002,14 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family,
* if there's any.
*/
if (cmd.set_current) {
- new_current = tcp_ao_established_key(ao_info, cmd.current_key, -1);
+ new_current = tcp_ao_established_key(sk, ao_info, cmd.current_key, -1);
if (!new_current) {
err = -ENOENT;
goto out;
}
}
if (cmd.set_rnext) {
- new_rnext = tcp_ao_established_key(ao_info, -1, cmd.rnext);
+ new_rnext = tcp_ao_established_key(sk, ao_info, -1, cmd.rnext);
if (!new_rnext) {
err = -ENOENT;
goto out;
@@ -2101,7 +2103,8 @@ int tcp_v4_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen)
* The layout of the fields in the user and kernel structures is expected to
* be the same (including in the 32bit vs 64bit case).
*/
-static int tcp_ao_copy_mkts_to_user(struct tcp_ao_info *ao_info,
+static int tcp_ao_copy_mkts_to_user(const struct sock *sk,
+ struct tcp_ao_info *ao_info,
sockptr_t optval, sockptr_t optlen)
{
struct tcp_ao_getsockopt opt_in, opt_out;
@@ -2229,7 +2232,8 @@ static int tcp_ao_copy_mkts_to_user(struct tcp_ao_info *ao_info,
/* May change in RX, while we're dumping, pre-fetch it */
current_key = READ_ONCE(ao_info->current_key);
- hlist_for_each_entry_rcu(key, &ao_info->head, node) {
+ hlist_for_each_entry_rcu(key, &ao_info->head, node,
+ lockdep_sock_is_held(sk)) {
if (opt_in.get_all)
goto match;
@@ -2309,7 +2313,7 @@ int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen)
if (!ao_info)
return -ENOENT;
- return tcp_ao_copy_mkts_to_user(ao_info, optval, optlen);
+ return tcp_ao_copy_mkts_to_user(sk, ao_info, optval, optlen);
}
int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen)
@@ -2396,7 +2400,7 @@ int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen)
WRITE_ONCE(ao->snd_sne, cmd.snd_sne);
WRITE_ONCE(ao->rcv_sne, cmd.rcv_sne);
- hlist_for_each_entry_rcu(key, &ao->head, node)
+ hlist_for_each_entry_rcu(key, &ao->head, node, lockdep_sock_is_held(sk))
tcp_ao_cache_traffic_keys(sk, ao, key);
return 0;
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index e7658c5d6b79..370993c03d31 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -221,11 +221,11 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
int flags,
int *addr_len)
{
- struct tcp_sock *tcp = tcp_sk(sk);
int peek = flags & MSG_PEEK;
- u32 seq = tcp->copied_seq;
struct sk_psock *psock;
+ struct tcp_sock *tcp;
int copied = 0;
+ u32 seq;
if (unlikely(flags & MSG_ERRQUEUE))
return inet_recv_error(sk, msg, len, addr_len);
@@ -238,7 +238,8 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
return tcp_recvmsg(sk, msg, len, flags, addr_len);
lock_sock(sk);
-
+ tcp = tcp_sk(sk);
+ seq = tcp->copied_seq;
/* We may have received data on the sk_receive_queue pre-accept and
* then we can not use read_skb in this context because we haven't
* assigned a sk_socket yet so have no link to the ops. The work-around
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 0306d257fa64..df758adbb445 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -270,8 +270,9 @@ void tcp_cleanup_congestion_control(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
- if (icsk->icsk_ca_ops->release)
+ if (icsk->icsk_ca_initialized && icsk->icsk_ca_ops->release)
icsk->icsk_ca_ops->release(sk);
+ icsk->icsk_ca_initialized = 0;
bpf_module_put(icsk->icsk_ca_ops, icsk->icsk_ca_ops->owner);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2d844e1f867f..5bdf13ac26ef 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4921,8 +4921,8 @@ static bool tcp_ooo_try_coalesce(struct sock *sk,
return res;
}
-static void tcp_drop_reason(struct sock *sk, struct sk_buff *skb,
- enum skb_drop_reason reason)
+noinline_for_tracing static void
+tcp_drop_reason(struct sock *sk, struct sk_buff *skb, enum skb_drop_reason reason)
{
sk_drops_add(sk, skb);
sk_skb_reason_drop(sk, skb, reason);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 9d3dd101ea71..a38c8b1f44db 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1053,7 +1053,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
}
if (aoh)
- key.ao_key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1);
+ key.ao_key = tcp_ao_established_key(sk, ao_info,
+ aoh->rnext_keyid, -1);
}
}
if (key.ao_key) {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 054244ce5117..5485a70b5fe5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2954,9 +2954,7 @@ void tcp_send_loss_probe(struct sock *sk)
}
skb = skb_rb_last(&sk->tcp_rtx_queue);
if (unlikely(!skb)) {
- WARN_ONCE(tp->packets_out,
- "invalid inflight: %u state %u cwnd %u mss %d\n",
- tp->packets_out, sk->sk_state, tcp_snd_cwnd(tp), mss);
+ tcp_warn_once(sk, tp->packets_out, "invalid inflight: ");
smp_store_release(&inet_csk(sk)->icsk_pending, 0);
return;
}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d0a99710d65d..96b5b2b0d507 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4793,7 +4793,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!pfx)
return -EINVAL;
- ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
+ ifa_flags = nla_get_u32_default(tb[IFA_FLAGS], ifm->ifa_flags);
/* We ignore other flags so far. */
ifa_flags &= IFA_F_MANAGETEMPADDR;
@@ -5018,10 +5018,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
return -ENODEV;
}
- if (tb[IFA_FLAGS])
- cfg.ifa_flags = nla_get_u32(tb[IFA_FLAGS]);
- else
- cfg.ifa_flags = ifm->ifa_flags;
+ cfg.ifa_flags = nla_get_u32_default(tb[IFA_FLAGS], ifm->ifa_flags);
/* We ignore other flags so far. */
cfg.ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS |
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 534a4498e280..7646e401c630 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -105,16 +105,11 @@ static int parse_nl_config(struct genl_info *info,
xp->ip.locator_match.v64 = (__force __be64)nla_get_u64(
info->attrs[ILA_ATTR_LOCATOR_MATCH]);
- if (info->attrs[ILA_ATTR_CSUM_MODE])
- xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
- else
- xp->ip.csum_mode = ILA_CSUM_NO_ACTION;
-
- if (info->attrs[ILA_ATTR_IDENT_TYPE])
- xp->ip.ident_type = nla_get_u8(
- info->attrs[ILA_ATTR_IDENT_TYPE]);
- else
- xp->ip.ident_type = ILA_ATYPE_USE_FORMAT;
+ xp->ip.csum_mode = nla_get_u8_default(info->attrs[ILA_ATTR_CSUM_MODE],
+ ILA_CSUM_NO_ACTION);
+
+ xp->ip.ident_type = nla_get_u8_default(info->attrs[ILA_ATTR_IDENT_TYPE],
+ ILA_ATYPE_USE_FORMAT);
if (info->attrs[ILA_ATTR_IFINDEX])
xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
index 08c929513065..a84d332f952f 100644
--- a/net/ipv6/ioam6.c
+++ b/net/ipv6/ioam6.c
@@ -135,15 +135,11 @@ static int ioam6_genl_addns(struct sk_buff *skb, struct genl_info *info)
ns->id = id;
- if (!info->attrs[IOAM6_ATTR_NS_DATA])
- data32 = IOAM6_U32_UNAVAILABLE;
- else
- data32 = nla_get_u32(info->attrs[IOAM6_ATTR_NS_DATA]);
-
- if (!info->attrs[IOAM6_ATTR_NS_DATA_WIDE])
- data64 = IOAM6_U64_UNAVAILABLE;
- else
- data64 = nla_get_u64(info->attrs[IOAM6_ATTR_NS_DATA_WIDE]);
+ data32 = nla_get_u32_default(info->attrs[IOAM6_ATTR_NS_DATA],
+ IOAM6_U32_UNAVAILABLE);
+
+ data64 = nla_get_u64_default(info->attrs[IOAM6_ATTR_NS_DATA_WIDE],
+ IOAM6_U64_UNAVAILABLE);
ns->data = cpu_to_be32(data32);
ns->data_wide = cpu_to_be64(data64);
diff --git a/net/ipv6/ioam6_iptunnel.c b/net/ipv6/ioam6_iptunnel.c
index beb6b4cfc551..9d8422e350f8 100644
--- a/net/ipv6/ioam6_iptunnel.c
+++ b/net/ipv6/ioam6_iptunnel.c
@@ -142,10 +142,8 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla,
}
}
- if (!tb[IOAM6_IPTUNNEL_MODE])
- mode = IOAM6_IPTUNNEL_MODE_INLINE;
- else
- mode = nla_get_u8(tb[IOAM6_IPTUNNEL_MODE]);
+ mode = nla_get_u8_default(tb[IOAM6_IPTUNNEL_MODE],
+ IOAM6_IPTUNNEL_MODE_INLINE);
if (tb[IOAM6_IPTUNNEL_SRC] && mode == IOAM6_IPTUNNEL_MODE_INLINE) {
NL_SET_ERR_MSG(extack, "no tunnel src expected with this mode");
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 6383263bfd04..c134ba202c4c 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1183,8 +1183,8 @@ next_iter:
while (sibling) {
if (sibling->fib6_metric == rt->fib6_metric &&
rt6_qualify_for_ecmp(sibling)) {
- list_add_tail(&rt->fib6_siblings,
- &sibling->fib6_siblings);
+ list_add_tail_rcu(&rt->fib6_siblings,
+ &sibling->fib6_siblings);
break;
}
sibling = rcu_dereference_protected(sibling->fib6_next,
@@ -1245,7 +1245,7 @@ add:
fib6_siblings)
sibling->fib6_nsiblings--;
rt->fib6_nsiblings = 0;
- list_del_init(&rt->fib6_siblings);
+ list_del_rcu(&rt->fib6_siblings);
rt6_multipath_rebalance(next_sibling);
return err;
}
@@ -1963,7 +1963,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
&rt->fib6_siblings, fib6_siblings)
sibling->fib6_nsiblings--;
rt->fib6_nsiblings = 0;
- list_del_init(&rt->fib6_siblings);
+ list_del_rcu(&rt->fib6_siblings);
rt6_multipath_rebalance(next_sibling);
}
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 8add0f45aa52..d66f58932a79 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2560,7 +2560,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
src = nla_get_in6_addr(tb[RTA_SRC]);
if (tb[RTA_DST])
grp = nla_get_in6_addr(tb[RTA_DST]);
- tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
+ tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
mrt = ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
if (!mrt) {
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index f3c8e2d918e1..e087a8e97ba7 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -8,7 +8,14 @@ menu "IPv6: Netfilter Configuration"
# old sockopt interface and eval loop
config IP6_NF_IPTABLES_LEGACY
- tristate
+ tristate "Legacy IP6 tables support"
+ depends on INET && IPV6
+ select NETFILTER_XTABLES
+ default n
+ help
+ ip6tables is a legacy packet classifier.
+ This is not needed if you are using iptables over nftables
+ (iptables-nft).
config NF_SOCKET_IPV6
tristate "IPv6 socket lookup support"
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
index 7db0437140bf..9ae2b2725bf9 100644
--- a/net/ipv6/netfilter/nf_reject_ipv6.c
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -268,12 +268,12 @@ static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
int hook)
{
- struct sk_buff *nskb;
- struct tcphdr _otcph;
- const struct tcphdr *otcph;
- unsigned int otcplen, hh_len;
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
struct dst_entry *dst = NULL;
+ const struct tcphdr *otcph;
+ struct sk_buff *nskb;
+ struct tcphdr _otcph;
+ unsigned int otcplen;
struct flowi6 fl6;
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
@@ -312,9 +312,8 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
if (IS_ERR(dst))
return;
- hh_len = (dst->dev->hard_header_len + 15)&~15;
- nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
- + sizeof(struct tcphdr) + dst->trailer_len,
+ nskb = alloc_skb(LL_MAX_HEADER + sizeof(struct ipv6hdr) +
+ sizeof(struct tcphdr) + dst->trailer_len,
GFP_ATOMIC);
if (!nskb) {
@@ -327,7 +326,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
nskb->mark = fl6.flowi6_mark;
- skb_reserve(nskb, hh_len + dst->header_len);
+ skb_reserve(nskb, LL_MAX_HEADER);
nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, ip6_dst_hoplimit(dst));
nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d7ce5cf2017a..63d7681c929f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -374,6 +374,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{
struct rt6_info *rt = dst_rt6_info(dst);
struct inet6_dev *idev = rt->rt6i_idev;
+ struct fib6_info *from;
if (idev && idev->dev != blackhole_netdev) {
struct inet6_dev *blackhole_idev = in6_dev_get(blackhole_netdev);
@@ -383,6 +384,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
in6_dev_put(idev);
}
}
+ from = unrcu_pointer(xchg(&rt->from, NULL));
+ fib6_info_release(from);
}
static bool __rt6_check_expired(const struct rt6_info *rt)
@@ -413,8 +416,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
struct flowi6 *fl6, int oif, bool have_oif_match,
const struct sk_buff *skb, int strict)
{
- struct fib6_info *sibling, *next_sibling;
struct fib6_info *match = res->f6i;
+ struct fib6_info *sibling;
if (!match->nh && (!match->fib6_nsiblings || have_oif_match))
goto out;
@@ -440,8 +443,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
if (fl6->mp_hash <= atomic_read(&match->fib6_nh->fib_nh_upper_bound))
goto out;
- list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
- fib6_siblings) {
+ list_for_each_entry_rcu(sibling, &match->fib6_siblings,
+ fib6_siblings) {
const struct fib6_nh *nh = sibling->fib6_nh;
int nh_upper_bound;
@@ -1455,7 +1458,6 @@ static DEFINE_SPINLOCK(rt6_exception_lock);
static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
struct rt6_exception *rt6_ex)
{
- struct fib6_info *from;
struct net *net;
if (!bucket || !rt6_ex)
@@ -1467,8 +1469,6 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
/* purge completely the exception to allow releasing the held resources:
* some [sk] cache may keep the dst around for unlimited time
*/
- from = unrcu_pointer(xchg(&rt6_ex->rt6i->from, NULL));
- fib6_info_release(from);
dst_dev_put(&rt6_ex->rt6i->dst);
hlist_del_rcu(&rt6_ex->hlist);
@@ -5195,14 +5195,18 @@ static void ip6_route_mpath_notify(struct fib6_info *rt,
* nexthop. Since sibling routes are always added at the end of
* the list, find the first sibling of the last route appended
*/
+ rcu_read_lock();
+
if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
- rt = list_first_entry(&rt_last->fib6_siblings,
- struct fib6_info,
- fib6_siblings);
+ rt = list_first_or_null_rcu(&rt_last->fib6_siblings,
+ struct fib6_info,
+ fib6_siblings);
}
if (rt)
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
+
+ rcu_read_unlock();
}
static bool ip6_route_mpath_should_notify(const struct fib6_info *rt)
@@ -5547,17 +5551,21 @@ static size_t rt6_nlmsg_size(struct fib6_info *f6i)
nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size,
&nexthop_len);
} else {
- struct fib6_info *sibling, *next_sibling;
struct fib6_nh *nh = f6i->fib6_nh;
+ struct fib6_info *sibling;
nexthop_len = 0;
if (f6i->fib6_nsiblings) {
rt6_nh_nlmsg_size(nh, &nexthop_len);
- list_for_each_entry_safe(sibling, next_sibling,
- &f6i->fib6_siblings, fib6_siblings) {
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
+ fib6_siblings) {
rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len);
}
+
+ rcu_read_unlock();
}
nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
}
@@ -5721,7 +5729,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
lwtunnel_fill_encap(skb, dst->lwtstate, RTA_ENCAP, RTA_ENCAP_TYPE) < 0)
goto nla_put_failure;
} else if (rt->fib6_nsiblings) {
- struct fib6_info *sibling, *next_sibling;
+ struct fib6_info *sibling;
struct nlattr *mp;
mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
@@ -5733,14 +5741,21 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
0) < 0)
goto nla_put_failure;
- list_for_each_entry_safe(sibling, next_sibling,
- &rt->fib6_siblings, fib6_siblings) {
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(sibling, &rt->fib6_siblings,
+ fib6_siblings) {
if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
sibling->fib6_nh->fib_nh_weight,
- AF_INET6, 0) < 0)
+ AF_INET6, 0) < 0) {
+ rcu_read_unlock();
+
goto nla_put_failure;
+ }
}
+ rcu_read_unlock();
+
nla_nest_end(skb, mp);
} else if (rt->nh) {
if (nla_put_u32(skb, RTA_NH_ID, rt->nh->id))
@@ -6177,7 +6192,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
err = -ENOBUFS;
seq = info->nlh ? info->nlh->nlmsg_seq : 0;
- skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
+ skb = nlmsg_new(rt6_nlmsg_size(rt), GFP_ATOMIC);
if (!skb)
goto errout;
@@ -6190,7 +6205,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
goto errout;
}
rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
- info->nlh, gfp_any());
+ info->nlh, GFP_ATOMIC);
return;
errout:
rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index c74705ead984..ac1dbd492c22 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -954,10 +954,10 @@ static int input_action_end_dx4_finish(struct net *net, struct sock *sk,
struct sk_buff *skb)
{
struct dst_entry *orig_dst = skb_dst(skb);
+ enum skb_drop_reason reason;
struct seg6_local_lwt *slwt;
struct iphdr *iph;
__be32 nhaddr;
- int err;
slwt = seg6_local_lwtunnel(orig_dst->lwtstate);
@@ -967,9 +967,9 @@ static int input_action_end_dx4_finish(struct net *net, struct sock *sk,
skb_dst_drop(skb);
- err = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev);
- if (err) {
- kfree_skb(skb);
+ reason = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev);
+ if (reason) {
+ kfree_skb_reason(skb, reason);
return -EINVAL;
}
@@ -1174,8 +1174,8 @@ drop:
static int input_action_end_dt4(struct sk_buff *skb,
struct seg6_local_lwt *slwt)
{
+ enum skb_drop_reason reason;
struct iphdr *iph;
- int err;
if (!decap_and_validate(skb, IPPROTO_IPIP))
goto drop;
@@ -1193,8 +1193,8 @@ static int input_action_end_dt4(struct sk_buff *skb,
iph = ip_hdr(skb);
- err = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev);
- if (unlikely(err))
+ reason = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev);
+ if (unlikely(reason))
goto drop;
return dst_input(skb);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 597920061a3a..2debdf085a3b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1172,8 +1172,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh))
goto out;
if (aoh)
- key.ao_key = tcp_ao_established_key(ao_info,
- aoh->rnext_keyid, -1);
+ key.ao_key = tcp_ao_established_key(sk, ao_info,
+ aoh->rnext_keyid, -1);
}
}
if (key.ao_key) {
@@ -1621,7 +1621,7 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
by tcp. Feel free to propose better solution.
--ANK (980728)
*/
- if (np->rxopt.all)
+ if (np->rxopt.all && sk->sk_state != TCP_LISTEN)
opt_skb = skb_clone_and_charge_r(skb, sk);
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
@@ -1659,8 +1659,6 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (reason)
goto reset;
}
- if (opt_skb)
- __kfree_skb(opt_skb);
return 0;
}
} else
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 13438cc0a6b1..cf0f7780fb10 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -96,7 +96,7 @@ config MAC80211_DEBUGFS
config MAC80211_MESSAGE_TRACING
bool "Trace all mac80211 debug messages"
- depends on MAC80211
+ depends on MAC80211 && TRACING
help
Select this option to have mac80211 register the
mac80211_msg trace subsystem with tracepoints to
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index fe7eab4b681b..f3fbe5a4395e 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -170,28 +170,63 @@ static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
rcu_read_unlock();
}
-static void ieee80211_add_addbaext(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb,
- const struct ieee80211_addba_ext_ie *req,
- u16 buf_size)
+void ieee80211_add_addbaext(struct sk_buff *skb,
+ const u8 req_addba_ext_data,
+ u16 buf_size)
{
- struct ieee80211_addba_ext_ie *resp;
+ struct ieee80211_addba_ext_ie *addba_ext;
u8 *pos;
pos = skb_put_zero(skb, 2 + sizeof(struct ieee80211_addba_ext_ie));
*pos++ = WLAN_EID_ADDBA_EXT;
*pos++ = sizeof(struct ieee80211_addba_ext_ie);
- resp = (struct ieee80211_addba_ext_ie *)pos;
- resp->data = req->data & IEEE80211_ADDBA_EXT_NO_FRAG;
+ addba_ext = (struct ieee80211_addba_ext_ie *)pos;
- resp->data |= u8_encode_bits(buf_size >> IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT,
- IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
+ addba_ext->data = IEEE80211_ADDBA_EXT_NO_FRAG;
+ if (req_addba_ext_data)
+ addba_ext->data &= req_addba_ext_data;
+
+ addba_ext->data |=
+ u8_encode_bits(buf_size >> IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT,
+ IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
+}
+
+u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
+ const void *elem_data, ssize_t elem_len,
+ u16 *buf_size)
+{
+ struct ieee802_11_elems *elems;
+ u8 buf_size_1k, data = 0;
+
+ if (!sta->sta.deflink.he_cap.has_he)
+ return 0;
+
+ if (elem_len <= 0)
+ return 0;
+
+ elems = ieee802_11_parse_elems(elem_data, elem_len, true, NULL);
+
+ if (elems && !elems->parse_error && elems->addba_ext_ie) {
+ data = elems->addba_ext_ie->data;
+
+ if (!sta->sta.deflink.eht_cap.has_eht || !buf_size)
+ goto free;
+
+ buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
+ IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
+ *buf_size |= (u16)buf_size_1k <<
+ IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
+ }
+free:
+ kfree(elems);
+
+ return data;
}
static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
u8 dialog_token, u16 status, u16 policy,
u16 buf_size, u16 timeout,
- const struct ieee80211_addba_ext_ie *addbaext)
+ const u8 req_addba_ext_data)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
@@ -223,8 +258,8 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
- if (sta->sta.deflink.he_cap.has_he && addbaext)
- ieee80211_add_addbaext(sdata, skb, addbaext, buf_size);
+ if (sta->sta.deflink.he_cap.has_he)
+ ieee80211_add_addbaext(skb, req_addba_ext_data, buf_size);
ieee80211_tx_skb(sdata, skb);
}
@@ -233,7 +268,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq,
- const struct ieee80211_addba_ext_ie *addbaext)
+ const u8 addba_ext_data)
{
struct ieee80211_local *local = sta->sdata->local;
struct tid_ampdu_rx *tid_agg_rx;
@@ -419,7 +454,7 @@ end:
if (tx)
ieee80211_send_addba_resp(sta, sta->sta.addr, tid,
dialog_token, status, 1, buf_size,
- timeout, addbaext);
+ timeout, addba_ext_data);
}
void ieee80211_process_addba_request(struct ieee80211_local *local,
@@ -428,9 +463,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
size_t len)
{
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
- struct ieee802_11_elems *elems = NULL;
- u8 dialog_token;
- int ies_len;
+ u8 dialog_token, addba_ext_data;
/* extract session parameters from addba request frame */
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
@@ -443,28 +476,17 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
- ies_len = len - offsetof(struct ieee80211_mgmt,
- u.action.u.addba_req.variable);
- if (ies_len) {
- elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
- ies_len, true, NULL);
- if (!elems || elems->parse_error)
- goto free;
- }
-
- if (sta->sta.deflink.eht_cap.has_eht && elems && elems->addba_ext_ie) {
- u8 buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
- IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
-
- buf_size |= buf_size_1k << IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
- }
+ addba_ext_data =
+ ieee80211_retrieve_addba_ext_data(sta,
+ mgmt->u.action.u.addba_req.variable,
+ len -
+ offsetof(typeof(*mgmt),
+ u.action.u.addba_req.variable),
+ &buf_size);
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
start_seq_num, ba_policy, tid,
- buf_size, true, false,
- elems ? elems->addba_ext_ie : NULL);
-free:
- kfree(elems);
+ buf_size, true, false, addba_ext_data);
}
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 1c18b862ef8c..61f2cac37728 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -58,23 +58,24 @@
* complete.
*/
-static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
- const u8 *da, u16 tid,
+static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
u8 dialog_token, u16 start_seq_num,
u16 agg_size, u16 timeout)
{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
+ skb = dev_alloc_skb(sizeof(*mgmt) +
+ 2 + sizeof(struct ieee80211_addba_ext_ie) +
+ local->hw.extra_tx_headroom);
if (!skb)
return;
skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = ieee80211_mgmt_ba(skb, da, sdata);
+ mgmt = ieee80211_mgmt_ba(skb, sta->sta.addr, sdata);
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
@@ -93,6 +94,9 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
mgmt->u.action.u.addba_req.start_seq_num =
cpu_to_le16(start_seq_num << 4);
+ if (sta->sta.deflink.he_cap.has_he)
+ ieee80211_add_addbaext(skb, 0, agg_size);
+
ieee80211_tx_skb_tid(sdata, skb, tid, -1);
}
@@ -460,8 +464,11 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
sta->ampdu_mlme.addba_req_num[tid]++;
spin_unlock_bh(&sta->lock);
- if (sta->sta.deflink.he_cap.has_he) {
+ if (sta->sta.deflink.eht_cap.has_eht) {
buf_size = local->hw.max_tx_aggregation_subframes;
+ } else if (sta->sta.deflink.he_cap.has_he) {
+ buf_size = min_t(u16, local->hw.max_tx_aggregation_subframes,
+ IEEE80211_MAX_AMPDU_BUF_HE);
} else {
/*
* We really should use what the driver told us it will
@@ -473,9 +480,8 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
}
/* send AddBA request */
- ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
- tid_tx->dialog_token, tid_tx->ssn,
- buf_size, tid_tx->timeout);
+ ieee80211_send_addba_request(sta, tid, tid_tx->dialog_token,
+ tid_tx->ssn, buf_size, tid_tx->timeout);
WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
}
@@ -797,7 +803,7 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) {
ieee80211_send_addba_with_timeout(sta, tid_tx);
- /* RESPONSE_RECEIVED state whould trigger the flow again */
+ /* RESPONSE_RECEIVED state would trigger the flow again */
return;
}
@@ -970,6 +976,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
+
+ ieee80211_retrieve_addba_ext_data(sta,
+ mgmt->u.action.u.addba_resp.variable,
+ len - offsetof(typeof(*mgmt),
+ u.action.u.addba_resp.variable),
+ &buf_size);
+
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
txq = sta->sta.txq[tid];
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 847304a3a29a..61a824ec33da 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -105,8 +105,11 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
}
/* also validate MU-MIMO change */
- monitor_sdata = wiphy_dereference(local->hw.wiphy,
- local->monitor_sdata);
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ monitor_sdata = sdata;
+ else
+ monitor_sdata = wiphy_dereference(local->hw.wiphy,
+ local->monitor_sdata);
if (!monitor_sdata &&
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
@@ -114,7 +117,9 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
/* apply all changes now - no failures allowed */
- if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
+ if (monitor_sdata &&
+ (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
if (params->flags) {
@@ -138,7 +143,7 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
}
static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
- struct cfg80211_mbssid_config params,
+ struct cfg80211_mbssid_config *params,
struct ieee80211_bss_conf *link_conf)
{
struct ieee80211_sub_if_data *tx_sdata;
@@ -149,10 +154,10 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
link_conf->ema_ap = false;
link_conf->bssid_indicator = 0;
- if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev)
+ if (sdata->vif.type != NL80211_IFTYPE_AP || !params->tx_wdev)
return -EINVAL;
- tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev);
+ tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params->tx_wdev);
if (!tx_sdata)
return -EINVAL;
@@ -161,9 +166,9 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
} else {
sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
link_conf->nontransmitted = true;
- link_conf->bssid_index = params.index;
+ link_conf->bssid_index = params->index;
}
- if (params.ema)
+ if (params->ema)
link_conf->ema_ap = true;
return 0;
@@ -194,6 +199,24 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
}
}
+ /* Let the driver know that an interface is going to be added.
+ * Indicate so only for interface types that will be added to the
+ * driver.
+ */
+ switch (type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
+ !(params->flags & MONITOR_FLAG_ACTIVE))
+ break;
+ fallthrough;
+ default:
+ drv_prep_add_interface(local,
+ ieee80211_vif_type_p2p(&sdata->vif));
+ break;
+ }
+
return wdev;
}
@@ -879,6 +902,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -888,22 +912,25 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
lockdep_assert_wiphy(local->hw.wiphy);
- if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
- &chanreq.oper))
- return 0;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
+ if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
+ &chanreq.oper))
+ return 0;
- sdata = wiphy_dereference(local->hw.wiphy,
- local->monitor_sdata);
- if (!sdata)
- goto done;
+ sdata = wiphy_dereference(wiphy, local->monitor_sdata);
+ if (!sdata)
+ goto done;
+ }
- if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
+ if (rcu_access_pointer(sdata->deflink.conf->chanctx_conf) &&
+ cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
&chanreq.oper))
return 0;
ieee80211_link_release_channel(&sdata->deflink);
ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
- IEEE80211_CHANCTX_EXCLUSIVE);
+ IEEE80211_CHANCTX_SHARED);
if (ret)
return ret;
done:
@@ -1294,9 +1321,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
return -EALREADY;
- if (params->smps_mode != NL80211_SMPS_OFF)
- return -EOPNOTSUPP;
-
link->smps_mode = IEEE80211_SMPS_OFF;
link->needed_rx_chains = sdata->local->rx_chains;
@@ -1390,7 +1414,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (sdata->vif.type == NL80211_IFTYPE_AP &&
params->mbssid_config.tx_wdev) {
err = ieee80211_set_ap_mbssid_options(sdata,
- params->mbssid_config,
+ &params->mbssid_config,
link_conf);
if (err)
return err;
@@ -1705,7 +1729,7 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
* before drv_sta_state() is called.
*/
if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
- rate_control_rate_init(sta);
+ rate_control_rate_init_all_links(sta);
ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
if (ret)
@@ -2134,7 +2158,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
*/
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
test_sta_flag(sta, WLAN_STA_ASSOC))
- rate_control_rate_init(sta);
+ rate_control_rate_init_all_links(sta);
return sta_info_insert(sta);
}
@@ -3046,13 +3070,31 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting txp_type = type;
bool update_txp_type = false;
bool has_monitor = false;
+ int user_power_level;
+ int old_power = local->user_power_level;
lockdep_assert_wiphy(local->hw.wiphy);
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ txp_type = NL80211_TX_POWER_LIMITED;
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ case NL80211_TX_POWER_FIXED:
+ if (mbm < 0 || (mbm % 100))
+ return -EOPNOTSUPP;
+ user_power_level = MBM_TO_DBM(mbm);
+ break;
+ default:
+ return -EINVAL;
+ }
+
if (wdev) {
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
return -EOPNOTSUPP;
@@ -3062,57 +3104,67 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
- switch (type) {
- case NL80211_TX_POWER_AUTOMATIC:
- sdata->deflink.user_power_level =
- IEEE80211_UNSET_POWER_LEVEL;
- txp_type = NL80211_TX_POWER_LIMITED;
- break;
- case NL80211_TX_POWER_LIMITED:
- case NL80211_TX_POWER_FIXED:
- if (mbm < 0 || (mbm % 100))
- return -EOPNOTSUPP;
- sdata->deflink.user_power_level = MBM_TO_DBM(mbm);
- break;
- }
+ for (int link_id = 0;
+ link_id < ARRAY_SIZE(sdata->link);
+ link_id++) {
+ struct ieee80211_link_data *link =
+ wiphy_dereference(wiphy, sdata->link[link_id]);
- if (txp_type != sdata->vif.bss_conf.txpower_type) {
- update_txp_type = true;
- sdata->vif.bss_conf.txpower_type = txp_type;
- }
+ if (!link)
+ continue;
- ieee80211_recalc_txpower(sdata, update_txp_type);
+ link->user_power_level = user_power_level;
+ if (txp_type != link->conf->txpower_type) {
+ update_txp_type = true;
+ link->conf->txpower_type = txp_type;
+ }
+
+ ieee80211_recalc_txpower(link, update_txp_type);
+ }
return 0;
}
- switch (type) {
- case NL80211_TX_POWER_AUTOMATIC:
- local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
- txp_type = NL80211_TX_POWER_LIMITED;
- break;
- case NL80211_TX_POWER_LIMITED:
- case NL80211_TX_POWER_FIXED:
- if (mbm < 0 || (mbm % 100))
- return -EOPNOTSUPP;
- local->user_power_level = MBM_TO_DBM(mbm);
- break;
- }
+ local->user_power_level = user_power_level;
list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
has_monitor = true;
continue;
}
- sdata->deflink.user_power_level = local->user_power_level;
- if (txp_type != sdata->vif.bss_conf.txpower_type)
- update_txp_type = true;
- sdata->vif.bss_conf.txpower_type = txp_type;
+
+ for (int link_id = 0;
+ link_id < ARRAY_SIZE(sdata->link);
+ link_id++) {
+ struct ieee80211_link_data *link =
+ wiphy_dereference(wiphy, sdata->link[link_id]);
+
+ if (!link)
+ continue;
+
+ link->user_power_level = local->user_power_level;
+ if (txp_type != link->conf->txpower_type)
+ update_txp_type = true;
+ link->conf->txpower_type = txp_type;
+ }
}
list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
continue;
- ieee80211_recalc_txpower(sdata, update_txp_type);
+
+ for (int link_id = 0;
+ link_id < ARRAY_SIZE(sdata->link);
+ link_id++) {
+ struct ieee80211_link_data *link =
+ wiphy_dereference(wiphy, sdata->link[link_id]);
+
+ if (!link)
+ continue;
+
+ ieee80211_recalc_txpower(link, update_txp_type);
+ }
}
if (has_monitor) {
@@ -3124,10 +3176,15 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
update_txp_type = true;
sdata->vif.bss_conf.txpower_type = txp_type;
- ieee80211_recalc_txpower(sdata, update_txp_type);
+ ieee80211_recalc_txpower(&sdata->deflink,
+ update_txp_type);
}
}
+ if (local->emulate_chanctx &&
+ (old_power != local->user_power_level))
+ ieee80211_hw_conf_chan(local);
+
return 0;
}
@@ -3138,7 +3195,8 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- if (local->ops->get_txpower)
+ if (local->ops->get_txpower &&
+ (sdata->flags & IEEE80211_SDATA_IN_DRIVER))
return drv_get_txpower(local, sdata, dbm);
if (local->emulate_chanctx)
@@ -4301,7 +4359,8 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
if (chanctx_conf) {
*chandef = link->conf->chanreq.oper;
ret = 0;
- } else if (local->open_count > 0 &&
+ } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
+ local->open_count > 0 &&
local->open_count == local->monitors &&
sdata->vif.type == NL80211_IFTYPE_MONITOR) {
*chandef = local->monitor_chanreq.oper;
@@ -4826,12 +4885,12 @@ void ieee80211_color_change_finalize_work(struct wiphy *wiphy,
ieee80211_color_change_finalize(link);
}
-void ieee80211_color_collision_detection_work(struct work_struct *work)
+void ieee80211_color_collision_detection_work(struct wiphy *wiphy,
+ struct wiphy_work *work)
{
- struct delayed_work *delayed_work = to_delayed_work(work);
struct ieee80211_link_data *link =
- container_of(delayed_work, struct ieee80211_link_data,
- color_collision_detect_work);
+ container_of(work, struct ieee80211_link_data,
+ color_collision_detect_work.work);
struct ieee80211_sub_if_data *sdata = link->sdata;
cfg80211_obss_color_collision_notify(sdata->dev, link->color_bitmap,
@@ -4884,7 +4943,8 @@ ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
return;
}
- if (delayed_work_pending(&link->color_collision_detect_work)) {
+ if (wiphy_delayed_work_pending(sdata->local->hw.wiphy,
+ &link->color_collision_detect_work)) {
rcu_read_unlock();
return;
}
@@ -4893,9 +4953,9 @@ ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
/* queue the color collision detection event every 500 ms in order to
* avoid sending too much netlink messages to userspace.
*/
- ieee80211_queue_delayed_work(&sdata->local->hw,
- &link->color_collision_detect_work,
- msecs_to_jiffies(500));
+ wiphy_delayed_work_queue(sdata->local->hw.wiphy,
+ &link->color_collision_detect_work,
+ msecs_to_jiffies(500));
rcu_read_unlock();
}
@@ -5023,6 +5083,13 @@ ieee80211_add_link_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
+ if (test_sta_flag(sta, WLAN_STA_ASSOC)) {
+ struct link_sta_info *link_sta;
+
+ link_sta = sdata_dereference(sta->link[params->link_id], sdata);
+ rate_control_rate_init(link_sta);
+ }
+
/* ieee80211_sta_activate_link frees the link upon failure */
return ieee80211_sta_activate_link(sta, params->link_id);
}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index cca6d14084d2..a442cb667520 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -323,22 +323,34 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
continue;
switch (link->sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
- width = ieee80211_get_max_required_bw(link);
- break;
case NL80211_IFTYPE_STATION:
+ if (!link->sdata->vif.cfg.assoc) {
+ /*
+ * The AP's sta->bandwidth may not yet be set
+ * at this point (pre-association), so simply
+ * take the width from the chandef. We cannot
+ * have TDLS peers yet (only after association).
+ */
+ width = link->conf->chanreq.oper.width;
+ break;
+ }
/*
- * The ap's sta->bandwidth is not set yet at this
- * point, so take the width from the chandef, but
- * account also for TDLS peers
+ * otherwise just use min_def like in AP, depending on what
+ * we currently think the AP STA (and possibly TDLS peers)
+ * require(s)
*/
- width = max(link->conf->chanreq.oper.width,
- ieee80211_get_max_required_bw(link));
+ fallthrough;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ width = ieee80211_get_max_required_bw(link);
break;
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_NAN:
continue;
+ case NL80211_IFTYPE_MONITOR:
+ WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
+ NO_VIRTUAL_MONITOR));
+ fallthrough;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
@@ -347,7 +359,6 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
- case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
WARN_ON_ONCE(1);
@@ -409,7 +420,7 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
if (!ctx->driver_present)
return 0;
- return IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;
+ return IEEE80211_CHANCTX_CHANGE_MIN_DEF;
}
static void ieee80211_chan_bw_change(struct ieee80211_local *local,
@@ -462,12 +473,12 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
continue;
/* vif changed to narrow BW and narrow BW for station wasn't
- * requested or vise versa */
+ * requested or vice versa */
if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
continue;
link_sta->pub->bandwidth = new_sta_bw;
- rate_control_rate_update(local, sband, sta, link_id,
+ rate_control_rate_update(local, sband, link_sta,
IEEE80211_RC_BW_CHANGED);
}
}
@@ -905,7 +916,7 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
- ieee80211_recalc_txpower(sdata, false);
+ ieee80211_recalc_txpower(link, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
}
@@ -956,6 +967,10 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
if (!link->sdata->u.mgd.associated)
continue;
break;
+ case NL80211_IFTYPE_MONITOR:
+ if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ continue;
+ break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
@@ -968,6 +983,11 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
continue;
+ if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ rx_chains_dynamic = rx_chains_static = local->rx_chains;
+ break;
+ }
+
switch (link->smps_mode) {
default:
WARN_ONCE(1, "Invalid SMPS mode %d\n",
@@ -1118,7 +1138,7 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
*
* Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
* link2 from ctx1 request new different chandefs starting 2
- * in-place reserations with ctx4 and ctx5 replacing ctx1 and
+ * in-place reservations with ctx4 and ctx5 replacing ctx1 and
* ctx2 respectively. Next link5 and link6 from ctx3 reserve
* ctx4. If link3 and link4 remain on ctx2 as they are then this
* fails unless `replace_ctx` from ctx5 is replaced with ctx3.
@@ -1169,7 +1189,7 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
static bool
ieee80211_find_available_radio(struct ieee80211_local *local,
const struct ieee80211_chan_req *chanreq,
- int *radio_idx)
+ u32 radio_mask, int *radio_idx)
{
struct wiphy *wiphy = local->hw.wiphy;
const struct wiphy_radio *radio;
@@ -1180,6 +1200,9 @@ ieee80211_find_available_radio(struct ieee80211_local *local,
return true;
for (i = 0; i < wiphy->n_radio; i++) {
+ if (!(radio_mask & BIT(i)))
+ continue;
+
radio = &wiphy->radio[i];
if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
continue;
@@ -1213,7 +1236,9 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
if (!new_ctx) {
if (ieee80211_can_create_new_chanctx(local, -1) &&
- ieee80211_find_available_radio(local, chanreq, &radio_idx))
+ ieee80211_find_available_radio(local, chanreq,
+ sdata->wdev.radio_mask,
+ &radio_idx))
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
false, radio_idx);
else
@@ -1712,7 +1737,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
link,
changed);
- ieee80211_recalc_txpower(sdata, false);
+ ieee80211_recalc_txpower(link, false);
}
ieee80211_recalc_chanctx_chantype(local, ctx);
@@ -1883,7 +1908,9 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
/* Note: context is now reserved */
if (ctx)
reserved = true;
- else if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
+ else if (!ieee80211_find_available_radio(local, chanreq,
+ sdata->wdev.radio_mask,
+ &radio_idx))
ctx = ERR_PTR(-EBUSY);
else
ctx = ieee80211_new_chanctx(local, chanreq, mode,
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 02b5476a4376..be2e486907f9 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -42,9 +42,8 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
}
#define DEBUGFS_READONLY_FILE_OPS(name) \
-static const struct file_operations name## _ops = { \
+static const struct debugfs_short_fops name## _ops = { \
.read = name## _read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
};
@@ -142,10 +141,9 @@ static ssize_t aqm_write(struct file *file,
return -EINVAL;
}
-static const struct file_operations aqm_ops = {
+static const struct debugfs_short_fops aqm_ops = {
.write = aqm_write,
.read = aqm_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -194,10 +192,9 @@ static ssize_t airtime_flags_write(struct file *file,
return count;
}
-static const struct file_operations airtime_flags_ops = {
+static const struct debugfs_short_fops airtime_flags_ops = {
.write = airtime_flags_write,
.read = airtime_flags_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -225,9 +222,8 @@ static ssize_t aql_pending_read(struct file *file,
buf, len);
}
-static const struct file_operations aql_pending_ops = {
+static const struct debugfs_short_fops aql_pending_ops = {
.read = aql_pending_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -305,10 +301,9 @@ static ssize_t aql_txq_limit_write(struct file *file,
return count;
}
-static const struct file_operations aql_txq_limit_ops = {
+static const struct debugfs_short_fops aql_txq_limit_ops = {
.write = aql_txq_limit_write,
.read = aql_txq_limit_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -355,10 +350,9 @@ static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
return count;
}
-static const struct file_operations aql_enable_ops = {
+static const struct debugfs_short_fops aql_enable_ops = {
.write = aql_enable_write,
.read = aql_enable_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -406,10 +400,9 @@ static ssize_t force_tx_status_write(struct file *file,
return count;
}
-static const struct file_operations force_tx_status_ops = {
+static const struct debugfs_short_fops force_tx_status_ops = {
.write = force_tx_status_write,
.read = force_tx_status_read,
- .open = simple_open,
.llseek = default_llseek,
};
@@ -434,9 +427,8 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
return count;
}
-static const struct file_operations reset_ops = {
+static const struct debugfs_short_fops reset_ops = {
.write = reset_write,
- .open = simple_open,
.llseek = noop_llseek,
};
#endif
@@ -456,6 +448,7 @@ static const char *hw_flag_names[] = {
FLAG(SUPPORTS_DYNAMIC_PS),
FLAG(MFP_CAPABLE),
FLAG(WANT_MONITOR_VIF),
+ FLAG(NO_VIRTUAL_MONITOR),
FLAG(NO_AUTO_VIF),
FLAG(SW_CRYPTO_CONTROL),
FLAG(SUPPORT_FAST_XMIT),
@@ -623,9 +616,8 @@ static ssize_t stats_ ##name## _read(struct file *file, \
print_devstats_##name); \
} \
\
-static const struct file_operations stats_ ##name## _ops = { \
+static const struct debugfs_short_fops stats_ ##name## _ops = { \
.read = stats_ ##name## _read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
};
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 7e54da508765..b3a64edea0f2 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -26,17 +26,15 @@ static ssize_t key_##name##_read(struct file *file, \
#define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n")
#define KEY_OPS(name) \
-static const struct file_operations key_ ##name## _ops = { \
+static const struct debugfs_short_fops key_ ##name## _ops = { \
.read = key_##name##_read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
#define KEY_OPS_W(name) \
-static const struct file_operations key_ ##name## _ops = { \
+static const struct debugfs_short_fops key_ ##name## _ops = { \
.read = key_##name##_read, \
.write = key_##name##_write, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
@@ -49,9 +47,8 @@ static const struct file_operations key_ ##name## _ops = { \
#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
#define KEY_CONF_OPS(name) \
-static const struct file_operations key_ ##name## _ops = { \
+static const struct debugfs_short_fops key_ ##name## _ops = { \
.read = key_conf_##name##_read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 68596ef78b15..a9bc2fd59f55 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -221,10 +221,9 @@ static ssize_t ieee80211_if_fmt_##name( \
}
#define _IEEE80211_IF_FILE_OPS(name, _read, _write) \
-static const struct file_operations name##_ops = { \
+static const struct debugfs_short_fops name##_ops = { \
.read = (_read), \
.write = (_write), \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 1e9389c49a57..a67a9d316008 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -30,17 +30,15 @@ static ssize_t sta_ ##name## _read(struct file *file, \
#define STA_READ_D(name, field) STA_READ(name, field, "%d\n")
#define STA_OPS(name) \
-static const struct file_operations sta_ ##name## _ops = { \
+static const struct debugfs_short_fops sta_ ##name## _ops = { \
.read = sta_##name##_read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
#define STA_OPS_RW(name) \
-static const struct file_operations sta_ ##name## _ops = { \
+static const struct debugfs_short_fops sta_ ##name## _ops = { \
.read = sta_##name##_read, \
.write = sta_##name##_write, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
@@ -450,9 +448,8 @@ STA_OPS_RW(agg_status);
/* link sta attributes */
#define LINK_STA_OPS(name) \
-static const struct file_operations link_sta_ ##name## _ops = { \
+static const struct debugfs_short_fops link_sta_ ##name## _ops = { \
.read = link_sta_##name##_read, \
- .open = simple_open, \
.llseek = generic_file_llseek, \
}
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index fe868b521622..299d38e9e863 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -65,6 +65,7 @@ int drv_add_interface(struct ieee80211_local *local,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
return -EINVAL;
@@ -181,9 +182,10 @@ int drv_sta_set_txpwr(struct ieee80211_local *local,
return ret;
}
-void drv_sta_rc_update(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta, u32 changed)
+void drv_link_sta_rc_update(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_sta *link_sta,
+ u32 changed)
{
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
@@ -193,10 +195,10 @@ void drv_sta_rc_update(struct ieee80211_local *local,
(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
- trace_drv_sta_rc_update(local, sdata, sta, changed);
- if (local->ops->sta_rc_update)
- local->ops->sta_rc_update(&local->hw, &sdata->vif,
- sta, changed);
+ trace_drv_link_sta_rc_update(local, sdata, link_sta, changed);
+ if (local->ops->link_sta_rc_update)
+ local->ops->link_sta_rc_update(&local->hw, &sdata->vif,
+ link_sta, changed);
trace_drv_return_void(local);
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d382d9729e85..edd1e4d4ad9d 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -594,9 +594,9 @@ int drv_sta_set_txpwr(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta);
-void drv_sta_rc_update(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta, u32 changed);
+void drv_link_sta_rc_update(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_link_sta *link_sta, u32 changed);
static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
@@ -1728,4 +1728,16 @@ drv_can_neg_ttlm(struct ieee80211_local *local,
return res;
}
+
+static inline void
+drv_prep_add_interface(struct ieee80211_local *local,
+ enum nl80211_iftype type)
+{
+ trace_drv_prep_add_interface(local, type);
+ if (local->ops->prep_add_interface)
+ local->ops->prep_add_interface(&local->hw, type);
+
+ trace_drv_return_void(local);
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index ddc7acc68335..7a3116c36df9 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -2,7 +2,7 @@
/*
* EHT handling
*
- * Copyright(c) 2021-2023 Intel Corporation
+ * Copyright(c) 2021-2024 Intel Corporation
*/
#include "ieee80211_i.h"
@@ -75,4 +75,23 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
+
+ switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0],
+ IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) {
+ case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454:
+ link_sta->pub->agg.max_amsdu_len =
+ IEEE80211_MAX_MPDU_LEN_VHT_11454;
+ break;
+ case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991:
+ link_sta->pub->agg.max_amsdu_len =
+ IEEE80211_MAX_MPDU_LEN_VHT_7991;
+ break;
+ case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895:
+ default:
+ link_sta->pub->agg.max_amsdu_len =
+ IEEE80211_MAX_MPDU_LEN_VHT_3895;
+ break;
+ }
+
+ ieee80211_sta_recalc_aggregates(&link_sta->sta->sta);
}
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 1c2b7dd8976a..32390d8a9d75 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -379,7 +379,7 @@ void ieee80211_ba_session_work(struct wiphy *wiphy, struct wiphy_work *work)
sta->ampdu_mlme.tid_rx_manage_offl))
__ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
IEEE80211_MAX_AMPDU_BUF_HT,
- false, true, NULL);
+ false, true, 0);
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
sta->ampdu_mlme.tid_rx_manage_offl))
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3f74bbceeca5..a1b4178deccf 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -569,7 +569,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
if (!sta->sdata->u.ibss.control_port)
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
- rate_control_rate_init(sta);
+ rate_control_rate_init(&sta->deflink);
/* If it fails, maybe we raced another insertion? */
if (sta_info_insert_rcu(sta))
@@ -1068,11 +1068,12 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
/* Force rx_nss recalculation */
sta->sta.deflink.rx_nss = 0;
- rate_control_rate_init(sta);
+ rate_control_rate_init(&sta->deflink);
if (sta->sta.deflink.rx_nss != rx_nss)
changed |= IEEE80211_RC_NSS_CHANGED;
- drv_sta_rc_update(local, sdata, &sta->sta, changed);
+ drv_link_sta_rc_update(local, sdata, &sta->sta.deflink,
+ changed);
}
rcu_read_unlock();
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4f0390918b60..a00096dd787b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -892,9 +892,10 @@ struct ieee80211_chanctx {
/* temporary data for search algorithm etc. */
struct ieee80211_chan_req req;
- struct ieee80211_chanctx_conf conf;
-
bool radar_detected;
+
+ /* MUST be last - ends in a flexible-array member. */
+ struct ieee80211_chanctx_conf conf;
};
struct mac80211_qos_map {
@@ -1015,8 +1016,6 @@ struct ieee80211_link_data_managed {
int wmm_last_param_set;
int mu_edca_last_param_set;
-
- u8 bss_param_ch_cnt;
};
struct ieee80211_link_data_ap {
@@ -1053,7 +1052,7 @@ struct ieee80211_link_data {
} csa;
struct wiphy_work color_change_finalize_work;
- struct delayed_work color_collision_detect_work;
+ struct wiphy_delayed_work color_collision_detect_work;
u64 color_bitmap;
/* context reservation -- protected with wiphy mutex */
@@ -1370,7 +1369,7 @@ struct ieee80211_local {
spinlock_t queue_stop_reason_lock;
int open_count;
- int monitors, cooked_mntrs;
+ int monitors, cooked_mntrs, tx_mntrs;
/* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
fif_probe_req;
@@ -2005,7 +2004,8 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
/* color change handling */
void ieee80211_color_change_finalize_work(struct wiphy *wiphy,
struct wiphy_work *work);
-void ieee80211_color_collision_detection_work(struct work_struct *work);
+void ieee80211_color_collision_detection_work(struct wiphy *wiphy,
+ struct wiphy_work *work);
/* interface handling */
#define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
@@ -2035,8 +2035,8 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
-bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
-void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
+bool __ieee80211_recalc_txpower(struct ieee80211_link_data *link);
+void ieee80211_recalc_txpower(struct ieee80211_link_data *link,
bool update_bss);
void ieee80211_recalc_offload(struct ieee80211_local *local);
@@ -2113,14 +2113,19 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, int link_id);
bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
enum ieee80211_smps_mode smps_mode_new);
-
+void ieee80211_add_addbaext(struct sk_buff *skb,
+ const u8 req_addba_ext_data,
+ u16 buf_size);
+u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
+ const void *elem_data, ssize_t elem_len,
+ u16 *buf_size);
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason, bool stop);
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
u8 dialog_token, u16 timeout,
u16 start_seq_num, u16 ba_policy, u16 tid,
u16 buf_size, bool tx, bool auto_seq,
- const struct ieee80211_addba_ext_ie *addbaext);
+ const u8 addba_ext_data);
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
enum ieee80211_agg_stop_reason reason);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
@@ -2196,8 +2201,6 @@ ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta)
return _ieee80211_sta_cur_vht_bw(link_sta, NULL);
}
void ieee80211_sta_init_nss(struct link_sta_info *link_sta);
-enum ieee80211_sta_rx_bandwidth
-ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width);
enum nl80211_chan_width
ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta);
void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
@@ -2452,7 +2455,7 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
/*
* If quiescing is set, we are racing with __ieee80211_suspend.
* __ieee80211_suspend flushes the workers after setting quiescing,
- * and we check quiescing / suspended before enqueing new workers.
+ * and we check quiescing / suspended before enqueuing new workers.
* We should abort the worker to avoid the races below.
*/
if (local->quiescing)
@@ -2545,8 +2548,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
const struct cfg80211_chan_def *chandef);
u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata);
-u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef);
-u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef,
+u8 *ieee80211_ie_build_he_oper(u8 *pos, const struct cfg80211_chan_def *chandef);
+u8 *ieee80211_ie_build_eht_oper(u8 *pos, const struct cfg80211_chan_def *chandef,
const struct ieee80211_sta_eht_cap *eht_cap);
int ieee80211_parse_bitrates(enum nl80211_chan_width width,
const struct ieee80211_supported_band *sband,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 6ef0990d3d29..a8fbedd530f4 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -44,13 +44,13 @@
static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work);
-bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
+bool __ieee80211_recalc_txpower(struct ieee80211_link_data *link)
{
struct ieee80211_chanctx_conf *chanctx_conf;
int power;
rcu_read_lock();
- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
+ chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return false;
@@ -59,27 +59,26 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
power = ieee80211_chandef_max_power(&chanctx_conf->def);
rcu_read_unlock();
- if (sdata->deflink.user_power_level != IEEE80211_UNSET_POWER_LEVEL)
- power = min(power, sdata->deflink.user_power_level);
+ if (link->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
+ power = min(power, link->user_power_level);
- if (sdata->deflink.ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
- power = min(power, sdata->deflink.ap_power_level);
+ if (link->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
+ power = min(power, link->ap_power_level);
- if (power != sdata->vif.bss_conf.txpower) {
- sdata->vif.bss_conf.txpower = power;
- ieee80211_hw_config(sdata->local, 0);
+ if (power != link->conf->txpower) {
+ link->conf->txpower = power;
return true;
}
return false;
}
-void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
+void ieee80211_recalc_txpower(struct ieee80211_link_data *link,
bool update_bss)
{
- if (__ieee80211_recalc_txpower(sdata) ||
- (update_bss && ieee80211_sdata_running(sdata)))
- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
+ if (__ieee80211_recalc_txpower(link) ||
+ (update_bss && ieee80211_sdata_running(link->sdata)))
+ ieee80211_link_info_change_notify(link->sdata, link,
BSS_CHANGED_TXPOWER);
}
@@ -279,8 +278,13 @@ static int _ieee80211_change_mac(struct ieee80211_sub_if_data *sdata,
ret = eth_mac_addr(sdata->dev, sa);
if (ret == 0) {
- memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
- ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
+ if (check_dup) {
+ memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
+ ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
+ } else {
+ memset(sdata->vif.addr, 0, ETH_ALEN);
+ memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
+ }
}
/* Regardless of eth_mac_addr() return we still want to add the
@@ -699,9 +703,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
ieee80211_recalc_idle(local);
ieee80211_recalc_offload(local);
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
break;
+ ieee80211_link_release_channel(&sdata->deflink);
fallthrough;
default:
if (!going_down)
@@ -1087,6 +1093,8 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
ADJUST(CONTROL, control);
ADJUST(CONTROL, pspoll);
ADJUST(OTHER_BSS, other_bss);
+ if (!(flags & MONITOR_FLAG_SKIP_TX))
+ local->tx_mntrs += offset;
#undef ADJUST
}
@@ -1131,7 +1139,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
ASSERT_RTNL();
lockdep_assert_wiphy(local->hw.wiphy);
- if (local->monitor_sdata)
+ if (local->monitor_sdata ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
return 0;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
@@ -1193,6 +1202,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ return;
+
ASSERT_RTNL();
lockdep_assert_wiphy(local->hw.wiphy);
@@ -1328,7 +1340,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
break;
}
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
@@ -2176,9 +2189,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ieee80211_set_default_queues(sdata);
- sdata->deflink.ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
- sdata->deflink.user_power_level = local->user_power_level;
-
/* setup type-dependent data */
ieee80211_setup_sdata(sdata, type);
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 6fac3ba00d88..67ecfea22982 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -987,6 +987,26 @@ void ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata)
}
}
+static void
+ieee80211_key_iter(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key *key,
+ void (*iter)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *data),
+ void *iter_data)
+{
+ /* skip keys of station in removal process */
+ if (key->sta && key->sta->removed)
+ return;
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ return;
+ iter(hw, vif, key->sta ? &key->sta->sta : NULL,
+ &key->conf, iter_data);
+}
+
void ieee80211_iter_keys(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
void (*iter)(struct ieee80211_hw *hw,
@@ -1005,16 +1025,13 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
if (vif) {
sdata = vif_to_sdata(vif);
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
- iter(hw, &sdata->vif,
- key->sta ? &key->sta->sta : NULL,
- &key->conf, iter_data);
+ ieee80211_key_iter(hw, vif, key, iter, iter_data);
} else {
list_for_each_entry(sdata, &local->interfaces, list)
list_for_each_entry_safe(key, tmp,
&sdata->key_list, list)
- iter(hw, &sdata->vif,
- key->sta ? &key->sta->sta : NULL,
- &key->conf, iter_data);
+ ieee80211_key_iter(hw, &sdata->vif, key,
+ iter, iter_data);
}
}
EXPORT_SYMBOL(ieee80211_iter_keys);
@@ -1031,17 +1048,8 @@ _ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
{
struct ieee80211_key *key;
- list_for_each_entry_rcu(key, &sdata->key_list, list) {
- /* skip keys of station in removal process */
- if (key->sta && key->sta->removed)
- continue;
- if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- continue;
-
- iter(hw, &sdata->vif,
- key->sta ? &key->sta->sta : NULL,
- &key->conf, iter_data);
- }
+ list_for_each_entry_rcu(key, &sdata->key_list, list)
+ ieee80211_key_iter(hw, &sdata->vif, key, iter, iter_data);
}
void ieee80211_iter_keys_rcu(struct ieee80211_hw *hw,
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 0bbac64d5fa0..58a76bcd6ae6 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -36,13 +36,16 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
link->conf = link_conf;
link_conf->link_id = link_id;
link_conf->vif = &sdata->vif;
+ link->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
+ link->user_power_level = sdata->local->user_power_level;
+ link_conf->txpower = INT_MIN;
wiphy_work_init(&link->csa.finalize_work,
ieee80211_csa_finalize_work);
wiphy_work_init(&link->color_change_finalize_work,
ieee80211_color_change_finalize_work);
- INIT_DELAYED_WORK(&link->color_collision_detect_work,
- ieee80211_color_collision_detection_work);
+ wiphy_delayed_work_init(&link->color_collision_detect_work,
+ ieee80211_color_collision_detection_work);
INIT_LIST_HEAD(&link->assigned_chanctx_list);
INIT_LIST_HEAD(&link->reserved_chanctx_list);
wiphy_delayed_work_init(&link->dfs_cac_timer_work,
@@ -72,7 +75,8 @@ void ieee80211_link_stop(struct ieee80211_link_data *link)
if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_mgd_stop_link(link);
- cancel_delayed_work_sync(&link->color_collision_detect_work);
+ wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy,
+ &link->color_collision_detect_work);
wiphy_work_cancel(link->sdata->local->hw.wiphy,
&link->color_change_finalize_work);
wiphy_work_cancel(link->sdata->local->hw.wiphy,
@@ -385,6 +389,37 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
jiffies);
}
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct ieee80211_link_data *link;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+
+ /*
+ * This call really should not fail. Unfortunately, it appears
+ * that this may happen occasionally with some drivers. Should
+ * it happen, we are stuck in a bad place as going backwards is
+ * not really feasible.
+ *
+ * So lets just tell link_use_channel that it must not fail to
+ * assign the channel context (from mac80211's perspective) and
+ * assume the driver is going to trigger a recovery flow if it
+ * had a failure.
+ * That really is not great nor guaranteed to work. But at least
+ * the internal mac80211 state remains consistent and there is
+ * a chance that we can recover.
+ */
+ ret = _ieee80211_link_use_channel(link,
+ &link->conf->chanreq,
+ IEEE80211_CHANCTX_SHARED,
+ true);
+ WARN_ON_ONCE(ret);
+
+ /*
+ * inform about the link info changed parameters after all
+ * stations are also added
+ */
+ }
+
list_for_each_entry(sta, &local->sta_list, list) {
if (sdata != sta->sdata)
continue;
@@ -428,26 +463,6 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
link = sdata_dereference(sdata->link[link_id], sdata);
- /*
- * This call really should not fail. Unfortunately, it appears
- * that this may happen occasionally with some drivers. Should
- * it happen, we are stuck in a bad place as going backwards is
- * not really feasible.
- *
- * So lets just tell link_use_channel that it must not fail to
- * assign the channel context (from mac80211's perspective) and
- * assume the driver is going to trigger a recovery flow if it
- * had a failure.
- * That really is not great nor guaranteed to work. But at least
- * the internal mac80211 state remains consistent and there is
- * a chance that we can recover.
- */
- ret = _ieee80211_link_use_channel(link,
- &link->conf->chanreq,
- IEEE80211_CHANCTX_SHARED,
- true);
- WARN_ON_ONCE(ret);
-
ieee80211_mgd_set_link_qos_params(link);
ieee80211_link_info_change_notify(sdata, link,
BSS_CHANGED_ERP_CTS_PROT |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 89084690350f..ee1211a213d7 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -167,6 +167,8 @@ static u32 ieee80211_calc_hw_conf_chan(struct ieee80211_local *local,
}
power = ieee80211_chandef_max_power(&chandef);
+ if (local->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
+ power = min(local->user_power_level, power);
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 640239f4425b..cb5f16366b9c 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1482,7 +1482,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
if (!elems)
return;
- /* ignore non-mesh or secure / unsecure mismatch */
+ /* ignore non-mesh or secure / insecure mismatch */
if ((!elems->mesh_id || !elems->mesh_config) ||
(elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
(!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 579d0f24ac9d..4e9546e998b6 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -220,12 +220,12 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
/**
* mesh_path_error_tx - Sends a PERR mesh management frame
*
+ * @sdata: local mesh subif
* @ttl: allowed remaining hops
* @target: broken destination
* @target_sn: SN of the broken destination
* @target_rcode: reason code for this PERR
* @ra: node this frame is addressed to
- * @sdata: local mesh subif
*
* Note: This function may be called with driver locks taken that the driver
* also acquires in the TX path. To avoid a deadlock we don't transmit the
@@ -1137,8 +1137,8 @@ enddiscovery:
/**
* mesh_nexthop_resolve - lookup next hop; conditionally start path discovery
*
- * @skb: 802.11 frame to be sent
* @sdata: network subif the frame will be sent through
+ * @skb: 802.11 frame to be sent
*
* Lookup next hop for given skb and start path discovery if no
* forwarding information is found.
@@ -1245,8 +1245,8 @@ void mesh_path_refresh(struct ieee80211_sub_if_data *sdata,
* this function is considered "using" the associated mpath, so preempt a path
* refresh if this mpath expires soon.
*
- * @skb: 802.11 frame to be sent
* @sdata: network subif the frame will be sent through
+ * @skb: 802.11 frame to be sent
*
* Returns: 0 if the next hop was found. Nonzero otherwise.
*/
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 30c0d89203af..9f9cb5af0a97 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -300,8 +300,8 @@ __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
/**
* mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
- * @idx: index
* @sdata: local subif, or NULL for all entries
+ * @idx: index
*
* Returns: pointer to the mesh path structure, or NULL if not found.
*
@@ -315,8 +315,8 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
/**
* mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
- * @idx: index
* @sdata: local subif, or NULL for all entries
+ * @idx: index
*
* Returns: pointer to the proxy path structure, or NULL if not found.
*
@@ -670,8 +670,8 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata,
/**
* mesh_path_add - allocate and add a new path to the mesh path table
- * @dst: destination address of the path (ETH_ALEN length)
* @sdata: local subif
+ * @dst: destination address of the path (ETH_ALEN length)
*
* Returns: 0 on success
*
@@ -916,8 +916,8 @@ static int table_path_del(struct mesh_table *tbl,
/**
* mesh_path_del - delete a mesh path from the table
*
- * @addr: dst address (ETH_ALEN length)
* @sdata: local subif
+ * @addr: dst address (ETH_ALEN length)
*
* Returns: 0 if successful
*/
@@ -996,8 +996,8 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
/**
* mesh_path_discard_frame - discard a frame whose path could not be resolved
*
- * @skb: frame to discard
* @sdata: network subif the frame was to be sent through
+ * @skb: frame to discard
*
* Locking: the function must me called within a rcu_read_lock region
*/
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 8f2b492a9fe9..6ea35c88dc48 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -486,10 +486,11 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
sta->sta.deflink.bandwidth = IEEE80211_STA_RX_BW_20;
}
+ /* FIXME: this check is wrong without SW rate control */
if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
- rate_control_rate_init(sta);
+ rate_control_rate_init(&sta->deflink);
else
- rate_control_rate_update(local, sband, sta, 0, changed);
+ rate_control_rate_update(local, sband, &sta->deflink, changed);
out:
spin_unlock_bh(&sta->mesh->plink_lock);
}
@@ -667,7 +668,7 @@ void mesh_plink_timer(struct timer_list *t)
/*
* This STA is valid because sta_info_destroy() will
* del_timer_sync() this timer after having made sure
- * it cannot be readded (by deleting the plink.)
+ * it cannot be re-added (by deleting the plink.)
*/
sta = mesh->plink_sta;
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
index 8cf3f395f52f..3a66b4cefca7 100644
--- a/net/mac80211/mesh_sync.c
+++ b/net/mac80211/mesh_sync.c
@@ -175,7 +175,7 @@ static void mesh_sync_offset_adjust_tsf(struct ieee80211_sub_if_data *sdata,
spin_lock_bh(&ifmsh->sync_offset_lock);
if (ifmsh->sync_offset_clockdrift_max > TOFFSET_MINIMUM_ADJUSTMENT) {
- /* Since ajusting the tsf here would
+ /* Since adjusting the tsf here would
* require a possibly blocking call
* to the driver tsf setter, we punt
* the tsf adjustment to the mesh tasklet
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0303972c23e4..480b664151c9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -31,6 +31,8 @@
#include "led.h"
#include "fils_aead.h"
+#include <kunit/static_stub.h>
+
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2)
#define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10)
@@ -2643,9 +2645,91 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
&ifmgd->csa_connection_drop_work);
}
+struct sta_bss_param_ch_cnt_data {
+ struct ieee80211_sub_if_data *sdata;
+ u8 reporting_link_id;
+ u8 mld_id;
+};
+
+static enum cfg80211_rnr_iter_ret
+ieee80211_sta_bss_param_ch_cnt_iter(void *_data, u8 type,
+ const struct ieee80211_neighbor_ap_info *info,
+ const u8 *tbtt_info, u8 tbtt_info_len)
+{
+ struct sta_bss_param_ch_cnt_data *data = _data;
+ struct ieee80211_sub_if_data *sdata = data->sdata;
+ const struct ieee80211_tbtt_info_ge_11 *ti;
+ u8 bss_param_ch_cnt;
+ int link_id;
+
+ if (type != IEEE80211_TBTT_INFO_TYPE_TBTT)
+ return RNR_ITER_CONTINUE;
+
+ if (tbtt_info_len < sizeof(*ti))
+ return RNR_ITER_CONTINUE;
+
+ ti = (const void *)tbtt_info;
+
+ if (ti->mld_params.mld_id != data->mld_id)
+ return RNR_ITER_CONTINUE;
+
+ link_id = le16_get_bits(ti->mld_params.params,
+ IEEE80211_RNR_MLD_PARAMS_LINK_ID);
+ bss_param_ch_cnt =
+ le16_get_bits(ti->mld_params.params,
+ IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT);
+
+ if (bss_param_ch_cnt != 255 &&
+ link_id < ARRAY_SIZE(sdata->link)) {
+ struct ieee80211_link_data *link =
+ sdata_dereference(sdata->link[link_id], sdata);
+
+ if (link && link->conf->bss_param_ch_cnt != bss_param_ch_cnt) {
+ link->conf->bss_param_ch_cnt = bss_param_ch_cnt;
+ link->conf->bss_param_ch_cnt_link_id =
+ data->reporting_link_id;
+ }
+ }
+
+ return RNR_ITER_CONTINUE;
+}
+
+static void
+ieee80211_mgd_update_bss_param_ch_cnt(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *bss_conf,
+ struct ieee802_11_elems *elems)
+{
+ struct sta_bss_param_ch_cnt_data data = {
+ .reporting_link_id = bss_conf->link_id,
+ .sdata = sdata,
+ };
+ int bss_param_ch_cnt;
+
+ if (!elems->ml_basic)
+ return;
+
+ data.mld_id = ieee80211_mle_get_mld_id((const void *)elems->ml_basic);
+
+ cfg80211_iter_rnr(elems->ie_start, elems->total_len,
+ ieee80211_sta_bss_param_ch_cnt_iter, &data);
+
+ bss_param_ch_cnt =
+ ieee80211_mle_get_bss_param_ch_cnt((const void *)elems->ml_basic);
+
+ /*
+ * Update bss_param_ch_cnt_link_id even if bss_param_ch_cnt
+ * didn't change to indicate that we got a beacon on our own
+ * link.
+ */
+ if (bss_param_ch_cnt >= 0 && bss_param_ch_cnt != 255) {
+ bss_conf->bss_param_ch_cnt = bss_param_ch_cnt;
+ bss_conf->bss_param_ch_cnt_link_id =
+ bss_conf->link_id;
+ }
+}
+
static bool
-ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
+ieee80211_find_80211h_pwr_constr(struct ieee80211_channel *channel,
const u8 *country_ie, u8 country_ie_len,
const u8 *pwr_constr_elem,
int *chan_pwr, int *pwr_reduction)
@@ -2715,8 +2799,7 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
return have_chan_pwr;
}
-static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_channel *channel,
+static void ieee80211_find_cisco_dtpc(struct ieee80211_channel *channel,
const u8 *cisco_dtpc_ie,
int *pwr_level)
{
@@ -2750,7 +2833,7 @@ static u64 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link,
(capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) ||
capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) {
has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
- sdata, channel, country_ie, country_ie_len,
+ channel, country_ie, country_ie_len,
pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
pwr_level_80211h =
max_t(int, 0, chan_pwr - pwr_reduction_80211h);
@@ -2758,7 +2841,7 @@ static u64 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link,
if (cisco_dtpc_ie) {
ieee80211_find_cisco_dtpc(
- sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
+ channel, cisco_dtpc_ie, &pwr_level_cisco);
has_cisco_pwr = true;
}
@@ -2791,7 +2874,7 @@ static u64 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link,
}
link->ap_power_level = new_ap_level;
- if (__ieee80211_recalc_txpower(sdata))
+ if (__ieee80211_recalc_txpower(link))
return BSS_CHANGED_TXPOWER;
return 0;
}
@@ -4101,8 +4184,13 @@ EXPORT_SYMBOL(ieee80211_beacon_loss);
void ieee80211_connection_loss(struct ieee80211_vif *vif)
{
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- struct ieee80211_hw *hw = &sdata->local->hw;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw *hw;
+
+ KUNIT_STATIC_STUB_REDIRECT(ieee80211_connection_loss, vif);
+
+ sdata = vif_to_sdata(vif);
+ hw = &sdata->local->hw;
trace_api_connection_loss(sdata);
@@ -4667,7 +4755,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
ret = false;
goto out;
}
- link->u.mgd.bss_param_ch_cnt = bss_param_ch_cnt;
+ bss_conf->bss_param_ch_cnt = bss_param_ch_cnt;
+ bss_conf->bss_param_ch_cnt_link_id = link_id;
}
} else if (elems->parse_error & IEEE80211_PARSE_ERR_DUP_NEST_ML_BASIC ||
!elems->prof ||
@@ -4677,6 +4766,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
} else {
const u8 *ptr = elems->prof->variable +
elems->prof->sta_info_len - 1;
+ int bss_param_ch_cnt;
/*
* During parsing, we validated that these fields exist,
@@ -4684,8 +4774,10 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
*/
capab_info = get_unaligned_le16(ptr);
assoc_data->link[link_id].status = get_unaligned_le16(ptr + 2);
- link->u.mgd.bss_param_ch_cnt =
+ bss_param_ch_cnt =
ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(elems->prof);
+ bss_conf->bss_param_ch_cnt = bss_param_ch_cnt;
+ bss_conf->bss_param_ch_cnt_link_id = link_id;
if (assoc_data->link[link_id].status != WLAN_STATUS_SUCCESS) {
link_info(link, "association response status code=%u\n",
@@ -5665,7 +5757,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
/* links might have changed due to rejected ones, set them again */
ieee80211_vif_set_links(sdata, valid_links, dormant_links);
- rate_control_rate_init(sta);
+ rate_control_rate_init_all_links(sta);
if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
set_sta_flag(sta, WLAN_STA_MFP);
@@ -6913,6 +7005,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
/* note that after this elems->ml_basic can no longer be used fully */
ieee80211_mgd_check_cross_link_csa(sdata, rx_status->link_id, elems);
+ ieee80211_mgd_update_bss_param_ch_cnt(sdata, bss_conf, elems);
+
if (!link->u.mgd.disable_wmm_tracking &&
ieee80211_sta_wmm_params(local, link, elems->wmm_param,
elems->wmm_param_len,
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
index f4c51e4a1e29..6218abc3e441 100644
--- a/net/mac80211/ocb.c
+++ b/net/mac80211/ocb.c
@@ -4,7 +4,7 @@
*
* Copyright: (c) 2014 Czech Technical University in Prague
* (c) 2014 Volkswagen Group Research
- * Copyright (C) 2022 - 2023 Intel Corporation
+ * Copyright (C) 2022 - 2024 Intel Corporation
* Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
* Funded by: Volkswagen Group Research
*/
@@ -96,7 +96,7 @@ static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
- rate_control_rate_init(sta);
+ rate_control_rate_init(&sta->deflink);
/* If it fails, maybe we raced another insertion? */
if (sta_info_insert_rcu(sta))
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 3dc9752188d5..0d056db9f81e 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -28,8 +28,9 @@ module_param(ieee80211_default_rc_algo, charp, 0644);
MODULE_PARM_DESC(ieee80211_default_rc_algo,
"Default rate control algorithm for mac80211 to use");
-void rate_control_rate_init(struct sta_info *sta)
+void rate_control_rate_init(struct link_sta_info *link_sta)
{
+ struct sta_info *sta = link_sta->sta;
struct ieee80211_local *local = sta->sdata->local;
struct rate_control_ref *ref = sta->rate_ctrl;
struct ieee80211_sta *ista = &sta->sta;
@@ -37,11 +38,15 @@ void rate_control_rate_init(struct sta_info *sta)
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
- ieee80211_sta_init_nss(&sta->deflink);
+ ieee80211_sta_init_nss(link_sta);
if (!ref)
return;
+ /* SW rate control isn't supported with MLO right now */
+ if (WARN_ON(ieee80211_vif_is_mld(&sta->sdata->vif)))
+ return;
+
rcu_read_lock();
chanctx_conf = rcu_dereference(sta->sdata->vif.bss_conf.chanctx_conf);
@@ -67,6 +72,21 @@ void rate_control_rate_init(struct sta_info *sta)
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
}
+void rate_control_rate_init_all_links(struct sta_info *sta)
+{
+ int link_id;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) {
+ struct link_sta_info *link_sta;
+
+ link_sta = sdata_dereference(sta->link[link_id], sta->sdata);
+ if (!link_sta)
+ continue;
+
+ rate_control_rate_init(link_sta);
+ }
+}
+
void rate_control_tx_status(struct ieee80211_local *local,
struct ieee80211_tx_status *st)
{
@@ -93,16 +113,15 @@ void rate_control_tx_status(struct ieee80211_local *local,
void rate_control_rate_update(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
- struct sta_info *sta, unsigned int link_id,
+ struct link_sta_info *link_sta,
u32 changed)
{
struct rate_control_ref *ref = local->rate_ctrl;
+ struct sta_info *sta = link_sta->sta;
struct ieee80211_sta *ista = &sta->sta;
void *priv_sta = sta->rate_ctrl_priv;
struct ieee80211_chanctx_conf *chanctx_conf;
- WARN_ON(link_id != 0);
-
if (ref && ref->ops->rate_update) {
rcu_read_lock();
@@ -120,7 +139,8 @@ void rate_control_rate_update(struct ieee80211_local *local,
}
if (sta->uploaded)
- drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
+ drv_link_sta_rc_update(local, sta->sdata, link_sta->pub,
+ changed);
}
int ieee80211_rate_control_register(const struct rate_control_ops *ops)
@@ -229,9 +249,8 @@ static ssize_t rcname_read(struct file *file, char __user *userbuf,
ref->ops->name, len);
}
-const struct file_operations rcname_ops = {
+const struct debugfs_short_fops rcname_ops = {
.read = rcname_read,
- .open = simple_open,
.llseek = default_llseek,
};
#endif
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index d6190f10fe7c..5e4bde598212 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -3,7 +3,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022, 2024 Intel Corporation
*/
#ifndef IEEE80211_RATE_H
@@ -29,11 +29,11 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
void rate_control_tx_status(struct ieee80211_local *local,
struct ieee80211_tx_status *st);
-void rate_control_rate_init(struct sta_info *sta);
+void rate_control_rate_init(struct link_sta_info *link_sta);
+void rate_control_rate_init_all_links(struct sta_info *sta);
void rate_control_rate_update(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
- struct sta_info *sta,
- unsigned int link_id,
+ struct link_sta_info *link_sta,
u32 changed);
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
@@ -62,7 +62,7 @@ static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
#endif
}
-extern const struct file_operations rcname_ops;
+extern const struct debugfs_short_fops rcname_ops;
static inline void rate_control_add_debugfs(struct ieee80211_local *local)
{
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 6bf3b4444a43..706cbc99f718 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1053,7 +1053,7 @@ minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi)
* - max_prob_rate must use only one stream, as a tradeoff between delivery
* probability and throughput during strong fluctuations
* - as long as the max prob rate has a probability of more than 75%, pick
- * higher throughput rates, even if the probablity is a bit lower
+ * higher throughput rates, even if the probability is a bit lower
*/
static void
minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 694b43091fec..2bec18fc1b03 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -508,18 +508,13 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
flags |= IEEE80211_RADIOTAP_AMPDU_IS_LAST;
if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_ERROR)
flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR;
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
- flags |= IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN;
if (status->flag & RX_FLAG_AMPDU_EOF_BIT_KNOWN)
flags |= IEEE80211_RADIOTAP_AMPDU_EOF_KNOWN;
if (status->flag & RX_FLAG_AMPDU_EOF_BIT)
flags |= IEEE80211_RADIOTAP_AMPDU_EOF;
put_unaligned_le16(flags, pos);
pos += 2;
- if (status->flag & RX_FLAG_AMPDU_DELIM_CRC_KNOWN)
- *pos++ = status->ampdu_delimiter_crc;
- else
- *pos++ = 0;
+ *pos++ = 0;
*pos++ = 0;
}
@@ -767,8 +762,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
struct ieee80211_rate *rate)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
- struct ieee80211_sub_if_data *sdata;
- struct sk_buff *monskb = NULL;
+ struct ieee80211_sub_if_data *sdata, *prev_sdata = NULL;
+ struct sk_buff *skb, *monskb = NULL;
int present_fcs_len = 0;
unsigned int rtap_space = 0;
struct ieee80211_sub_if_data *monitor_sdata =
@@ -842,40 +837,52 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
- bool last_monitor = list_is_last(&sdata->u.mntr.list,
- &local->mon_list);
+ struct cfg80211_chan_def *chandef;
+
+ chandef = &sdata->vif.bss_conf.chanreq.oper;
+ if (chandef->chan &&
+ chandef->chan->center_freq != status->freq)
+ continue;
+
+ if (!prev_sdata) {
+ prev_sdata = sdata;
+ continue;
+ }
+
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
if (!monskb)
monskb = ieee80211_make_monitor_skb(local, &origskb,
rate, rtap_space,
- only_monitor &&
- last_monitor);
+ false);
+ if (!monskb)
+ continue;
- if (monskb) {
- struct sk_buff *skb;
+ skb = skb_clone(monskb, GFP_ATOMIC);
+ if (!skb)
+ continue;
- if (last_monitor) {
- skb = monskb;
- monskb = NULL;
- } else {
- skb = skb_clone(monskb, GFP_ATOMIC);
- }
+ skb->dev = prev_sdata->dev;
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
+ netif_receive_skb(skb);
+ prev_sdata = sdata;
+ }
- if (skb) {
- skb->dev = sdata->dev;
- dev_sw_netstats_rx_add(skb->dev, skb->len);
- netif_receive_skb(skb);
- }
+ if (prev_sdata) {
+ if (monskb)
+ skb = monskb;
+ else
+ skb = ieee80211_make_monitor_skb(local, &origskb,
+ rate, rtap_space,
+ only_monitor);
+ if (skb) {
+ skb->dev = prev_sdata->dev;
+ dev_sw_netstats_rx_add(skb->dev, skb->len);
+ netif_receive_skb(skb);
}
-
- if (last_monitor)
- break;
}
- /* this happens if last_monitor was erroneously false */
- dev_kfree_skb(monskb);
-
- /* ditto */
if (!origskb)
return NULL;
@@ -3568,7 +3575,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sband = rx->local->hw.wiphy->bands[status->band];
- rate_control_rate_update(local, sband, rx->sta, 0,
+ rate_control_rate_update(local, sband, rx->link_sta,
IEEE80211_RC_SMPS_CHANGED);
cfg80211_sta_opmode_change_notify(sdata->dev,
rx->sta->addr,
@@ -3605,7 +3612,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
ieee80211_sta_rx_bw_to_chan_width(rx->link_sta);
sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED;
- rate_control_rate_update(local, sband, rx->sta, 0,
+ rate_control_rate_update(local, sband, rx->link_sta,
IEEE80211_RC_BW_CHANGED);
cfg80211_sta_opmode_change_notify(sdata->dev,
rx->sta->addr,
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index adb88c06b598..cb7079071885 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -1176,14 +1176,14 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
unsigned int n_channels)
{
struct ieee80211_local *local = sdata->local;
- int ret = -EBUSY, i, n_ch = 0;
+ int i, n_ch = 0;
enum nl80211_band band;
lockdep_assert_wiphy(local->hw.wiphy);
/* busy scanning */
if (local->scan_req)
- goto unlock;
+ return -EBUSY;
/* fill internal scan request */
if (!channels) {
@@ -1200,7 +1200,9 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
&local->hw.wiphy->bands[band]->channels[i];
if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
- IEEE80211_CHAN_DISABLED))
+ IEEE80211_CHAN_DISABLED) ||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
+ tmp_ch))
continue;
local->int_scan_req->channels[n_ch] = tmp_ch;
@@ -1209,21 +1211,23 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
}
if (WARN_ON_ONCE(n_ch == 0))
- goto unlock;
+ return -EINVAL;
local->int_scan_req->n_channels = n_ch;
} else {
for (i = 0; i < n_channels; i++) {
if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
- IEEE80211_CHAN_DISABLED))
+ IEEE80211_CHAN_DISABLED) ||
+ !cfg80211_wdev_channel_allowed(&sdata->wdev,
+ channels[i]))
continue;
local->int_scan_req->channels[n_ch] = channels[i];
n_ch++;
}
- if (WARN_ON_ONCE(n_ch == 0))
- goto unlock;
+ if (n_ch == 0)
+ return -EINVAL;
local->int_scan_req->n_channels = n_ch;
}
@@ -1233,9 +1237,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
local->int_scan_req->ssids[0].ssid_len = ssid_len;
- ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
- unlock:
- return ret;
+ return __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
}
void ieee80211_scan_cancel(struct ieee80211_local *local)
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 073ff9e0f397..c6015cd00372 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -377,13 +377,8 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
/* capture the AP chandef before (potential) downgrading */
csa_ie->chanreq.ap = new_chandef;
- if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 &&
- new_chandef.width == NL80211_CHAN_WIDTH_320)
- ieee80211_chandef_downgrade(&new_chandef, NULL);
-
- if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_160 &&
- (new_chandef.width == NL80211_CHAN_WIDTH_80P80 ||
- new_chandef.width == NL80211_CHAN_WIDTH_160))
+ while (conn->bw_limit <
+ ieee80211_min_bw_limit_from_chandef(&new_chandef))
ieee80211_chandef_downgrade(&new_chandef, NULL);
if (!cfg80211_chandef_compatible(&new_chandef,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9195d5a2de0a..9f89fb5bee37 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -169,7 +169,7 @@ struct sta_info;
* @buf_size: reorder buffer size at receiver
* @failed_bar_ssn: ssn of the last failed BAR tx attempt
* @bar_pending: BAR needs to be re-sent
- * @amsdu: support A-MSDU withing A-MDPU
+ * @amsdu: support A-MSDU within A-MDPU
* @ssn: starting sequence number of the session
*
* This structure's lifetime is managed by RCU, assignments to
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index b41b867f43b2..5f28f3633fa0 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -927,6 +927,9 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
if (!ieee80211_sdata_running(sdata))
continue;
+ if (sdata->u.mntr.flags & MONITOR_FLAG_SKIP_TX)
+ continue;
+
if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) &&
!send_to_cooked)
continue;
@@ -1099,7 +1102,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
* This is a bit racy but we can avoid a lot of work
* with this test...
*/
- if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
+ if (!local->tx_mntrs && (!send_to_cooked || !local->cooked_mntrs)) {
if (status->free_list)
list_add_tail(&skb->list, status->free_list);
else
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index f07b40916485..2f92e7c7f203 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1342,7 +1342,8 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata,
bw = min(bw, ieee80211_sta_cap_rx_bw(&sta->deflink));
if (bw != sta->sta.deflink.bandwidth) {
sta->sta.deflink.bandwidth = bw;
- rate_control_rate_update(local, sband, sta, 0,
+ rate_control_rate_update(local, sband,
+ &sta->deflink,
IEEE80211_RC_BW_CHANGED);
/*
* if a TDLS peer BW was updated, we need to
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 880a1fa8705a..94c00e71f6f8 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -313,7 +313,7 @@ int ieee80211_tkip_decrypt_data(struct arc4_ctx *ctx,
* Record previously received IV, will be copied into the
* key information after MIC verification. It is possible
* that we don't catch replays of fragments but that's ok
- * because the Michael MIC verication will then fail.
+ * because the Michael MIC verification will then fail.
*/
*out_iv32 = iv32;
*out_iv16 = iv16;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index dc498cd8cd91..7a4985fc2b16 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -939,31 +939,34 @@ TRACE_EVENT(drv_sta_set_txpwr,
)
);
-TRACE_EVENT(drv_sta_rc_update,
+TRACE_EVENT(drv_link_sta_rc_update,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
u32 changed),
- TP_ARGS(local, sdata, sta, changed),
+ TP_ARGS(local, sdata, link_sta, changed),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
__field(u32, changed)
+ __field(u32, link_id)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
- STA_ASSIGN;
+ STA_NAMED_ASSIGN(link_sta->sta);
__entry->changed = changed;
+ __entry->link_id = link_sta->link_id;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " changed: 0x%x",
- LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->changed
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " (link %d) changed: 0x%x",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id,
+ __entry->changed
)
);
@@ -3154,6 +3157,25 @@ TRACE_EVENT(drv_neg_ttlm_res,
LOCAL_PR_ARG, VIF_PR_ARG, __entry->res
)
);
+
+TRACE_EVENT(drv_prep_add_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ enum nl80211_iftype type),
+
+ TP_ARGS(local, type),
+ TP_STRUCT__entry(LOCAL_ENTRY
+ __field(u32, type)
+ ),
+
+ TP_fast_assign(LOCAL_ASSIGN;
+ __entry->type = type;
+ ),
+
+ TP_printk(LOCAL_PR_FMT " type: %u\n ",
+ LOCAL_PR_ARG, __entry->type
+ )
+);
+
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0ff8b56f5807..a24636bda679 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1763,7 +1763,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
- if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
+ if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
vif = &sdata->vif;
break;
}
@@ -3952,7 +3953,8 @@ begin:
switch (tx.sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
- if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
+ if ((tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
+ ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
vif = &tx.sdata->vif;
break;
}
@@ -6214,7 +6216,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
goto start_xmit;
/* update QoS header to prioritize control port frames if possible,
- * priorization also happens for control port frames send over
+ * prioritization also happens for control port frames send over
* AF_PACKET
*/
rcu_read_lock();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index f94faa86ba8a..a4e1301cc999 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -756,7 +756,8 @@ static void __iterate_interfaces(struct ieee80211_local *local,
lockdep_is_held(&local->hw.wiphy->mtx)) {
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
- if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+ if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
continue;
break;
case NL80211_IFTYPE_AP_VLAN:
@@ -1010,7 +1011,7 @@ void ieee80211_set_wmm_default(struct ieee80211_link_data *link,
else
aCWmin = 15;
- /* Confiure old 802.11b/g medium access rules. */
+ /* Configure old 802.11b/g medium access rules. */
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
@@ -1873,8 +1874,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ continue;
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
ieee80211_sdata_running(sdata)) {
res = drv_add_interface(local, sdata);
if (WARN_ON(res))
@@ -1887,11 +1890,14 @@ int ieee80211_reconfig(struct ieee80211_local *local)
*/
if (res) {
list_for_each_entry_continue_reverse(sdata, &local->interfaces,
- list)
+ list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+ continue;
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- sdata->vif.type != NL80211_IFTYPE_MONITOR &&
ieee80211_sdata_running(sdata))
drv_remove_interface(local, sdata);
+ }
ieee80211_handle_reconfig_failure(local);
return res;
}
@@ -2752,7 +2758,7 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
return pos + sizeof(struct ieee80211_vht_operation);
}
-u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef)
+u8 *ieee80211_ie_build_he_oper(u8 *pos, const struct cfg80211_chan_def *chandef)
{
struct ieee80211_he_operation *he_oper;
struct ieee80211_he_6ghz_oper *he_6ghz_op;
@@ -2844,7 +2850,7 @@ out:
return pos;
}
-u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef,
+u8 *ieee80211_ie_build_eht_oper(u8 *pos, const struct cfg80211_chan_def *chandef,
const struct ieee80211_sta_eht_cap *eht_cap)
{
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index bf6ef45af757..6a20fa099190 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -280,10 +280,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
/*
* This is a workaround for VHT-enabled STAs which break the spec
* and have the VHT-MCS Rx map filled in with value 3 for all eight
- * spacial streams, an example is AR9462.
+ * spatial streams, an example is AR9462.
*
* As per spec, in section 22.1.1 Introduction to the VHT PHY
- * A VHT STA shall support at least single spactial stream VHT-MCSs
+ * A VHT STA shall support at least single spatial stream VHT-MCSs
* 0 to 7 (transmit and receive) in all supported channel widths.
*/
if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) {
@@ -479,28 +479,6 @@ ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *link_sta)
}
}
-enum ieee80211_sta_rx_bandwidth
-ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
-{
- switch (width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
- case NL80211_CHAN_WIDTH_20:
- return IEEE80211_STA_RX_BW_20;
- case NL80211_CHAN_WIDTH_40:
- return IEEE80211_STA_RX_BW_40;
- case NL80211_CHAN_WIDTH_80:
- return IEEE80211_STA_RX_BW_80;
- case NL80211_CHAN_WIDTH_160:
- case NL80211_CHAN_WIDTH_80P80:
- return IEEE80211_STA_RX_BW_160;
- case NL80211_CHAN_WIDTH_320:
- return IEEE80211_STA_RX_BW_320;
- default:
- WARN_ON_ONCE(1);
- return IEEE80211_STA_RX_BW_20;
- }
-}
-
/* FIXME: rename/move - this deals with everything not just VHT */
enum ieee80211_sta_rx_bandwidth
_ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta,
@@ -766,8 +744,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
if (changed > 0) {
ieee80211_recalc_min_chandef(sdata, link_sta->link_id);
- rate_control_rate_update(local, sband, link_sta->sta,
- link_sta->link_id, changed);
+ rate_control_rate_update(local, sband, link_sta, changed);
}
}
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 293afa3f57c5..40d5d9e48479 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -598,9 +598,6 @@ static void gcmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *j_0, u8 *aad,
memcpy(j_0, hdr->addr2, ETH_ALEN);
memcpy(&j_0[ETH_ALEN], pn, IEEE80211_GCMP_PN_LEN);
- j_0[13] = 0;
- j_0[14] = 0;
- j_0[AES_BLOCK_SIZE - 1] = 0x01;
ccmp_gcmp_aad(skb, aad, spp_amsdu);
}
diff --git a/net/mctp/device.c b/net/mctp/device.c
index 3d75b919995d..26ce34b7e88e 100644
--- a/net/mctp/device.c
+++ b/net/mctp/device.c
@@ -371,6 +371,8 @@ static int mctp_fill_link_af(struct sk_buff *skb,
return -ENODATA;
if (nla_put_u32(skb, IFLA_MCTP_NET, mdev->net))
return -EMSGSIZE;
+ if (nla_put_u8(skb, IFLA_MCTP_PHYS_BINDING, mdev->binding))
+ return -EMSGSIZE;
return 0;
}
@@ -385,6 +387,7 @@ static size_t mctp_get_link_af_size(const struct net_device *dev,
if (!mdev)
return 0;
ret = nla_total_size(4); /* IFLA_MCTP_NET */
+ ret += nla_total_size(1); /* IFLA_MCTP_PHYS_BINDING */
mctp_dev_put(mdev);
return ret;
}
@@ -480,7 +483,8 @@ static int mctp_dev_notify(struct notifier_block *this, unsigned long event,
}
static int mctp_register_netdevice(struct net_device *dev,
- const struct mctp_netdev_ops *ops)
+ const struct mctp_netdev_ops *ops,
+ enum mctp_phys_binding binding)
{
struct mctp_dev *mdev;
@@ -489,17 +493,19 @@ static int mctp_register_netdevice(struct net_device *dev,
return PTR_ERR(mdev);
mdev->ops = ops;
+ mdev->binding = binding;
return register_netdevice(dev);
}
int mctp_register_netdev(struct net_device *dev,
- const struct mctp_netdev_ops *ops)
+ const struct mctp_netdev_ops *ops,
+ enum mctp_phys_binding binding)
{
int rc;
rtnl_lock();
- rc = mctp_register_netdevice(dev, ops);
+ rc = mctp_register_netdevice(dev, ops, binding);
rtnl_unlock();
return rc;
diff --git a/net/mptcp/mptcp_pm_gen.c b/net/mptcp/mptcp_pm_gen.c
index 5a6b2b4510d3..dcffd847af33 100644
--- a/net/mptcp/mptcp_pm_gen.c
+++ b/net/mptcp/mptcp_pm_gen.c
@@ -112,7 +112,6 @@ const struct genl_ops mptcp_pm_nl_ops[11] = {
.dumpit = mptcp_pm_nl_get_addr_dumpit,
.policy = mptcp_pm_get_addr_nl_policy,
.maxattr = MPTCP_PM_ATTR_TOKEN,
- .flags = GENL_UNS_ADMIN_PERM,
},
{
.cmd = MPTCP_PM_CMD_FLUSH_ADDRS,
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 618289aac0ab..758a0dbfcf78 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -524,7 +524,8 @@ __lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info)
{
struct mptcp_pm_addr_entry *entry;
- list_for_each_entry(entry, &pernet->local_addr_list, list) {
+ list_for_each_entry_rcu(entry, &pernet->local_addr_list, list,
+ lockdep_is_held(&pernet->lock)) {
if (mptcp_addresses_equal(&entry->addr, info, entry->addr.port))
return entry;
}
diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c
index 2cceded3a83a..e35178f5205f 100644
--- a/net/mptcp/pm_userspace.c
+++ b/net/mptcp/pm_userspace.c
@@ -91,6 +91,7 @@ static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
struct mptcp_pm_addr_entry *addr)
{
struct mptcp_pm_addr_entry *entry, *tmp;
+ struct sock *sk = (struct sock *)msk;
list_for_each_entry_safe(entry, tmp, &msk->pm.userspace_pm_local_addr_list, list) {
if (mptcp_addresses_equal(&entry->addr, &addr->addr, false)) {
@@ -98,7 +99,7 @@ static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
* be used multiple times (e.g. fullmesh mode).
*/
list_del_rcu(&entry->list);
- kfree(entry);
+ sock_kfree_s(sk, entry, sizeof(*entry));
msk->pm.local_addr_used--;
return 0;
}
@@ -307,14 +308,17 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
lock_sock(sk);
+ spin_lock_bh(&msk->pm.lock);
match = mptcp_userspace_pm_lookup_addr_by_id(msk, id_val);
if (!match) {
GENL_SET_ERR_MSG(info, "address with specified id not found");
+ spin_unlock_bh(&msk->pm.lock);
release_sock(sk);
goto out;
}
list_move(&match->list, &free_list);
+ spin_unlock_bh(&msk->pm.lock);
mptcp_pm_remove_addrs(msk, &free_list);
@@ -559,6 +563,7 @@ int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
struct net *net = sock_net(skb->sk);
+ struct mptcp_pm_addr_entry *entry;
struct mptcp_sock *msk;
int ret = -EINVAL;
struct sock *sk;
@@ -600,6 +605,17 @@ int mptcp_userspace_pm_set_flags(struct sk_buff *skb, struct genl_info *info)
if (loc.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
bkup = 1;
+ spin_lock_bh(&msk->pm.lock);
+ list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) {
+ if (mptcp_addresses_equal(&entry->addr, &loc.addr, false)) {
+ if (bkup)
+ entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+ else
+ entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
+ }
+ }
+ spin_unlock_bh(&msk->pm.lock);
+
lock_sock(sk);
ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc.addr, &rem.addr, bkup);
release_sock(sk);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index e978e05ec8d1..08a72242428c 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -2082,7 +2082,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
slow = lock_sock_fast(ssk);
WRITE_ONCE(ssk->sk_rcvbuf, rcvbuf);
WRITE_ONCE(tcp_sk(ssk)->window_clamp, window_clamp);
- tcp_cleanup_rbuf(ssk, 1);
+ if (tcp_can_send_ack(ssk))
+ tcp_cleanup_rbuf(ssk, 1);
unlock_sock_fast(ssk, slow);
}
}
@@ -2205,7 +2206,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
cmsg_flags = MPTCP_CMSG_INQ;
while (copied < len) {
- int bytes_read;
+ int err, bytes_read;
bytes_read = __mptcp_recvmsg_mskq(msk, msg, len - copied, flags, &tss, &cmsg_flags);
if (unlikely(bytes_read < 0)) {
@@ -2267,9 +2268,16 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
}
pr_debug("block timeout %ld\n", timeo);
- sk_wait_data(sk, &timeo, NULL);
+ mptcp_rcv_space_adjust(msk, copied);
+ err = sk_wait_data(sk, &timeo, NULL);
+ if (err < 0) {
+ err = copied ? : err;
+ goto out_err;
+ }
}
+ mptcp_rcv_space_adjust(msk, copied);
+
out_err:
if (cmsg_flags && copied >= 0) {
if (cmsg_flags & MPTCP_CMSG_TS)
@@ -2285,8 +2293,6 @@ out_err:
pr_debug("msk=%p rx queue empty=%d:%d copied=%d\n",
msk, skb_queue_empty_lockless(&sk->sk_receive_queue),
skb_queue_empty(&msk->receive_queue), copied);
- if (!(flags & MSG_PEEK))
- mptcp_rcv_space_adjust(msk, copied);
release_sock(sk);
return copied;
@@ -2722,8 +2728,8 @@ void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout)
if (!fail_tout && !inet_csk(sk)->icsk_mtup.probe_timestamp)
return;
- close_timeout = inet_csk(sk)->icsk_mtup.probe_timestamp - tcp_jiffies32 + jiffies +
- mptcp_close_timeout(sk);
+ close_timeout = (unsigned long)inet_csk(sk)->icsk_mtup.probe_timestamp -
+ tcp_jiffies32 + jiffies + mptcp_close_timeout(sk);
/* the close timeout takes precedence on the fail one, and here at least one of
* them is active
@@ -2864,8 +2870,10 @@ static int mptcp_init_sock(struct sock *sk)
if (unlikely(!net->mib.mptcp_statistics) && !mptcp_mib_alloc(net))
return -ENOMEM;
+ rcu_read_lock();
ret = mptcp_init_sched(mptcp_sk(sk),
mptcp_sched_find(mptcp_get_scheduler(net)));
+ rcu_read_unlock();
if (ret)
return ret;
diff --git a/net/mptcp/sched.c b/net/mptcp/sched.c
index 78ed508ebc1b..df7dbcfa3b71 100644
--- a/net/mptcp/sched.c
+++ b/net/mptcp/sched.c
@@ -60,7 +60,6 @@ void mptcp_get_available_schedulers(char *buf, size_t maxlen)
size_t offs = 0;
rcu_read_lock();
- spin_lock(&mptcp_sched_list_lock);
list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
offs += snprintf(buf + offs, maxlen - offs,
"%s%s",
@@ -69,7 +68,6 @@ void mptcp_get_available_schedulers(char *buf, size_t maxlen)
if (WARN_ON_ONCE(offs >= maxlen))
break;
}
- spin_unlock(&mptcp_sched_list_lock);
rcu_read_unlock();
}
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 07352b15f145..fd021cf8286e 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -2049,7 +2049,6 @@ static void subflow_ulp_clone(const struct request_sock *req,
new_ctx->tcp_state_change = old_ctx->tcp_state_change;
new_ctx->tcp_error_report = old_ctx->tcp_error_report;
new_ctx->rel_write_seq = 1;
- new_ctx->tcp_sock = newsk;
if (subflow_req->mp_capable) {
/* see comments in subflow_syn_recv_sock(), MPTCP connection
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index dc6ddc4abbe2..7d13110ce188 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3662,10 +3662,7 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr));
udest->port = nla_get_be16(nla_port);
- if (nla_addr_family)
- udest->af = nla_get_u16(nla_addr_family);
- else
- udest->af = 0;
+ udest->af = nla_get_u16_default(nla_addr_family, 0);
/* If a full entry was requested, check for the additional fields */
if (full_entry) {
diff --git a/net/netfilter/nf_bpf_link.c b/net/netfilter/nf_bpf_link.c
index 3d64a4511fcf..06b084844700 100644
--- a/net/netfilter/nf_bpf_link.c
+++ b/net/netfilter/nf_bpf_link.c
@@ -43,7 +43,7 @@ get_proto_defrag_hook(struct bpf_nf_link *link,
hook = rcu_dereference(*ptr_global_hook);
if (!hook) {
rcu_read_unlock();
- err = request_module(mod);
+ err = request_module("%s", mod);
if (err)
return ERR_PTR(err < 0 ? err : -EINVAL);
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 4085c436e306..aad84aabd7f1 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -1090,10 +1090,8 @@ static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
range->flags |= NF_NAT_RANGE_MAP_IPS;
}
- if (tb[CTA_NAT_V4_MAXIP])
- range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
- else
- range->max_addr.ip = range->min_addr.ip;
+ range->max_addr.ip = nla_get_be32_default(tb[CTA_NAT_V4_MAXIP],
+ range->min_addr.ip);
return 0;
}
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index a24fe62650a7..21b6f7410a1f 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -26,6 +26,9 @@
#define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-"))
#define NFT_SET_MAX_ANONLEN 16
+/* limit compaction to avoid huge kmalloc/krealloc sizes. */
+#define NFT_MAX_SET_NELEMS ((2048 - sizeof(struct nft_trans_elem)) / sizeof(struct nft_trans_one_elem))
+
unsigned int nf_tables_net_id __read_mostly;
static LIST_HEAD(nf_tables_expressions);
@@ -391,6 +394,86 @@ static void nf_tables_unregister_hook(struct net *net,
return __nf_tables_unregister_hook(net, table, chain, false);
}
+static bool nft_trans_collapse_set_elem_allowed(const struct nft_trans_elem *a, const struct nft_trans_elem *b)
+{
+ /* NB: the ->bound equality check is defensive, at this time we only merge
+ * a new nft_trans_elem transaction request with the transaction tail
+ * element, but a->bound != b->bound would imply a NEWRULE transaction
+ * is queued in-between.
+ *
+ * The set check is mandatory, the NFT_MAX_SET_NELEMS check prevents
+ * huge krealloc() requests.
+ */
+ return a->set == b->set && a->bound == b->bound && a->nelems < NFT_MAX_SET_NELEMS;
+}
+
+static bool nft_trans_collapse_set_elem(struct nftables_pernet *nft_net,
+ struct nft_trans_elem *tail,
+ struct nft_trans_elem *trans,
+ gfp_t gfp)
+{
+ unsigned int nelems, old_nelems = tail->nelems;
+ struct nft_trans_elem *new_trans;
+
+ if (!nft_trans_collapse_set_elem_allowed(tail, trans))
+ return false;
+
+ /* "cannot happen", at this time userspace element add
+ * requests always allocate a new transaction element.
+ *
+ * This serves as a reminder to adjust the list_add_tail
+ * logic below in case this ever changes.
+ */
+ if (WARN_ON_ONCE(trans->nelems != 1))
+ return false;
+
+ if (check_add_overflow(old_nelems, trans->nelems, &nelems))
+ return false;
+
+ /* krealloc might free tail which invalidates list pointers */
+ list_del_init(&tail->nft_trans.list);
+
+ new_trans = krealloc(tail, struct_size(tail, elems, nelems), gfp);
+ if (!new_trans) {
+ list_add_tail(&tail->nft_trans.list, &nft_net->commit_list);
+ return false;
+ }
+
+ /*
+ * new_trans->nft_trans.list contains garbage, but
+ * list_add_tail() doesn't care.
+ */
+ new_trans->nelems = nelems;
+ new_trans->elems[old_nelems] = trans->elems[0];
+ list_add_tail(&new_trans->nft_trans.list, &nft_net->commit_list);
+
+ return true;
+}
+
+static bool nft_trans_try_collapse(struct nftables_pernet *nft_net,
+ struct nft_trans *trans, gfp_t gfp)
+{
+ struct nft_trans *tail;
+
+ if (list_empty(&nft_net->commit_list))
+ return false;
+
+ tail = list_last_entry(&nft_net->commit_list, struct nft_trans, list);
+
+ if (tail->msg_type != trans->msg_type)
+ return false;
+
+ switch (trans->msg_type) {
+ case NFT_MSG_NEWSETELEM:
+ case NFT_MSG_DELSETELEM:
+ return nft_trans_collapse_set_elem(nft_net,
+ nft_trans_container_elem(tail),
+ nft_trans_container_elem(trans), gfp);
+ }
+
+ return false;
+}
+
static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
{
struct nftables_pernet *nft_net = nft_pernet(net);
@@ -421,6 +504,24 @@ static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *tr
}
}
+static void nft_trans_commit_list_add_elem(struct net *net, struct nft_trans *trans,
+ gfp_t gfp)
+{
+ struct nftables_pernet *nft_net = nft_pernet(net);
+
+ WARN_ON_ONCE(trans->msg_type != NFT_MSG_NEWSETELEM &&
+ trans->msg_type != NFT_MSG_DELSETELEM);
+
+ might_alloc(gfp);
+
+ if (nft_trans_try_collapse(nft_net, trans, gfp)) {
+ kfree(trans);
+ return;
+ }
+
+ nft_trans_commit_list_add_tail(net, trans);
+}
+
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
{
struct nft_trans *trans;
@@ -1495,6 +1596,7 @@ static int nf_tables_newtable(struct sk_buff *skb, const struct nfnl_info *info,
INIT_LIST_HEAD(&table->sets);
INIT_LIST_HEAD(&table->objects);
INIT_LIST_HEAD(&table->flowtables);
+ write_pnet(&table->net, net);
table->family = family;
table->flags = flags;
table->handle = ++nft_net->table_handle;
@@ -1824,7 +1926,8 @@ nla_put_failure:
return -ENOSPC;
}
-static int nft_dump_basechain_hook(struct sk_buff *skb, int family,
+static int nft_dump_basechain_hook(struct sk_buff *skb,
+ const struct net *net, int family,
const struct nft_base_chain *basechain,
const struct list_head *hook_list)
{
@@ -1849,7 +1952,8 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, int family,
if (!hook_list)
hook_list = &basechain->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list) {
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
if (!first)
first = hook;
@@ -1900,7 +2004,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
const struct nft_base_chain *basechain = nft_base_chain(chain);
struct nft_stats __percpu *stats;
- if (nft_dump_basechain_hook(skb, family, basechain, hook_list))
+ if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list))
goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
@@ -2082,14 +2186,14 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
err = nla_parse_nested_deprecated(tb, NFTA_COUNTER_MAX, attr,
nft_counter_policy, NULL);
if (err < 0)
- return ERR_PTR(err);
+ return ERR_PTR_PCPU(err);
if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
- return ERR_PTR(-EINVAL);
+ return ERR_PTR_PCPU(-EINVAL);
newstats = netdev_alloc_pcpu_stats(struct nft_stats);
if (newstats == NULL)
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR_PCPU(-ENOMEM);
/* Restore old counters on this cpu, no problem. Per-cpu statistics
* are not exposed to userspace.
@@ -2533,10 +2637,10 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (nla[NFTA_CHAIN_COUNTERS]) {
stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
- if (IS_ERR(stats)) {
+ if (IS_ERR_PCPU(stats)) {
nft_chain_release_hook(&hook);
kfree(basechain);
- return PTR_ERR(stats);
+ return PTR_ERR_PCPU(stats);
}
rcu_assign_pointer(basechain->stats, stats);
}
@@ -2650,7 +2754,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
struct nft_table *table = ctx->table;
struct nft_chain *chain = ctx->chain;
struct nft_chain_hook hook = {};
- struct nft_stats *stats = NULL;
+ struct nft_stats __percpu *stats = NULL;
struct nft_hook *h, *next;
struct nf_hook_ops *ops;
struct nft_trans *trans;
@@ -2746,8 +2850,8 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
}
stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
- if (IS_ERR(stats)) {
- err = PTR_ERR(stats);
+ if (IS_ERR_PCPU(stats)) {
+ err = PTR_ERR_PCPU(stats);
goto err_hooks;
}
}
@@ -3294,25 +3398,37 @@ int nft_expr_inner_parse(const struct nft_ctx *ctx, const struct nlattr *nla,
if (!tb[NFTA_EXPR_DATA] || !tb[NFTA_EXPR_NAME])
return -EINVAL;
+ rcu_read_lock();
+
type = __nft_expr_type_get(ctx->family, tb[NFTA_EXPR_NAME]);
- if (!type)
- return -ENOENT;
+ if (!type) {
+ err = -ENOENT;
+ goto out_unlock;
+ }
- if (!type->inner_ops)
- return -EOPNOTSUPP;
+ if (!type->inner_ops) {
+ err = -EOPNOTSUPP;
+ goto out_unlock;
+ }
err = nla_parse_nested_deprecated(info->tb, type->maxattr,
tb[NFTA_EXPR_DATA],
type->policy, NULL);
if (err < 0)
- goto err_nla_parse;
+ goto out_unlock;
info->attr = nla;
info->ops = type->inner_ops;
+ /* No module reference will be taken on type->owner.
+ * Presence of type->inner_ops implies that the expression
+ * is builtin, so it cannot go away.
+ */
+ rcu_read_unlock();
return 0;
-err_nla_parse:
+out_unlock:
+ rcu_read_unlock();
return err;
}
@@ -3411,13 +3527,15 @@ void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr)
* Rules
*/
-static struct nft_rule *__nft_rule_lookup(const struct nft_chain *chain,
+static struct nft_rule *__nft_rule_lookup(const struct net *net,
+ const struct nft_chain *chain,
u64 handle)
{
struct nft_rule *rule;
// FIXME: this sucks
- list_for_each_entry_rcu(rule, &chain->rules, list) {
+ list_for_each_entry_rcu(rule, &chain->rules, list,
+ lockdep_commit_lock_is_held(net)) {
if (handle == rule->handle)
return rule;
}
@@ -3425,13 +3543,14 @@ static struct nft_rule *__nft_rule_lookup(const struct nft_chain *chain,
return ERR_PTR(-ENOENT);
}
-static struct nft_rule *nft_rule_lookup(const struct nft_chain *chain,
+static struct nft_rule *nft_rule_lookup(const struct net *net,
+ const struct nft_chain *chain,
const struct nlattr *nla)
{
if (nla == NULL)
return ERR_PTR(-EINVAL);
- return __nft_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
+ return __nft_rule_lookup(net, chain, be64_to_cpu(nla_get_be64(nla)));
}
static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
@@ -3732,7 +3851,7 @@ static int nf_tables_dump_rules_done(struct netlink_callback *cb)
return 0;
}
-/* called with rcu_read_lock held */
+/* Caller must hold rcu read lock or transaction mutex */
static struct sk_buff *
nf_tables_getrule_single(u32 portid, const struct nfnl_info *info,
const struct nlattr * const nla[], bool reset)
@@ -3759,7 +3878,7 @@ nf_tables_getrule_single(u32 portid, const struct nfnl_info *info,
return ERR_CAST(chain);
}
- rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
+ rule = nft_rule_lookup(net, chain, nla[NFTA_RULE_HANDLE]);
if (IS_ERR(rule)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
return ERR_CAST(rule);
@@ -3983,7 +4102,8 @@ int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
struct nft_set_ext *ext;
int ret = 0;
- list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list,
+ lockdep_commit_lock_is_held(ctx->net)) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, dummy_iter.genmask))
continue;
@@ -4057,7 +4177,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
if (nla[NFTA_RULE_HANDLE]) {
handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
- rule = __nft_rule_lookup(chain, handle);
+ rule = __nft_rule_lookup(net, chain, handle);
if (IS_ERR(rule)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
return PTR_ERR(rule);
@@ -4079,7 +4199,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
if (nla[NFTA_RULE_POSITION]) {
pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
- old_rule = __nft_rule_lookup(chain, pos_handle);
+ old_rule = __nft_rule_lookup(net, chain, pos_handle);
if (IS_ERR(old_rule)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_POSITION]);
return PTR_ERR(old_rule);
@@ -4296,7 +4416,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
if (chain) {
if (nla[NFTA_RULE_HANDLE]) {
- rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
+ rule = nft_rule_lookup(info->net, chain, nla[NFTA_RULE_HANDLE]);
if (IS_ERR(rule)) {
if (PTR_ERR(rule) == -ENOENT &&
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
@@ -4456,7 +4576,8 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
[NFTA_SET_DESC_CONCAT] = NLA_POLICY_NESTED_ARRAY(nft_concat_policy),
};
-static struct nft_set *nft_set_lookup(const struct nft_table *table,
+static struct nft_set *nft_set_lookup(const struct net *net,
+ const struct nft_table *table,
const struct nlattr *nla, u8 genmask)
{
struct nft_set *set;
@@ -4464,7 +4585,8 @@ static struct nft_set *nft_set_lookup(const struct nft_table *table,
if (nla == NULL)
return ERR_PTR(-EINVAL);
- list_for_each_entry_rcu(set, &table->sets, list) {
+ list_for_each_entry_rcu(set, &table->sets, list,
+ lockdep_commit_lock_is_held(net)) {
if (!nla_strcmp(nla, set->name) &&
nft_active_genmask(set, genmask))
return set;
@@ -4514,7 +4636,7 @@ struct nft_set *nft_set_lookup_global(const struct net *net,
{
struct nft_set *set;
- set = nft_set_lookup(table, nla_set_name, genmask);
+ set = nft_set_lookup(net, table, nla_set_name, genmask);
if (IS_ERR(set)) {
if (!nla_set_id)
return set;
@@ -4890,7 +5012,7 @@ static int nf_tables_getset(struct sk_buff *skb, const struct nfnl_info *info,
if (!nla[NFTA_SET_TABLE])
return -EINVAL;
- set = nft_set_lookup(table, nla[NFTA_SET_NAME], genmask);
+ set = nft_set_lookup(net, table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_NAME]);
return PTR_ERR(set);
@@ -5226,7 +5348,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
- set = nft_set_lookup(table, nla[NFTA_SET_NAME], genmask);
+ set = nft_set_lookup(net, table, nla[NFTA_SET_NAME], genmask);
if (IS_ERR(set)) {
if (PTR_ERR(set) != -ENOENT) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_NAME]);
@@ -5428,7 +5550,7 @@ static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
set = nft_set_lookup_byhandle(table, attr, genmask);
} else {
attr = nla[NFTA_SET_NAME];
- set = nft_set_lookup(table, attr, genmask);
+ set = nft_set_lookup(net, table, attr, genmask);
}
if (IS_ERR(set)) {
@@ -5492,7 +5614,8 @@ static int nft_set_catchall_bind_check(const struct nft_ctx *ctx,
struct nft_set_ext *ext;
int ret = 0;
- list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list,
+ lockdep_commit_lock_is_held(ctx->net)) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
@@ -6258,7 +6381,7 @@ static int nft_set_dump_ctx_init(struct nft_set_dump_ctx *dump_ctx,
return PTR_ERR(table);
}
- set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
+ set = nft_set_lookup(net, table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
if (IS_ERR(set)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_SET]);
return PTR_ERR(set);
@@ -6409,17 +6532,21 @@ err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
}
-static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
+static struct nft_trans *nft_trans_elem_alloc(const struct nft_ctx *ctx,
int msg_type,
struct nft_set *set)
{
+ struct nft_trans_elem *te;
struct nft_trans *trans;
- trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_elem));
+ trans = nft_trans_alloc(ctx, msg_type, struct_size(te, elems, 1));
if (trans == NULL)
return NULL;
- nft_trans_elem_set(trans) = set;
+ te = nft_trans_container_elem(trans);
+ te->nelems = 1;
+ te->set = set;
+
return trans;
}
@@ -6541,28 +6668,52 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
}
/* Drop references and destroy. Called from gc, dynset and abort path. */
-void nft_set_elem_destroy(const struct nft_set *set,
- const struct nft_elem_priv *elem_priv,
- bool destroy_expr)
+static void __nft_set_elem_destroy(const struct nft_ctx *ctx,
+ const struct nft_set *set,
+ const struct nft_elem_priv *elem_priv,
+ bool destroy_expr)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
- struct nft_ctx ctx = {
- .net = read_pnet(&set->net),
- .family = set->table->family,
- };
nft_data_release(nft_set_ext_key(ext), NFT_DATA_VALUE);
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
- nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
+ nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
kfree(elem_priv);
}
+
+/* Drop references and destroy. Called from gc and dynset. */
+void nft_set_elem_destroy(const struct nft_set *set,
+ const struct nft_elem_priv *elem_priv,
+ bool destroy_expr)
+{
+ struct nft_ctx ctx = {
+ .net = read_pnet(&set->net),
+ .family = set->table->family,
+ };
+
+ __nft_set_elem_destroy(&ctx, set, elem_priv, destroy_expr);
+}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
+/* Drop references and destroy. Called from abort path. */
+static void nft_trans_set_elem_destroy(const struct nft_ctx *ctx, struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ /* skip update request, see nft_trans_elems_new_abort() */
+ if (!te->elems[i].priv)
+ continue;
+
+ __nft_set_elem_destroy(ctx, te->set, te->elems[i].priv, true);
+ }
+}
+
/* Destroy element. References have been already dropped in the preparation
* path via nft_setelem_data_deactivate().
*/
@@ -6578,6 +6729,15 @@ void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
kfree(elem_priv);
}
+static void nft_trans_elems_destroy(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++)
+ nf_tables_set_elem_destroy(ctx, te->set, te->elems[i].priv);
+}
+
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_expr *expr_array[])
{
@@ -6734,6 +6894,38 @@ static void nft_setelem_activate(struct net *net, struct nft_set *set,
}
}
+static void nft_trans_elem_update(const struct nft_set *set,
+ const struct nft_trans_one_elem *elem)
+{
+ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+ const struct nft_elem_update *update = elem->update;
+
+ if (update->flags & NFT_TRANS_UPD_TIMEOUT)
+ WRITE_ONCE(nft_set_ext_timeout(ext)->timeout, update->timeout);
+
+ if (update->flags & NFT_TRANS_UPD_EXPIRATION)
+ WRITE_ONCE(nft_set_ext_timeout(ext)->expiration, get_jiffies_64() + update->expiration);
+}
+
+static void nft_trans_elems_add(const struct nft_ctx *ctx,
+ struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ struct nft_trans_one_elem *elem = &te->elems[i];
+
+ if (elem->update)
+ nft_trans_elem_update(te->set, elem);
+ else
+ nft_setelem_activate(ctx->net, te->set, elem->priv);
+
+ nf_tables_setelem_notify(ctx, te->set, elem->priv,
+ NFT_MSG_NEWSETELEM);
+ kfree(elem->update);
+ }
+}
+
static int nft_setelem_catchall_deactivate(const struct net *net,
struct nft_set *set,
struct nft_set_elem *elem)
@@ -6816,6 +7008,26 @@ static void nft_setelem_remove(const struct net *net,
set->ops->remove(net, set, elem_priv);
}
+static void nft_trans_elems_remove(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ WARN_ON_ONCE(te->elems[i].update);
+
+ nf_tables_setelem_notify(ctx, te->set,
+ te->elems[i].priv,
+ te->nft_trans.msg_type);
+
+ nft_setelem_remove(ctx->net, te->set, te->elems[i].priv);
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv)) {
+ atomic_dec(&te->set->nelems);
+ te->set->ndeact--;
+ }
+ }
+}
+
static bool nft_setelem_valid_key_end(const struct nft_set *set,
struct nlattr **nla, u32 flags)
{
@@ -6852,7 +7064,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_data_desc desc;
enum nft_registers dreg;
struct nft_trans *trans;
- u8 update_flags;
u64 expiration;
u64 timeout;
int err, i;
@@ -7167,23 +7378,33 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
else if (!(nlmsg_flags & NLM_F_EXCL)) {
err = 0;
if (nft_set_ext_exists(ext2, NFT_SET_EXT_TIMEOUT)) {
- update_flags = 0;
+ struct nft_elem_update update = { };
+
if (timeout != nft_set_ext_timeout(ext2)->timeout) {
- nft_trans_elem_timeout(trans) = timeout;
+ update.timeout = timeout;
if (expiration == 0)
expiration = timeout;
- update_flags |= NFT_TRANS_UPD_TIMEOUT;
+ update.flags |= NFT_TRANS_UPD_TIMEOUT;
}
if (expiration) {
- nft_trans_elem_expiration(trans) = expiration;
- update_flags |= NFT_TRANS_UPD_EXPIRATION;
+ update.expiration = expiration;
+ update.flags |= NFT_TRANS_UPD_EXPIRATION;
}
- if (update_flags) {
- nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_elem_update_flags(trans) = update_flags;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ if (update.flags) {
+ struct nft_trans_one_elem *ue;
+
+ ue = &nft_trans_container_elem(trans)->elems[0];
+
+ ue->update = kmemdup(&update, sizeof(update), GFP_KERNEL);
+ if (!ue->update) {
+ err = -ENOMEM;
+ goto err_element_clash;
+ }
+
+ ue->priv = elem_priv;
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
goto err_elem_free;
}
}
@@ -7206,8 +7427,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
}
}
- nft_trans_elem_priv(trans) = elem.priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_container_elem(trans)->elems[0].priv = elem.priv;
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
err_set_full:
@@ -7344,6 +7565,55 @@ void nft_setelem_data_deactivate(const struct net *net,
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
}
+/* similar to nft_trans_elems_remove, but called from abort path to undo newsetelem.
+ * No notifications and no ndeact changes.
+ *
+ * Returns true if set had been added to (i.e., elements need to be removed again).
+ */
+static bool nft_trans_elems_new_abort(const struct nft_ctx *ctx,
+ struct nft_trans_elem *te)
+{
+ bool removed = false;
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ if (te->elems[i].update) {
+ kfree(te->elems[i].update);
+ te->elems[i].update = NULL;
+ /* Update request, so do not release this element */
+ te->elems[i].priv = NULL;
+ continue;
+ }
+
+ if (!te->set->ops->abort || nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ nft_setelem_remove(ctx->net, te->set, te->elems[i].priv);
+
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ atomic_dec(&te->set->nelems);
+
+ removed = true;
+ }
+
+ return removed;
+}
+
+/* Called from abort path to undo DELSETELEM/DESTROYSETELEM. */
+static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx,
+ const struct nft_trans_elem *te)
+{
+ int i;
+
+ for (i = 0; i < te->nelems; i++) {
+ if (!nft_setelem_active_next(ctx->net, te->set, te->elems[i].priv)) {
+ nft_setelem_data_activate(ctx->net, te->set, te->elems[i].priv);
+ nft_setelem_activate(ctx->net, te->set, te->elems[i].priv);
+ }
+
+ if (!nft_setelem_is_catchall(te->set, te->elems[i].priv))
+ te->set->ndeact--;
+ }
+}
+
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr)
{
@@ -7423,8 +7693,8 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
nft_setelem_data_deactivate(ctx->net, set, elem.priv);
- nft_trans_elem_priv(trans) = elem.priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_container_elem(trans)->elems[0].priv = elem.priv;
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
fail_ops:
@@ -7450,7 +7720,8 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
return 0;
trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
- sizeof(struct nft_trans_elem), GFP_ATOMIC);
+ struct_size_t(struct nft_trans_elem, elems, 1),
+ GFP_ATOMIC);
if (!trans)
return -ENOMEM;
@@ -7459,8 +7730,9 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
nft_trans_elem_set(trans) = set;
- nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_container_elem(trans)->nelems = 1;
+ nft_trans_container_elem(trans)->elems[0].priv = elem_priv;
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_ATOMIC);
return 0;
}
@@ -7471,15 +7743,13 @@ static int __nft_set_catchall_flush(const struct nft_ctx *ctx,
{
struct nft_trans *trans;
- trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
- sizeof(struct nft_trans_elem), GFP_KERNEL);
+ trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (!trans)
return -ENOMEM;
nft_setelem_data_deactivate(ctx->net, set, elem_priv);
- nft_trans_elem_set(trans) = set;
- nft_trans_elem_priv(trans) = elem_priv;
- nft_trans_commit_list_add_tail(ctx->net, trans);
+ nft_trans_container_elem(trans)->elems[0].priv = elem_priv;
+ nft_trans_commit_list_add_elem(ctx->net, trans, GFP_KERNEL);
return 0;
}
@@ -7492,7 +7762,8 @@ static int nft_set_catchall_flush(const struct nft_ctx *ctx,
struct nft_set_ext *ext;
int ret = 0;
- list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+ list_for_each_entry_rcu(catchall, &set->catchall_list, list,
+ lockdep_commit_lock_is_held(ctx->net)) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
continue;
@@ -7542,7 +7813,7 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
return PTR_ERR(table);
}
- set = nft_set_lookup(table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
+ set = nft_set_lookup(net, table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
if (IS_ERR(set)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_SET]);
return PTR_ERR(set);
@@ -7789,9 +8060,7 @@ static int nf_tables_updobj(const struct nft_ctx *ctx,
struct nft_trans *trans;
int err = -ENOMEM;
- if (!try_module_get(type->owner))
- return -ENOENT;
-
+ /* caller must have obtained type->owner reference. */
trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ,
sizeof(struct nft_trans_obj));
if (!trans)
@@ -7859,15 +8128,16 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
if (info->nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
- type = __nft_obj_type_get(objtype, family);
- if (WARN_ON_ONCE(!type))
- return -ENOENT;
-
if (!obj->ops->update)
return 0;
+ type = nft_obj_type_get(net, objtype, family);
+ if (WARN_ON_ONCE(IS_ERR(type)))
+ return PTR_ERR(type);
+
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
+ /* type->owner reference is put when transaction object is released. */
return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
}
@@ -8103,7 +8373,7 @@ static int nf_tables_dump_obj_done(struct netlink_callback *cb)
return 0;
}
-/* called with rcu_read_lock held */
+/* Caller must hold rcu read lock or transaction mutex */
static struct sk_buff *
nf_tables_getobj_single(u32 portid, const struct nfnl_info *info,
const struct nlattr * const nla[], bool reset)
@@ -8372,12 +8642,14 @@ static const struct nla_policy nft_flowtable_policy[NFTA_FLOWTABLE_MAX + 1] = {
[NFTA_FLOWTABLE_FLAGS] = { .type = NLA_U32 },
};
-struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
+struct nft_flowtable *nft_flowtable_lookup(const struct net *net,
+ const struct nft_table *table,
const struct nlattr *nla, u8 genmask)
{
struct nft_flowtable *flowtable;
- list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
+ list_for_each_entry_rcu(flowtable, &table->flowtables, list,
+ lockdep_commit_lock_is_held(net)) {
if (!nla_strcmp(nla, flowtable->name) &&
nft_active_genmask(flowtable, genmask))
return flowtable;
@@ -8733,7 +9005,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
return PTR_ERR(table);
}
- flowtable = nft_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
+ flowtable = nft_flowtable_lookup(net, table, nla[NFTA_FLOWTABLE_NAME],
genmask);
if (IS_ERR(flowtable)) {
err = PTR_ERR(flowtable);
@@ -8927,7 +9199,7 @@ static int nf_tables_delflowtable(struct sk_buff *skb,
flowtable = nft_flowtable_lookup_byhandle(table, attr, genmask);
} else {
attr = nla[NFTA_FLOWTABLE_NAME];
- flowtable = nft_flowtable_lookup(table, attr, genmask);
+ flowtable = nft_flowtable_lookup(net, table, attr, genmask);
}
if (IS_ERR(flowtable)) {
@@ -8997,7 +9269,8 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
if (!hook_list)
hook_list = &flowtable->hook_list;
- list_for_each_entry_rcu(hook, hook_list, list) {
+ list_for_each_entry_rcu(hook, hook_list, list,
+ lockdep_commit_lock_is_held(net)) {
if (nla_put_string(skb, NFTA_DEVICE_NAME, hook->ops.dev->name))
goto nla_put_failure;
}
@@ -9139,7 +9412,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
return PTR_ERR(table);
}
- flowtable = nft_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
+ flowtable = nft_flowtable_lookup(net, table, nla[NFTA_FLOWTABLE_NAME],
genmask);
if (IS_ERR(flowtable)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_NAME]);
@@ -9657,9 +9930,7 @@ static void nft_commit_release(struct nft_trans *trans)
break;
case NFT_MSG_DELSETELEM:
case NFT_MSG_DESTROYSETELEM:
- nf_tables_set_elem_destroy(&ctx,
- nft_trans_elem_set(trans),
- nft_trans_elem_priv(trans));
+ nft_trans_elems_destroy(&ctx, nft_trans_container_elem(trans));
break;
case NFT_MSG_DELOBJ:
case NFT_MSG_DESTROYOBJ:
@@ -10232,9 +10503,24 @@ static void nf_tables_commit_audit_free(struct list_head *adl)
}
}
+/* nft audit emits the number of elements that get added/removed/updated,
+ * so NEW/DELSETELEM needs to increment based on the total elem count.
+ */
+static unsigned int nf_tables_commit_audit_entrycount(const struct nft_trans *trans)
+{
+ switch (trans->msg_type) {
+ case NFT_MSG_NEWSETELEM:
+ case NFT_MSG_DELSETELEM:
+ return nft_trans_container_elem(trans)->nelems;
+ }
+
+ return 1;
+}
+
static void nf_tables_commit_audit_collect(struct list_head *adl,
- struct nft_table *table, u32 op)
+ const struct nft_trans *trans, u32 op)
{
+ const struct nft_table *table = trans->table;
struct nft_audit_data *adp;
list_for_each_entry(adp, adl, list) {
@@ -10244,7 +10530,7 @@ static void nf_tables_commit_audit_collect(struct list_head *adl,
WARN_ONCE(1, "table=%s not expected in commit list", table->name);
return;
found:
- adp->entries++;
+ adp->entries += nf_tables_commit_audit_entrycount(trans);
if (!adp->op || adp->op > op)
adp->op = op;
}
@@ -10403,7 +10689,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
nft_ctx_update(&ctx, trans);
- nf_tables_commit_audit_collect(&adl, table, trans->msg_type);
+ nf_tables_commit_audit_collect(&adl, trans, trans->msg_type);
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
@@ -10512,25 +10798,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_NEWSETELEM:
te = nft_trans_container_elem(trans);
- if (te->update_flags) {
- const struct nft_set_ext *ext =
- nft_set_elem_ext(te->set, te->elem_priv);
-
- if (te->update_flags & NFT_TRANS_UPD_TIMEOUT) {
- WRITE_ONCE(nft_set_ext_timeout(ext)->timeout,
- te->timeout);
- }
- if (te->update_flags & NFT_TRANS_UPD_EXPIRATION) {
- WRITE_ONCE(nft_set_ext_timeout(ext)->expiration,
- get_jiffies_64() + te->expiration);
- }
- } else {
- nft_setelem_activate(net, te->set, te->elem_priv);
- }
+ nft_trans_elems_add(&ctx, te);
- nf_tables_setelem_notify(&ctx, te->set,
- te->elem_priv,
- NFT_MSG_NEWSETELEM);
if (te->set->ops->commit &&
list_empty(&te->set->pending_update)) {
list_add_tail(&te->set->pending_update,
@@ -10542,14 +10811,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
case NFT_MSG_DESTROYSETELEM:
te = nft_trans_container_elem(trans);
- nf_tables_setelem_notify(&ctx, te->set,
- te->elem_priv,
- trans->msg_type);
- nft_setelem_remove(net, te->set, te->elem_priv);
- if (!nft_setelem_is_catchall(te->set, te->elem_priv)) {
- atomic_dec(&te->set->nelems);
- te->set->ndeact--;
- }
+ nft_trans_elems_remove(&ctx, te);
+
if (te->set->ops->commit &&
list_empty(&te->set->pending_update)) {
list_add_tail(&te->set->pending_update,
@@ -10669,8 +10932,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
nft_set_destroy(&ctx, nft_trans_set(trans));
break;
case NFT_MSG_NEWSETELEM:
- nft_set_elem_destroy(nft_trans_elem_set(trans),
- nft_trans_elem_priv(trans), true);
+ nft_trans_set_elem_destroy(&ctx, nft_trans_container_elem(trans));
break;
case NFT_MSG_NEWOBJ:
nft_obj_destroy(&ctx, nft_trans_obj(trans));
@@ -10827,18 +11089,15 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
nft_trans_destroy(trans);
break;
case NFT_MSG_NEWSETELEM:
- if (nft_trans_elem_update_flags(trans) ||
- nft_trans_elem_set_bound(trans)) {
+ if (nft_trans_elem_set_bound(trans)) {
nft_trans_destroy(trans);
break;
}
te = nft_trans_container_elem(trans);
- if (!te->set->ops->abort ||
- nft_setelem_is_catchall(te->set, te->elem_priv))
- nft_setelem_remove(net, te->set, te->elem_priv);
-
- if (!nft_setelem_is_catchall(te->set, te->elem_priv))
- atomic_dec(&te->set->nelems);
+ if (!nft_trans_elems_new_abort(&ctx, te)) {
+ nft_trans_destroy(trans);
+ break;
+ }
if (te->set->ops->abort &&
list_empty(&te->set->pending_update)) {
@@ -10850,12 +11109,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DESTROYSETELEM:
te = nft_trans_container_elem(trans);
- if (!nft_setelem_active_next(net, te->set, te->elem_priv)) {
- nft_setelem_data_activate(net, te->set, te->elem_priv);
- nft_setelem_activate(net, te->set, te->elem_priv);
- }
- if (!nft_setelem_is_catchall(te->set, te->elem_priv))
- te->set->ndeact--;
+ nft_trans_elems_destroy_abort(&ctx, te);
if (te->set->ops->abort &&
list_empty(&te->set->pending_update)) {
@@ -11430,22 +11684,48 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
}
EXPORT_SYMBOL_GPL(nft_data_dump);
-int __nft_release_basechain(struct nft_ctx *ctx)
+static void __nft_release_basechain_now(struct nft_ctx *ctx)
{
struct nft_rule *rule, *nr;
- if (WARN_ON(!nft_is_base_chain(ctx->chain)))
- return 0;
-
- nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list);
- nft_use_dec(&ctx->chain->use);
nf_tables_rule_release(ctx, rule);
}
+ nf_tables_chain_destroy(ctx->chain);
+}
+
+static void nft_release_basechain_rcu(struct rcu_head *head)
+{
+ struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
+ struct nft_ctx ctx = {
+ .family = chain->table->family,
+ .chain = chain,
+ .net = read_pnet(&chain->table->net),
+ };
+
+ __nft_release_basechain_now(&ctx);
+ put_net(ctx.net);
+}
+
+int __nft_release_basechain(struct nft_ctx *ctx)
+{
+ struct nft_rule *rule;
+
+ if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain)))
+ return 0;
+
+ nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
+ list_for_each_entry(rule, &ctx->chain->rules, list)
+ nft_use_dec(&ctx->chain->use);
+
nft_chain_del(ctx->chain);
nft_use_dec(&ctx->table->use);
- nf_tables_chain_destroy(ctx->chain);
+
+ if (maybe_get_net(ctx->net))
+ call_rcu(&ctx->chain->rcu_head, nft_release_basechain_rcu);
+ else
+ __nft_release_basechain_now(ctx);
return 0;
}
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 7784ec094097..e598a2a252b0 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -517,7 +517,7 @@ replay_abort:
err = nla_parse_deprecated(cda,
ss->cb[cb_id].attr_count,
attr, attrlen,
- ss->cb[cb_id].policy, NULL);
+ ss->cb[cb_id].policy, &extack);
if (err < 0)
goto ack;
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 7de95674fd8c..d550910aabec 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -17,6 +17,7 @@
struct nft_bitwise {
u8 sreg;
+ u8 sreg2;
u8 dreg;
enum nft_bitwise_ops op:8;
u8 len;
@@ -25,8 +26,8 @@ struct nft_bitwise {
struct nft_data data;
};
-static void nft_bitwise_eval_bool(u32 *dst, const u32 *src,
- const struct nft_bitwise *priv)
+static void nft_bitwise_eval_mask_xor(u32 *dst, const u32 *src,
+ const struct nft_bitwise *priv)
{
unsigned int i;
@@ -60,28 +61,72 @@ static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src,
}
}
+static void nft_bitwise_eval_and(u32 *dst, const u32 *src, const u32 *src2,
+ const struct nft_bitwise *priv)
+{
+ unsigned int i, n;
+
+ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++)
+ dst[i] = src[i] & src2[i];
+}
+
+static void nft_bitwise_eval_or(u32 *dst, const u32 *src, const u32 *src2,
+ const struct nft_bitwise *priv)
+{
+ unsigned int i, n;
+
+ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++)
+ dst[i] = src[i] | src2[i];
+}
+
+static void nft_bitwise_eval_xor(u32 *dst, const u32 *src, const u32 *src2,
+ const struct nft_bitwise *priv)
+{
+ unsigned int i, n;
+
+ for (i = 0, n = DIV_ROUND_UP(priv->len, sizeof(u32)); i < n; i++)
+ dst[i] = src[i] ^ src2[i];
+}
+
void nft_bitwise_eval(const struct nft_expr *expr,
struct nft_regs *regs, const struct nft_pktinfo *pkt)
{
const struct nft_bitwise *priv = nft_expr_priv(expr);
- const u32 *src = &regs->data[priv->sreg];
+ const u32 *src = &regs->data[priv->sreg], *src2;
u32 *dst = &regs->data[priv->dreg];
- switch (priv->op) {
- case NFT_BITWISE_BOOL:
- nft_bitwise_eval_bool(dst, src, priv);
- break;
- case NFT_BITWISE_LSHIFT:
+ if (priv->op == NFT_BITWISE_MASK_XOR) {
+ nft_bitwise_eval_mask_xor(dst, src, priv);
+ return;
+ }
+ if (priv->op == NFT_BITWISE_LSHIFT) {
nft_bitwise_eval_lshift(dst, src, priv);
- break;
- case NFT_BITWISE_RSHIFT:
+ return;
+ }
+ if (priv->op == NFT_BITWISE_RSHIFT) {
nft_bitwise_eval_rshift(dst, src, priv);
- break;
+ return;
+ }
+
+ src2 = priv->sreg2 ? &regs->data[priv->sreg2] : priv->data.data;
+
+ if (priv->op == NFT_BITWISE_AND) {
+ nft_bitwise_eval_and(dst, src, src2, priv);
+ return;
+ }
+ if (priv->op == NFT_BITWISE_OR) {
+ nft_bitwise_eval_or(dst, src, src2, priv);
+ return;
+ }
+ if (priv->op == NFT_BITWISE_XOR) {
+ nft_bitwise_eval_xor(dst, src, src2, priv);
+ return;
}
}
static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
[NFTA_BITWISE_SREG] = { .type = NLA_U32 },
+ [NFTA_BITWISE_SREG2] = { .type = NLA_U32 },
[NFTA_BITWISE_DREG] = { .type = NLA_U32 },
[NFTA_BITWISE_LEN] = { .type = NLA_U32 },
[NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
@@ -90,8 +135,8 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
[NFTA_BITWISE_DATA] = { .type = NLA_NESTED },
};
-static int nft_bitwise_init_bool(struct nft_bitwise *priv,
- const struct nlattr *const tb[])
+static int nft_bitwise_init_mask_xor(struct nft_bitwise *priv,
+ const struct nlattr *const tb[])
{
struct nft_data_desc mask = {
.type = NFT_DATA_VALUE,
@@ -105,7 +150,8 @@ static int nft_bitwise_init_bool(struct nft_bitwise *priv,
};
int err;
- if (tb[NFTA_BITWISE_DATA])
+ if (tb[NFTA_BITWISE_DATA] ||
+ tb[NFTA_BITWISE_SREG2])
return -EINVAL;
if (!tb[NFTA_BITWISE_MASK] ||
@@ -139,7 +185,8 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
int err;
if (tb[NFTA_BITWISE_MASK] ||
- tb[NFTA_BITWISE_XOR])
+ tb[NFTA_BITWISE_XOR] ||
+ tb[NFTA_BITWISE_SREG2])
return -EINVAL;
if (!tb[NFTA_BITWISE_DATA])
@@ -157,6 +204,41 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
return 0;
}
+static int nft_bitwise_init_bool(const struct nft_ctx *ctx,
+ struct nft_bitwise *priv,
+ const struct nlattr *const tb[])
+{
+ int err;
+
+ if (tb[NFTA_BITWISE_MASK] ||
+ tb[NFTA_BITWISE_XOR])
+ return -EINVAL;
+
+ if ((!tb[NFTA_BITWISE_DATA] && !tb[NFTA_BITWISE_SREG2]) ||
+ (tb[NFTA_BITWISE_DATA] && tb[NFTA_BITWISE_SREG2]))
+ return -EINVAL;
+
+ if (tb[NFTA_BITWISE_DATA]) {
+ struct nft_data_desc desc = {
+ .type = NFT_DATA_VALUE,
+ .size = sizeof(priv->data),
+ .len = priv->len,
+ };
+
+ err = nft_data_init(NULL, &priv->data, &desc,
+ tb[NFTA_BITWISE_DATA]);
+ if (err < 0)
+ return err;
+ } else {
+ err = nft_parse_register_load(ctx, tb[NFTA_BITWISE_SREG2],
+ &priv->sreg2, priv->len);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static int nft_bitwise_init(const struct nft_ctx *ctx,
const struct nft_expr *expr,
const struct nlattr * const tb[])
@@ -185,32 +267,40 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
if (tb[NFTA_BITWISE_OP]) {
priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP]));
switch (priv->op) {
- case NFT_BITWISE_BOOL:
+ case NFT_BITWISE_MASK_XOR:
case NFT_BITWISE_LSHIFT:
case NFT_BITWISE_RSHIFT:
+ case NFT_BITWISE_AND:
+ case NFT_BITWISE_OR:
+ case NFT_BITWISE_XOR:
break;
default:
return -EOPNOTSUPP;
}
} else {
- priv->op = NFT_BITWISE_BOOL;
+ priv->op = NFT_BITWISE_MASK_XOR;
}
switch(priv->op) {
- case NFT_BITWISE_BOOL:
- err = nft_bitwise_init_bool(priv, tb);
+ case NFT_BITWISE_MASK_XOR:
+ err = nft_bitwise_init_mask_xor(priv, tb);
break;
case NFT_BITWISE_LSHIFT:
case NFT_BITWISE_RSHIFT:
err = nft_bitwise_init_shift(priv, tb);
break;
+ case NFT_BITWISE_AND:
+ case NFT_BITWISE_OR:
+ case NFT_BITWISE_XOR:
+ err = nft_bitwise_init_bool(ctx, priv, tb);
+ break;
}
return err;
}
-static int nft_bitwise_dump_bool(struct sk_buff *skb,
- const struct nft_bitwise *priv)
+static int nft_bitwise_dump_mask_xor(struct sk_buff *skb,
+ const struct nft_bitwise *priv)
{
if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
NFT_DATA_VALUE, priv->len) < 0)
@@ -232,6 +322,21 @@ static int nft_bitwise_dump_shift(struct sk_buff *skb,
return 0;
}
+static int nft_bitwise_dump_bool(struct sk_buff *skb,
+ const struct nft_bitwise *priv)
+{
+ if (priv->sreg2) {
+ if (nft_dump_register(skb, NFTA_BITWISE_SREG2, priv->sreg2))
+ return -1;
+ } else {
+ if (nft_data_dump(skb, NFTA_BITWISE_DATA, &priv->data,
+ NFT_DATA_VALUE, sizeof(u32)) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
static int nft_bitwise_dump(struct sk_buff *skb,
const struct nft_expr *expr, bool reset)
{
@@ -248,13 +353,18 @@ static int nft_bitwise_dump(struct sk_buff *skb,
return -1;
switch (priv->op) {
- case NFT_BITWISE_BOOL:
- err = nft_bitwise_dump_bool(skb, priv);
+ case NFT_BITWISE_MASK_XOR:
+ err = nft_bitwise_dump_mask_xor(skb, priv);
break;
case NFT_BITWISE_LSHIFT:
case NFT_BITWISE_RSHIFT:
err = nft_bitwise_dump_shift(skb, priv);
break;
+ case NFT_BITWISE_AND:
+ case NFT_BITWISE_OR:
+ case NFT_BITWISE_XOR:
+ err = nft_bitwise_dump_bool(skb, priv);
+ break;
}
return err;
@@ -269,7 +379,7 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
const struct nft_bitwise *priv = nft_expr_priv(expr);
struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
- if (priv->op != NFT_BITWISE_BOOL)
+ if (priv->op != NFT_BITWISE_MASK_XOR)
return -EOPNOTSUPP;
if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
@@ -299,6 +409,7 @@ static bool nft_bitwise_reduce(struct nft_regs_track *track,
track->regs[priv->dreg].bitwise &&
track->regs[priv->dreg].bitwise->ops == expr->ops &&
priv->sreg == bitwise->sreg &&
+ priv->sreg2 == bitwise->sreg2 &&
priv->dreg == bitwise->dreg &&
priv->op == bitwise->op &&
priv->len == bitwise->len &&
@@ -375,7 +486,8 @@ static int nft_bitwise_fast_init(const struct nft_ctx *ctx,
if (err < 0)
return err;
- if (tb[NFTA_BITWISE_DATA])
+ if (tb[NFTA_BITWISE_DATA] ||
+ tb[NFTA_BITWISE_SREG2])
return -EINVAL;
if (!tb[NFTA_BITWISE_MASK] ||
@@ -406,7 +518,7 @@ nft_bitwise_fast_dump(struct sk_buff *skb,
return -1;
if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(sizeof(u32))))
return -1;
- if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_BOOL)))
+ if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_MASK_XOR)))
return -1;
data.data[0] = priv->mask;
@@ -501,7 +613,7 @@ nft_bitwise_select_ops(const struct nft_ctx *ctx,
return &nft_bitwise_ops;
if (tb[NFTA_BITWISE_OP] &&
- ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_BOOL)
+ ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_MASK_XOR)
return &nft_bitwise_ops;
return &nft_bitwise_fast_ops;
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 2f732fae5a83..3b474d235663 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -8,7 +8,7 @@
#include <linux/spinlock.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/nf_tables.h>
-#include <net/ip.h> /* for ipv4 options. */
+#include <net/ip.h>
#include <net/inet_dscp.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
@@ -236,7 +236,7 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip;
fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
fl.u.ip4.flowi4_iif = this_dst->dev->ifindex;
- fl.u.ip4.flowi4_tos = ip_hdr(pkt->skb)->tos & INET_DSCP_MASK;
+ fl.u.ip4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip_hdr(pkt->skb)));
fl.u.ip4.flowi4_mark = pkt->skb->mark;
fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC;
break;
@@ -409,8 +409,8 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx,
if (!tb[NFTA_FLOW_TABLE_NAME])
return -EINVAL;
- flowtable = nft_flowtable_lookup(ctx->table, tb[NFTA_FLOW_TABLE_NAME],
- genmask);
+ flowtable = nft_flowtable_lookup(ctx->net, ctx->table,
+ tb[NFTA_FLOW_TABLE_NAME], genmask);
if (IS_ERR(flowtable))
return PTR_ERR(flowtable);
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 330609a76fb2..7dfc5343dae4 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -904,6 +904,9 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER &&
priv->base != NFT_PAYLOAD_INNER_HEADER) ||
skb->ip_summed != CHECKSUM_PARTIAL)) {
+ if (offset + priv->len > skb->len)
+ goto err;
+
fsum = skb_checksum(skb, offset, priv->len, 0);
tsum = csum_partial(src, priv->len, 0);
diff --git a/net/netfilter/nft_set_bitmap.c b/net/netfilter/nft_set_bitmap.c
index 1caa04619dc6..12390d2e994f 100644
--- a/net/netfilter/nft_set_bitmap.c
+++ b/net/netfilter/nft_set_bitmap.c
@@ -88,13 +88,15 @@ bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
}
static struct nft_bitmap_elem *
-nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
+nft_bitmap_elem_find(const struct net *net,
+ const struct nft_set *set, struct nft_bitmap_elem *this,
u8 genmask)
{
const struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *be;
- list_for_each_entry_rcu(be, &priv->list, head) {
+ list_for_each_entry_rcu(be, &priv->list, head,
+ lockdep_is_held(&nft_pernet(net)->commit_mutex)) {
if (memcmp(nft_set_ext_key(&be->ext),
nft_set_ext_key(&this->ext), set->klen) ||
!nft_set_elem_active(&be->ext, genmask))
@@ -132,7 +134,7 @@ static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
u8 genmask = nft_genmask_next(net);
u32 idx, off;
- be = nft_bitmap_elem_find(set, new, genmask);
+ be = nft_bitmap_elem_find(net, set, new, genmask);
if (be) {
*elem_priv = &be->priv;
return -EEXIST;
@@ -201,7 +203,7 @@ nft_bitmap_deactivate(const struct net *net, const struct nft_set *set,
nft_bitmap_location(set, elem->key.val.data, &idx, &off);
- be = nft_bitmap_elem_find(set, this, genmask);
+ be = nft_bitmap_elem_find(net, set, this, genmask);
if (!be)
return NULL;
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index daa56dda737a..65bd291318f2 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -647,7 +647,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
int i;
for (i = 0; i < priv->buckets; i++) {
- hlist_for_each_entry_rcu(he, &priv->table[i], node) {
+ hlist_for_each_entry_rcu(he, &priv->table[i], node,
+ lockdep_is_held(&nft_pernet(ctx->net)->commit_mutex)) {
if (iter->count < iter->skip)
goto cont;
diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
index 5c6ed68cc6e0..681301b46aa4 100644
--- a/net/netfilter/nft_tunnel.c
+++ b/net/netfilter/nft_tunnel.c
@@ -497,10 +497,7 @@ static int nft_tunnel_obj_init(const struct nft_ctx *ctx,
}
if (tb[NFTA_TUNNEL_KEY_TOS])
info.key.tos = nla_get_u8(tb[NFTA_TUNNEL_KEY_TOS]);
- if (tb[NFTA_TUNNEL_KEY_TTL])
- info.key.ttl = nla_get_u8(tb[NFTA_TUNNEL_KEY_TTL]);
- else
- info.key.ttl = U8_MAX;
+ info.key.ttl = nla_get_u8_default(tb[NFTA_TUNNEL_KEY_TTL], U8_MAX);
if (tb[NFTA_TUNNEL_KEY_OPTS]) {
err = nft_tunnel_obj_opts_init(ctx, tb[NFTA_TUNNEL_KEY_OPTS],
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index da5d929c7c85..709840612f0d 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1269,7 +1269,7 @@ struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
/* and once again: */
list_for_each_entry(t, &xt_net->tables[af], list)
- if (strcmp(t->name, name) == 0)
+ if (strcmp(t->name, name) == 0 && owner == t->me)
return t;
module_put(owner);
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 689eaa2afbec..079fe72a6384 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -107,11 +107,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
switch (entry->def.type) {
case NETLBL_NLTYPE_UNLABELED:
- if (info->attrs[NLBL_MGMT_A_FAMILY])
- entry->family =
- nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
- else
- entry->family = AF_UNSPEC;
+ entry->family =
+ nla_get_u16_default(info->attrs[NLBL_MGMT_A_FAMILY],
+ AF_UNSPEC);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
@@ -601,10 +599,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
struct netlbl_dom_map *entry;
u16 family;
- if (info->attrs[NLBL_MGMT_A_FAMILY])
- family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
- else
- family = AF_INET;
+ family = nla_get_u16_default(info->attrs[NLBL_MGMT_A_FAMILY], AF_INET);
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (ans_skb == NULL)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 0a9287fadb47..8c78b29683a6 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -393,15 +393,6 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
static void netlink_sock_destruct(struct sock *sk)
{
- struct netlink_sock *nlk = nlk_sk(sk);
-
- if (nlk->cb_running) {
- if (nlk->cb.done)
- nlk->cb.done(&nlk->cb);
- module_put(nlk->cb.module);
- kfree_skb(nlk->cb.skb);
- }
-
skb_queue_purge(&sk->sk_receive_queue);
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -414,14 +405,6 @@ static void netlink_sock_destruct(struct sock *sk)
WARN_ON(nlk_sk(sk)->groups);
}
-static void netlink_sock_destruct_work(struct work_struct *work)
-{
- struct netlink_sock *nlk = container_of(work, struct netlink_sock,
- work);
-
- sk_free(&nlk->sk);
-}
-
/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
* SMP. Look, when several writers sleep and reader wakes them up, all but one
* immediately hit write lock and grab all the cpus. Exclusive sleep solves
@@ -731,12 +714,6 @@ static void deferred_put_nlk_sk(struct rcu_head *head)
if (!refcount_dec_and_test(&sk->sk_refcnt))
return;
- if (nlk->cb_running && nlk->cb.done) {
- INIT_WORK(&nlk->work, netlink_sock_destruct_work);
- schedule_work(&nlk->work);
- return;
- }
-
sk_free(sk);
}
@@ -788,6 +765,14 @@ static int netlink_release(struct socket *sock)
NETLINK_URELEASE, &n);
}
+ /* Terminate any outstanding dump */
+ if (nlk->cb_running) {
+ if (nlk->cb.done)
+ nlk->cb.done(&nlk->cb);
+ module_put(nlk->cb.module);
+ kfree_skb(nlk->cb.skb);
+ }
+
module_put(nlk->module);
if (netlink_is_kernel(sk)) {
@@ -2279,7 +2264,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
goto errout_skb;
/* NLMSG_GOODSIZE is small to avoid high order allocations being
- * required, but it makes sense to _attempt_ a 16K bytes allocation
+ * required, but it makes sense to _attempt_ a 32KiB allocation
* to reduce number of system calls on dump operations, if user
* ever provided a big enough buffer.
*/
@@ -2301,7 +2286,7 @@ static int netlink_dump(struct sock *sk, bool lock_taken)
goto errout_skb;
/* Trim skb to allocated size. User is expected to provide buffer as
- * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at
+ * large as max(min_dump_alloc, 32KiB (max_recvmsg_len capped at
* netlink_recvmsg())). dump will pack as many smaller messages as
* could fit within the allocated skb. skb is typically allocated
* with larger space than required (could be as much as near 2x the
@@ -2935,12 +2920,8 @@ static int __init netlink_proto_init(void)
for (i = 0; i < MAX_LINKS; i++) {
if (rhashtable_init(&nl_table[i].hash,
- &netlink_rhashtable_params) < 0) {
- while (--i > 0)
- rhashtable_destroy(&nl_table[i].hash);
- kfree(nl_table);
+ &netlink_rhashtable_params) < 0)
goto panic;
- }
}
netlink_add_usersock_entry();
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index 5b0e4e62ab8b..778a3809361f 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -4,7 +4,6 @@
#include <linux/rhashtable.h>
#include <linux/atomic.h>
-#include <linux/workqueue.h>
#include <net/sock.h>
/* flags */
@@ -50,7 +49,6 @@ struct netlink_sock {
struct rhash_head node;
struct rcu_head rcu;
- struct work_struct work;
};
static inline struct netlink_sock *nlk_sk(struct sock *sk)
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index f456a5911e7d..1ec5955fe469 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -757,6 +757,14 @@ int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id)
}
EXPORT_SYMBOL(nci_core_conn_close);
+static void nci_set_target_ats(struct nfc_target *target, struct nci_dev *ndev)
+{
+ if (ndev->target_ats_len > 0) {
+ target->ats_len = ndev->target_ats_len;
+ memcpy(target->ats, ndev->target_ats, target->ats_len);
+ }
+}
+
static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
@@ -939,8 +947,11 @@ static int nci_activate_target(struct nfc_dev *nfc_dev,
msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
}
- if (!rc)
+ if (!rc) {
ndev->target_active_prot = protocol;
+ if (protocol == NFC_PROTO_ISO14443)
+ nci_set_target_ats(target, ndev);
+ }
return rc;
}
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 994a0a1efb58..a818eff27e6b 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -402,7 +402,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
switch (ntf->activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
- nfca_poll->rats_res_len = min_t(__u8, *data++, 20);
+ nfca_poll->rats_res_len = min_t(__u8, *data++, NFC_ATS_MAXSIZE);
pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
if (nfca_poll->rats_res_len > 0) {
memcpy(nfca_poll->rats_res,
@@ -531,6 +531,28 @@ static int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev,
return NCI_STATUS_OK;
}
+static int nci_store_ats_nfc_iso_dep(struct nci_dev *ndev,
+ const struct nci_rf_intf_activated_ntf *ntf)
+{
+ ndev->target_ats_len = 0;
+
+ if (ntf->activation_params_len <= 0)
+ return NCI_STATUS_OK;
+
+ if (ntf->activation_params.nfca_poll_iso_dep.rats_res_len > NFC_ATS_MAXSIZE) {
+ pr_debug("ATS too long\n");
+ return NCI_STATUS_RF_PROTOCOL_ERROR;
+ }
+
+ if (ntf->activation_params.nfca_poll_iso_dep.rats_res_len > 0) {
+ ndev->target_ats_len = ntf->activation_params.nfca_poll_iso_dep.rats_res_len;
+ memcpy(ndev->target_ats, ntf->activation_params.nfca_poll_iso_dep.rats_res,
+ ndev->target_ats_len);
+ }
+
+ return NCI_STATUS_OK;
+}
+
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
const struct sk_buff *skb)
{
@@ -660,6 +682,14 @@ exit:
if (err != NCI_STATUS_OK)
pr_err("unable to store general bytes\n");
}
+
+ /* store ATS to be reported later in nci_activate_target */
+ if (ntf.rf_interface == NCI_RF_INTERFACE_ISO_DEP &&
+ ntf.activation_rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) {
+ err = nci_store_ats_nfc_iso_dep(ndev, &ntf);
+ if (err != NCI_STATUS_OK)
+ pr_err("unable to store ATS\n");
+ }
}
if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) {
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index dd2ce73a24fb..6a40b8d0350d 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -96,6 +96,11 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
goto nla_put_failure;
}
+ if (target->ats_len > 0 &&
+ nla_put(msg, NFC_ATTR_TARGET_ATS, target->ats_len,
+ target->ats))
+ goto nla_put_failure;
+
genlmsg_end(msg, hdr);
return 0;
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 78d9961fcd44..225f6048867f 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1828,8 +1828,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
parms.dp = dp;
parms.port_no = OVSP_LOCAL;
parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
- parms.desired_ifindex = a[OVS_DP_ATTR_IFINDEX]
- ? nla_get_s32(a[OVS_DP_ATTR_IFINDEX]) : 0;
+ parms.desired_ifindex = nla_get_s32_default(a[OVS_DP_ATTR_IFINDEX], 0);
/* So far only local changes have been made, now need the lock. */
ovs_lock();
@@ -2266,8 +2265,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (a[OVS_VPORT_ATTR_IFINDEX] && parms.type != OVS_VPORT_TYPE_INTERNAL)
return -EOPNOTSUPP;
- port_no = a[OVS_VPORT_ATTR_PORT_NO]
- ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
+ port_no = nla_get_u32_default(a[OVS_VPORT_ATTR_PORT_NO], 0);
if (port_no >= DP_MAX_PORTS)
return -EFBIG;
@@ -2304,8 +2302,8 @@ restart:
parms.dp = dp;
parms.port_no = port_no;
parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
- parms.desired_ifindex = a[OVS_VPORT_ATTR_IFINDEX]
- ? nla_get_s32(a[OVS_VPORT_ATTR_IFINDEX]) : 0;
+ parms.desired_ifindex = nla_get_s32_default(a[OVS_VPORT_ATTR_IFINDEX],
+ 0);
vport = new_vport(&parms);
err = PTR_ERR(vport);
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 729ef582a3a8..881ddd3696d5 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -1938,7 +1938,7 @@ int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
{
- return attr ? nla_get_u32(attr) : 0;
+ return nla_get_u32_default(attr, 0);
}
/**
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 5858d65ea1a9..2412d7813d24 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -195,7 +195,6 @@ static int internal_dev_recv(struct sk_buff *skb)
skb_dst_drop(skb);
nf_reset_ct(skb);
- secpath_reset(skb);
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, netdev);
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 19234d664c4f..5c36bae37b8f 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -406,8 +406,9 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
if (!dev)
return -ENOENT;
- synchronize_rcu();
- dev_put(dev);
+
+ /* Note : our caller must call synchronize_rcu() and dev_put(dev) */
+
return 0;
}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index ca1f04e4a2d9..b9043c92dc24 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -233,6 +233,7 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[RTA_MAX+1];
+ bool sync_needed = false;
struct net_device *dev;
struct rtmsg *rtm;
u32 ifindex;
@@ -269,13 +270,20 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
return -ENODEV;
}
- if (nlh->nlmsg_type == RTM_NEWROUTE)
+ if (nlh->nlmsg_type == RTM_NEWROUTE) {
err = phonet_route_add(dev, dst);
- else
+ } else {
err = phonet_route_del(dev, dst);
+ if (!err)
+ sync_needed = true;
+ }
rcu_read_unlock();
+ if (sync_needed) {
+ synchronize_rcu();
+ dev_put(dev);
+ }
if (!err)
rtm_phonet_notify(net, nlh->nlmsg_type, ifindex, dst);
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index c268c2b011f4..a8e21060112f 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -32,8 +32,12 @@ static int rfkill_gpio_set_power(void *data, bool blocked)
{
struct rfkill_gpio_data *rfkill = data;
- if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled)
- clk_enable(rfkill->clk);
+ if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled) {
+ int ret = clk_enable(rfkill->clk);
+
+ if (ret)
+ return ret;
+ }
gpiod_set_value_cansleep(rfkill->shutdown_gpio, !blocked);
gpiod_set_value_cansleep(rfkill->reset_gpio, !blocked);
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index d25bf1cf3670..bb11e8289d6d 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -516,6 +516,7 @@ void rxrpc_connect_client_calls(struct rxrpc_local *local)
spin_lock(&local->client_call_lock);
list_move_tail(&call->wait_link, &bundle->waiting_calls);
+ rxrpc_see_call(call, rxrpc_call_see_waiting_call);
spin_unlock(&local->client_call_lock);
if (rxrpc_bundle_has_space(bundle))
@@ -586,7 +587,10 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
_debug("call is waiting");
ASSERTCMP(call->call_id, ==, 0);
ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags));
+ /* May still be on ->new_client_calls. */
+ spin_lock(&local->client_call_lock);
list_del_init(&call->wait_link);
+ spin_unlock(&local->client_call_lock);
return;
}
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 1539d315afe7..694c4df7a1a3 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -337,9 +337,7 @@ static void rxrpc_clean_up_connection(struct work_struct *work)
*/
rxrpc_purge_queue(&conn->rx_queue);
- if (conn->tx_data_alloc.va)
- __page_frag_cache_drain(virt_to_page(conn->tx_data_alloc.va),
- conn->tx_data_alloc.pagecnt_bias);
+ page_frag_cache_drain(&conn->tx_data_alloc);
call_rcu(&conn->rcu, rxrpc_rcu_free_connection);
}
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c
index f9623ace2201..2792d2304605 100644
--- a/net/rxrpc/local_object.c
+++ b/net/rxrpc/local_object.c
@@ -452,9 +452,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
#endif
rxrpc_purge_queue(&local->rx_queue);
rxrpc_purge_client_connections(local);
- if (local->tx_alloc.va)
- __page_frag_cache_drain(virt_to_page(local->tx_alloc.va),
- local->tx_alloc.pagecnt_bias);
+ page_frag_cache_drain(&local->tx_alloc);
}
/*
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index 23d18fe5de9f..6abb8eec1b2b 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -29,6 +29,7 @@ bool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error,
call->send_abort_why = why;
call->send_abort_err = error;
call->send_abort_seq = 0;
+ trace_rxrpc_abort_call(call, abort_code);
/* Request abort locklessly vs rxrpc_input_call_event(). */
smp_store_release(&call->send_abort, abort_code);
rxrpc_poke_call(call, rxrpc_call_poke_abort);
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index 2197eb625658..c02f39efc6ef 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -1183,9 +1183,8 @@ static int tcf_ct_fill_params_nat(struct tcf_ct_params *p,
range->min_addr.ip =
nla_get_in_addr(tb[TCA_CT_NAT_IPV4_MIN]);
- range->max_addr.ip = max_attr ?
- nla_get_in_addr(max_attr) :
- range->min_addr.ip;
+ range->max_addr.ip =
+ nla_get_in_addr_default(max_attr, range->min_addr.ip);
} else if (tb[TCA_CT_NAT_IPV6_MIN]) {
struct nlattr *max_attr = tb[TCA_CT_NAT_IPV6_MAX];
@@ -1314,8 +1313,9 @@ static int tcf_ct_fill_params(struct net *net,
err = -EINVAL;
goto err;
}
- family = tb[TCA_CT_HELPER_FAMILY] ? nla_get_u8(tb[TCA_CT_HELPER_FAMILY]) : AF_INET;
- proto = tb[TCA_CT_HELPER_PROTO] ? nla_get_u8(tb[TCA_CT_HELPER_PROTO]) : IPPROTO_TCP;
+ family = nla_get_u8_default(tb[TCA_CT_HELPER_FAMILY], AF_INET);
+ proto = nla_get_u8_default(tb[TCA_CT_HELPER_PROTO],
+ IPPROTO_TCP);
err = nf_ct_add_helper(tmpl, name, family, proto,
p->ct_action & TCA_CT_ACT_NAT, &p->helper);
if (err) {
diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c
index 5dd41a012110..5b1241ddc758 100644
--- a/net/sched/act_ctinfo.c
+++ b/net/sched/act_ctinfo.c
@@ -197,8 +197,9 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
"dscp mask must be 6 contiguous bits");
return -EINVAL;
}
- dscpstatemask = tb[TCA_CTINFO_PARMS_DSCP_STATEMASK] ?
- nla_get_u32(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) : 0;
+ dscpstatemask =
+ nla_get_u32_default(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK],
+ 0);
/* mask & statemask must not overlap */
if (dscpmask & dscpstatemask) {
NL_SET_ERR_MSG_ATTR(extack,
@@ -243,8 +244,7 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
}
cp_new->net = net;
- cp_new->zone = tb[TCA_CTINFO_ZONE] ?
- nla_get_u16(tb[TCA_CTINFO_ZONE]) : 0;
+ cp_new->zone = nla_get_u16_default(tb[TCA_CTINFO_ZONE], 0);
if (dscpmask) {
cp_new->dscpmask = dscpmask;
cp_new->dscpmaskshift = dscpmaskshift;
diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c
index 1dd74125398a..91c0ec729823 100644
--- a/net/sched/act_gate.c
+++ b/net/sched/act_gate.c
@@ -190,15 +190,10 @@ static int fill_gate_entry(struct nlattr **tb, struct tcfg_gate_entry *entry,
entry->interval = interval;
- if (tb[TCA_GATE_ENTRY_IPV])
- entry->ipv = nla_get_s32(tb[TCA_GATE_ENTRY_IPV]);
- else
- entry->ipv = -1;
+ entry->ipv = nla_get_s32_default(tb[TCA_GATE_ENTRY_IPV], -1);
- if (tb[TCA_GATE_ENTRY_MAX_OCTETS])
- entry->maxoctets = nla_get_s32(tb[TCA_GATE_ENTRY_MAX_OCTETS]);
- else
- entry->maxoctets = -1;
+ entry->maxoctets = nla_get_s32_default(tb[TCA_GATE_ENTRY_MAX_OCTETS],
+ -1);
return 0;
}
diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
index 44a37a71ae92..9f86f4e666d3 100644
--- a/net/sched/act_mpls.c
+++ b/net/sched/act_mpls.c
@@ -288,16 +288,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
}
p->tcfm_action = parm->m_action;
- p->tcfm_label = tb[TCA_MPLS_LABEL] ? nla_get_u32(tb[TCA_MPLS_LABEL]) :
- ACT_MPLS_LABEL_NOT_SET;
- p->tcfm_tc = tb[TCA_MPLS_TC] ? nla_get_u8(tb[TCA_MPLS_TC]) :
- ACT_MPLS_TC_NOT_SET;
- p->tcfm_ttl = tb[TCA_MPLS_TTL] ? nla_get_u8(tb[TCA_MPLS_TTL]) :
- mpls_ttl;
- p->tcfm_bos = tb[TCA_MPLS_BOS] ? nla_get_u8(tb[TCA_MPLS_BOS]) :
- ACT_MPLS_BOS_NOT_SET;
- p->tcfm_proto = tb[TCA_MPLS_PROTO] ? nla_get_be16(tb[TCA_MPLS_PROTO]) :
- htons(ETH_P_MPLS_UC);
+ p->tcfm_label = nla_get_u32_default(tb[TCA_MPLS_LABEL],
+ ACT_MPLS_LABEL_NOT_SET);
+ p->tcfm_tc = nla_get_u8_default(tb[TCA_MPLS_TC], ACT_MPLS_TC_NOT_SET);
+ p->tcfm_ttl = nla_get_u8_default(tb[TCA_MPLS_TTL], mpls_ttl);
+ p->tcfm_bos = nla_get_u8_default(tb[TCA_MPLS_BOS],
+ ACT_MPLS_BOS_NOT_SET);
+ p->tcfm_proto = nla_get_be16_default(tb[TCA_MPLS_PROTO],
+ htons(ETH_P_MPLS_UC));
spin_lock_bh(&m->tcf_lock);
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 8555125ed34d..a214ed681142 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -167,8 +167,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
}
if (R_tab) {
new->rate_present = true;
- rate64 = tb[TCA_POLICE_RATE64] ?
- nla_get_u64(tb[TCA_POLICE_RATE64]) : 0;
+ rate64 = nla_get_u64_default(tb[TCA_POLICE_RATE64], 0);
psched_ratecfg_precompute(&new->rate, &R_tab->rate, rate64);
qdisc_put_rtab(R_tab);
} else {
@@ -176,8 +175,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
}
if (P_tab) {
new->peak_present = true;
- prate64 = tb[TCA_POLICE_PEAKRATE64] ?
- nla_get_u64(tb[TCA_POLICE_PEAKRATE64]) : 0;
+ prate64 = nla_get_u64_default(tb[TCA_POLICE_PEAKRATE64], 0);
psched_ratecfg_precompute(&new->peak, &P_tab->rate, prate64);
qdisc_put_rtab(P_tab);
} else {
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 7637f979d689..7578e27260c9 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1518,6 +1518,7 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
return 0;
err_dev_insert:
+ tcf_block_offload_unbind(block, q, ei);
err_block_offload_bind:
tcf_chain0_head_change_cb_del(block, ei);
err_chain0_head_change_cb_add:
@@ -1932,7 +1933,8 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain,
static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
u32 protocol, u32 prio,
- bool prio_allocate);
+ bool prio_allocate,
+ struct netlink_ext_ack *extack);
/* Try to insert new proto.
* If proto with specified priority already exists, free new proto
@@ -1956,8 +1958,7 @@ static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
return ERR_PTR(-EAGAIN);
}
- tp = tcf_chain_tp_find(chain, &chain_info,
- protocol, prio, false);
+ tp = tcf_chain_tp_find(chain, &chain_info, protocol, prio, false, NULL);
if (!tp)
err = tcf_chain_tp_insert(chain, &chain_info, tp_new);
mutex_unlock(&chain->filter_chain_lock);
@@ -2017,7 +2018,8 @@ static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
u32 protocol, u32 prio,
- bool prio_allocate)
+ bool prio_allocate,
+ struct netlink_ext_ack *extack)
{
struct tcf_proto **pprev;
struct tcf_proto *tp;
@@ -2028,9 +2030,14 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
pprev = &tp->next) {
if (tp->prio >= prio) {
if (tp->prio == prio) {
- if (prio_allocate ||
- (tp->protocol != protocol && protocol))
+ if (prio_allocate) {
+ NL_SET_ERR_MSG(extack, "Lowest ID from auto-alloc range already in use");
+ return ERR_PTR(-ENOSPC);
+ }
+ if (tp->protocol != protocol && protocol) {
+ NL_SET_ERR_MSG(extack, "Protocol mismatch for filter with specified priority");
return ERR_PTR(-EINVAL);
+ }
} else {
tp = NULL;
}
@@ -2296,7 +2303,7 @@ replay:
}
block->classid = parent;
- chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
+ chain_index = nla_get_u32_default(tca[TCA_CHAIN], 0);
if (chain_index > TC_ACT_EXT_VAL_MASK) {
NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
err = -EINVAL;
@@ -2311,9 +2318,8 @@ replay:
mutex_lock(&chain->filter_chain_lock);
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
- prio, prio_allocate);
+ prio, prio_allocate, extack);
if (IS_ERR(tp)) {
- NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
err = PTR_ERR(tp);
goto errout_locked;
}
@@ -2508,7 +2514,7 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
goto errout;
}
- chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
+ chain_index = nla_get_u32_default(tca[TCA_CHAIN], 0);
if (chain_index > TC_ACT_EXT_VAL_MASK) {
NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
err = -EINVAL;
@@ -2538,10 +2544,13 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
mutex_lock(&chain->filter_chain_lock);
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
- prio, false);
- if (!tp || IS_ERR(tp)) {
+ prio, false, extack);
+ if (!tp) {
+ err = -ENOENT;
NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
- err = tp ? PTR_ERR(tp) : -ENOENT;
+ goto errout_locked;
+ } else if (IS_ERR(tp)) {
+ err = PTR_ERR(tp);
goto errout_locked;
} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
@@ -2663,7 +2672,7 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
goto errout;
}
- chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
+ chain_index = nla_get_u32_default(tca[TCA_CHAIN], 0);
if (chain_index > TC_ACT_EXT_VAL_MASK) {
NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
err = -EINVAL;
@@ -2678,11 +2687,14 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
mutex_lock(&chain->filter_chain_lock);
tp = tcf_chain_tp_find(chain, &chain_info, protocol,
- prio, false);
+ prio, false, extack);
mutex_unlock(&chain->filter_chain_lock);
- if (!tp || IS_ERR(tp)) {
+ if (!tp) {
+ err = -ENOENT;
NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
- err = tp ? PTR_ERR(tp) : -ENOENT;
+ goto errout;
+ } else if (IS_ERR(tp)) {
+ err = PTR_ERR(tp);
goto errout;
} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
@@ -3103,7 +3115,7 @@ replay:
if (IS_ERR(block))
return PTR_ERR(block);
- chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
+ chain_index = nla_get_u32_default(tca[TCA_CHAIN], 0);
if (chain_index > TC_ACT_EXT_VAL_MASK) {
NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
err = -EINVAL;
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 9412d88a99bc..d3a03c57545b 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -92,6 +92,16 @@ struct tc_u_common {
long knodes;
};
+static u32 handle2id(u32 h)
+{
+ return ((h & 0x80000000) ? ((h >> 20) & 0x7FF) : h);
+}
+
+static u32 id2handle(u32 id)
+{
+ return (id | 0x800U) << 20;
+}
+
static inline unsigned int u32_hash_fold(__be32 key,
const struct tc_u32_sel *sel,
u8 fshift)
@@ -310,7 +320,7 @@ static u32 gen_new_htid(struct tc_u_common *tp_c, struct tc_u_hnode *ptr)
int id = idr_alloc_cyclic(&tp_c->handle_idr, ptr, 1, 0x7FF, GFP_KERNEL);
if (id < 0)
return 0;
- return (id | 0x800U) << 20;
+ return id2handle(id);
}
static struct hlist_head *tc_u_common_hash;
@@ -360,7 +370,7 @@ static int u32_init(struct tcf_proto *tp)
return -ENOBUFS;
refcount_set(&root_ht->refcnt, 1);
- root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : 0x80000000;
+ root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : id2handle(0);
root_ht->prio = tp->prio;
root_ht->is_root = true;
idr_init(&root_ht->handle_idr);
@@ -612,7 +622,7 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
if (phn == ht) {
u32_clear_hw_hnode(tp, ht, extack);
idr_destroy(&ht->handle_idr);
- idr_remove(&tp_c->handle_idr, ht->handle);
+ idr_remove(&tp_c->handle_idr, handle2id(ht->handle));
RCU_INIT_POINTER(*hn, ht->next);
kfree_rcu(ht, rcu);
return 0;
@@ -989,7 +999,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
err = u32_replace_hw_hnode(tp, ht, userflags, extack);
if (err) {
- idr_remove(&tp_c->handle_idr, handle);
+ idr_remove(&tp_c->handle_idr, handle2id(handle));
kfree(ht);
return err;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index da2da2ab858b..300430b8c4d2 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -791,7 +791,7 @@ void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
drops = max_t(int, n, 0);
rcu_read_lock();
while ((parentid = sch->parent)) {
- if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
+ if (parentid == TC_H_ROOT)
break;
if (sch->flags & TCQ_F_NOPARENT)
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index 91072010923d..1e940ad0d2fa 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -356,7 +356,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt,
tb[TCA_CHOKE_STAB] == NULL)
return -EINVAL;
- max_P = tb[TCA_CHOKE_MAX_P] ? nla_get_u32(tb[TCA_CHOKE_MAX_P]) : 0;
+ max_P = nla_get_u32_default(tb[TCA_CHOKE_MAX_P], 0);
ctl = nla_data(tb[TCA_CHOKE_PARMS]);
stab = nla_data(tb[TCA_CHOKE_STAB]);
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 79ba9dc70254..7d2151c62c4a 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -668,7 +668,7 @@ static int gred_change(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL;
}
- max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0;
+ max_P = nla_get_u32_default(tb[TCA_GRED_MAX_P], 0);
ctl = nla_data(tb[TCA_GRED_PARMS]);
stab = nla_data(tb[TCA_GRED_STAB]);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index ff3de37874e4..c31bc5489bdd 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1810,8 +1810,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB],
NULL));
- rate64 = tb[TCA_HTB_RATE64] ? nla_get_u64(tb[TCA_HTB_RATE64]) : 0;
- ceil64 = tb[TCA_HTB_CEIL64] ? nla_get_u64(tb[TCA_HTB_CEIL64]) : 0;
+ rate64 = nla_get_u64_default(tb[TCA_HTB_RATE64], 0);
+ ceil64 = nla_get_u64_default(tb[TCA_HTB_CEIL64], 0);
if (!cl) { /* new class */
struct net_device *dev = qdisc_dev(sch);
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index d584c0c25899..6a07cdbdb9e1 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -421,10 +421,7 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (err < 0)
return err;
- if (tb[TCA_QFQ_WEIGHT])
- weight = nla_get_u32(tb[TCA_QFQ_WEIGHT]);
- else
- weight = 1;
+ weight = nla_get_u32_default(tb[TCA_QFQ_WEIGHT], 1);
if (tb[TCA_QFQ_LMAX]) {
lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index b5f096588fae..6029bc29b51e 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -248,7 +248,7 @@ static int __red_change(struct Qdisc *sch, struct nlattr **tb,
tb[TCA_RED_STAB] == NULL)
return -EINVAL;
- max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0;
+ max_P = nla_get_u32_default(tb[TCA_RED_MAX_P], 0);
ctl = nla_data(tb[TCA_RED_PARMS]);
stab = nla_data(tb[TCA_RED_STAB]);
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 8623dc0bafc0..a68e17891b0b 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -1828,7 +1828,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
* zero; (2) the 'flags' of a "running" taprio instance cannot be
* changed.
*/
- taprio_flags = tb[TCA_TAPRIO_ATTR_FLAGS] ? nla_get_u32(tb[TCA_TAPRIO_ATTR_FLAGS]) : 0;
+ taprio_flags = nla_get_u32_default(tb[TCA_TAPRIO_ATTR_FLAGS], 0);
/* txtime-assist and full offload are mutually exclusive */
if ((taprio_flags & TCA_TAPRIO_ATTR_FLAG_TXTIME_ASSIST) &&
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index f7b809c0d142..a9ed2ccab1bd 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -103,10 +103,10 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
ipv6_addr_equal(&addr->a.v6.sin6_addr,
&ifa->addr) &&
addr->a.v6.sin6_scope_id == ifa->idev->dev->ifindex) {
- sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
+ sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
break;
}
}
@@ -683,7 +683,7 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
struct sock *sk = &sp->inet.sk;
struct net *net = sock_net(sk);
struct net_device *dev = NULL;
- int type;
+ int type, res, bound_dev_if;
type = ipv6_addr_type(in6);
if (IPV6_ADDR_ANY == type)
@@ -697,14 +697,21 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
if (!(type & IPV6_ADDR_UNICAST))
return 0;
- if (sk->sk_bound_dev_if) {
- dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
+ rcu_read_lock();
+ bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
+ if (bound_dev_if) {
+ res = 0;
+ dev = dev_get_by_index_rcu(net, bound_dev_if);
if (!dev)
- return 0;
+ goto out;
}
- return ipv6_can_nonlocal_bind(net, &sp->inet) ||
- ipv6_chk_addr(net, in6, dev, 0);
+ res = ipv6_can_nonlocal_bind(net, &sp->inet) ||
+ ipv6_chk_addr(net, in6, dev, 0);
+
+out:
+ rcu_read_unlock();
+ return res;
}
/* This function checks if the address is a valid address to be used for
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 39ca5403d4d7..8b9a1b96695e 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -738,6 +738,20 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
*/
spin_lock_bh(&net->sctp.addr_wq_lock);
+
+ /* Avoid searching the queue or modifying it if there are no consumers,
+ * as it can lead to performance degradation if addresses are modified
+ * en-masse.
+ *
+ * If the queue already contains some events, update it anyway to avoid
+ * ugly races between new sessions and new address events.
+ */
+ if (list_empty(&net->sctp.auto_asconf_splist) &&
+ list_empty(&net->sctp.addr_waitq)) {
+ spin_unlock_bh(&net->sctp.addr_wq_lock);
+ return;
+ }
+
/* Offsets existing events in addr_wq */
addrw = sctp_addr_wq_lookup(net, addr);
if (addrw) {
@@ -808,10 +822,10 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
if (addr->a.sa.sa_family == AF_INET &&
addr->a.v4.sin_addr.s_addr ==
ifa->ifa_local) {
- sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
+ sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
break;
}
}
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 7d315a18612b..a0524ba8d787 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3751,7 +3751,7 @@ enum sctp_disposition sctp_sf_ootb(struct net *net,
}
ch = (struct sctp_chunkhdr *)ch_end;
- } while (ch_end < skb_tail_pointer(skb));
+ } while (ch_end + sizeof(*ch) < skb_tail_pointer(skb));
if (ootb_shut_ack)
return sctp_sf_shut_8_4_5(net, ep, asoc, type, arg, commands);
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 0316217b7687..9d76e902fd77 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -3359,8 +3359,10 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol,
else
rc = smc_create_clcsk(net, sk, family);
- if (rc)
+ if (rc) {
sk_common_release(sk);
+ sock->sk = NULL;
+ }
out:
return rc;
}
diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c
index 9297dc20bfe2..9c563cdbea90 100644
--- a/net/smc/smc_ib.c
+++ b/net/smc/smc_ib.c
@@ -899,9 +899,7 @@ static void smc_copy_netdev_ifindex(struct smc_ib_device *smcibdev, int port)
struct ib_device *ibdev = smcibdev->ibdev;
struct net_device *ndev;
- if (!ibdev->ops.get_netdev)
- return;
- ndev = ibdev->ops.get_netdev(ibdev, port + 1);
+ ndev = ib_device_get_netdev(ibdev, port + 1);
if (ndev) {
smcibdev->ndev_ifidx[port] = ndev->ifindex;
dev_put(ndev);
@@ -921,9 +919,7 @@ void smc_ib_ndev_change(struct net_device *ndev, unsigned long event)
port_cnt = smcibdev->ibdev->phys_port_cnt;
for (i = 0; i < min_t(size_t, port_cnt, SMC_MAX_PORTS); i++) {
libdev = smcibdev->ibdev;
- if (!libdev->ops.get_netdev)
- continue;
- lndev = libdev->ops.get_netdev(libdev, i + 1);
+ lndev = ib_device_get_netdev(libdev, i + 1);
dev_put(lndev);
if (lndev != ndev)
continue;
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index a04aa0e882f8..716808f374a8 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -1054,9 +1054,7 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev,
for (i = 1; i <= SMC_MAX_PORTS; i++) {
if (!rdma_is_port_valid(ibdev->ibdev, i))
continue;
- if (!ibdev->ibdev->ops.get_netdev)
- continue;
- ndev = ibdev->ibdev->ops.get_netdev(ibdev->ibdev, i);
+ ndev = ib_device_get_netdev(ibdev->ibdev, i);
if (!ndev)
continue;
dev_put(ndev);
diff --git a/net/socket.c b/net/socket.c
index 9a8e4452b9b2..5fb3d265e492 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1578,7 +1578,9 @@ int __sock_create(struct net *net, int family, int type, int protocol,
/* ->create should release the allocated sock->sk object on error
* and make sure sock->sk is set to NULL to avoid use-after-free
*/
- DEBUG_NET_WARN_ON_ONCE(sock->sk);
+ DEBUG_NET_WARN_ONCE(sock->sk,
+ "%ps must clear sock->sk on failure, family: %d, type: %d, protocol: %d\n",
+ pf->create, family, type, protocol);
goto out_module_put;
}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 825ec5357691..b785425c3315 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1608,7 +1608,6 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt)
static void svc_sock_free(struct svc_xprt *xprt)
{
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
- struct page_frag_cache *pfc = &svsk->sk_frag_cache;
struct socket *sock = svsk->sk_sock;
trace_svcsock_free(svsk, sock);
@@ -1618,8 +1617,7 @@ static void svc_sock_free(struct svc_xprt *xprt)
sockfd_put(sock);
else
sock_release(sock);
- if (pfc->va)
- __page_frag_cache_drain(virt_to_head_page(pfc->va),
- pfc->pagecnt_bias);
+
+ page_frag_cache_drain(&svsk->sk_frag_cache);
kfree(svsk);
}
diff --git a/net/sunrpc/xprtrdma/ib_client.c b/net/sunrpc/xprtrdma/ib_client.c
index 8507cd4d8921..28c68b5f6823 100644
--- a/net/sunrpc/xprtrdma/ib_client.c
+++ b/net/sunrpc/xprtrdma/ib_client.c
@@ -153,6 +153,7 @@ static void rpcrdma_remove_one(struct ib_device *device,
}
trace_rpcrdma_client_remove_one_done(device);
+ xa_destroy(&rd->rd_xa);
kfree(rd);
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 0e1691316f42..1326fbf45a34 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2459,6 +2459,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
case -EHOSTUNREACH:
case -EADDRINUSE:
case -ENOBUFS:
+ case -ENOTCONN:
break;
default:
printk("%s: connect returned unhandled error %d\n",
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 109b7a0bd071..25b28b1434f5 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -836,6 +836,9 @@ static void vsock_sk_destruct(struct sock *sk)
{
struct vsock_sock *vsk = vsock_sk(sk);
+ /* Flush MSG_ZEROCOPY leftovers. */
+ __skb_queue_purge(&sk->sk_error_queue);
+
vsock_deassign_transport(vsk);
/* When clearing these addresses, there's no need to set the family and
diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index e2157e387217..56c232cf5b0f 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -549,6 +549,7 @@ static void hvs_destruct(struct vsock_sock *vsk)
vmbus_hvsock_device_unregister(chan);
kfree(hvs);
+ vsk->trans = NULL;
}
static int hvs_dgram_bind(struct vsock_sock *vsk, struct sockaddr_vm *addr)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index ccbd2bc0d210..9acc13ab3f82 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -400,6 +400,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
if (virtio_transport_init_zcopy_skb(vsk, skb,
info->msg,
can_zcopy)) {
+ kfree_skb(skb);
ret = -ENOMEM;
break;
}
@@ -1109,6 +1110,7 @@ void virtio_transport_destruct(struct vsock_sock *vsk)
struct virtio_vsock_sock *vvs = vsk->trans;
kfree(vvs);
+ vsk->trans = NULL;
}
EXPORT_SYMBOL_GPL(virtio_transport_destruct);
@@ -1512,6 +1514,14 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
return -ENOMEM;
}
+ /* __vsock_release() might have already flushed accept_queue.
+ * Subsequent enqueues would lead to a memory leak.
+ */
+ if (sk->sk_shutdown == SHUTDOWN_MASK) {
+ virtio_transport_reset_no_sock(t, skb);
+ return -ESHUTDOWN;
+ }
+
child = vsock_create_connected(sk);
if (!child) {
virtio_transport_reset_no_sock(t, skb);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 10345388ad13..2d67b5f2010e 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -11,9 +11,6 @@ config WEXT_PROC
depends on PROC_FS
depends on WEXT_CORE
-config WEXT_SPY
- bool
-
config WEXT_PRIV
bool
@@ -188,19 +185,12 @@ config CFG80211_CRDA_SUPPORT
If unsure, say Y.
config CFG80211_WEXT
- bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT
+ bool "cfg80211 wireless extensions compatibility"
select WEXT_CORE
- default y if CFG80211_WEXT_EXPORT
help
Enable this option if you need old userspace for wireless
extensions with cfg80211-based drivers.
-config CFG80211_WEXT_EXPORT
- bool
- help
- Drivers should select this option if they require cfg80211's
- wext compatibility symbols to be exported.
-
config CFG80211_KUNIT_TEST
tristate "KUnit tests for cfg80211" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -212,36 +202,3 @@ config CFG80211_KUNIT_TEST
If unsure, say N.
endif # CFG80211
-
-config LIB80211
- tristate
- default n
- help
- This options enables a library of common routines used
- by IEEE802.11 wireless LAN drivers.
-
- Drivers should select this themselves if needed.
-
-config LIB80211_CRYPT_WEP
- tristate
- select CRYPTO_LIB_ARC4
-
-config LIB80211_CRYPT_CCMP
- tristate
- select CRYPTO
- select CRYPTO_AES
- select CRYPTO_CCM
-
-config LIB80211_CRYPT_TKIP
- tristate
- select CRYPTO_LIB_ARC4
-
-config LIB80211_DEBUG
- bool "lib80211 debugging messages"
- depends on LIB80211
- default n
- help
- You can enable this if you want verbose debugging messages
- from lib80211.
-
- If unsure, say N.
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 1d49cc8b6da1..62a83faf0e07 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,14 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CFG80211) += cfg80211.o
-obj-$(CONFIG_LIB80211) += lib80211.o
-obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
-obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
-obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
obj-y += tests/
obj-$(CONFIG_WEXT_CORE) += wext-core.o
obj-$(CONFIG_WEXT_PROC) += wext-proc.o
-obj-$(CONFIG_WEXT_SPY) += wext-spy.o
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index e579d7e1425f..40b6375a5de4 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -289,7 +289,7 @@ static bool cfg80211_valid_center_freq(u32 center,
/*
* Valid channels are packed from lowest frequency towards higher ones.
- * So test that the lower frequency alignes with one of these steps.
+ * So test that the lower frequency aligns with one of these steps.
*/
return (center - bw / 2 - 5945) % step == 0;
}
@@ -1628,6 +1628,7 @@ bool cfg80211_reg_check_beaconing(struct wiphy *wiphy,
EXPORT_SYMBOL(cfg80211_reg_check_beaconing);
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
if (!rdev->ops->set_monitor_channel)
@@ -1635,7 +1636,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
if (!cfg80211_has_monitors_only(rdev))
return -EBUSY;
- return rdev_set_monitor_channel(rdev, chandef);
+ return rdev_set_monitor_channel(rdev, dev, chandef);
}
bool cfg80211_any_usable_channels(struct wiphy *wiphy,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 661adfc77644..afbdc549fb4a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -603,16 +603,20 @@ use_default_name:
}
EXPORT_SYMBOL(wiphy_new_nm);
-static int wiphy_verify_combinations(struct wiphy *wiphy)
+static
+int wiphy_verify_iface_combinations(struct wiphy *wiphy,
+ const struct ieee80211_iface_combination *iface_comb,
+ int n_iface_comb,
+ bool combined_radio)
{
const struct ieee80211_iface_combination *c;
int i, j;
- for (i = 0; i < wiphy->n_iface_combinations; i++) {
+ for (i = 0; i < n_iface_comb; i++) {
u32 cnt = 0;
u16 all_iftypes = 0;
- c = &wiphy->iface_combinations[i];
+ c = &iface_comb[i];
/*
* Combinations with just one interface aren't real,
@@ -625,9 +629,13 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
if (WARN_ON(!c->num_different_channels))
return -EINVAL;
- /* DFS only works on one channel. */
- if (WARN_ON(c->radar_detect_widths &&
- (c->num_different_channels > 1)))
+ /* DFS only works on one channel. Avoid this check
+ * for multi-radio global combination, since it hold
+ * the capabilities of all radio combinations.
+ */
+ if (!combined_radio &&
+ WARN_ON(c->radar_detect_widths &&
+ c->num_different_channels > 1))
return -EINVAL;
if (WARN_ON(!c->n_limits))
@@ -648,13 +656,21 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
if (WARN_ON(wiphy->software_iftypes & types))
return -EINVAL;
- /* Only a single P2P_DEVICE can be allowed */
- if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
+ /* Only a single P2P_DEVICE can be allowed, avoid this
+ * check for multi-radio global combination, since it
+ * hold the capabilities of all radio combinations.
+ */
+ if (!combined_radio &&
+ WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
c->limits[j].max > 1))
return -EINVAL;
- /* Only a single NAN can be allowed */
- if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
+ /* Only a single NAN can be allowed, avoid this
+ * check for multi-radio global combination, since it
+ * hold the capabilities of all radio combinations.
+ */
+ if (!combined_radio &&
+ WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
c->limits[j].max > 1))
return -EINVAL;
@@ -693,6 +709,34 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
return 0;
}
+static int wiphy_verify_combinations(struct wiphy *wiphy)
+{
+ int i, ret;
+ bool combined_radio = false;
+
+ if (wiphy->n_radio) {
+ for (i = 0; i < wiphy->n_radio; i++) {
+ const struct wiphy_radio *radio = &wiphy->radio[i];
+
+ ret = wiphy_verify_iface_combinations(wiphy,
+ radio->iface_combinations,
+ radio->n_iface_combinations,
+ false);
+ if (ret)
+ return ret;
+ }
+
+ combined_radio = true;
+ }
+
+ ret = wiphy_verify_iface_combinations(wiphy,
+ wiphy->iface_combinations,
+ wiphy->n_iface_combinations,
+ combined_radio);
+
+ return ret;
+}
+
int wiphy_register(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -1236,6 +1280,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
/* deleted from the list, so can't be found from nl80211 any more */
cqm_config = rcu_access_pointer(wdev->cqm_config);
kfree_rcu(cqm_config, rcu_head);
+ RCU_INIT_POINTER(wdev->cqm_config, NULL);
/*
* Ensure that all events have been processed and
@@ -1386,6 +1431,8 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
/* allow mac80211 to determine the timeout */
wdev->ps_timeout = -1;
+ wdev->radio_mask = BIT(wdev->wiphy->n_radio) - 1;
+
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
@@ -1704,6 +1751,13 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy,
}
EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush);
+bool wiphy_delayed_work_pending(struct wiphy *wiphy,
+ struct wiphy_delayed_work *dwork)
+{
+ return timer_pending(&dwork->timer);
+}
+EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending);
+
static int __init cfg80211_init(void)
{
int err;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3b3e3cd7027a..4c45f994a8c0 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -516,6 +516,7 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
}
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef);
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c
deleted file mode 100644
index 64c447040786..000000000000
--- a/net/wireless/lib80211.c
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lib80211 -- common bits for IEEE802.11 drivers
- *
- * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com>
- *
- * Portions copied from old ieee80211 component, w/ original copyright
- * notices below:
- *
- * Host AP crypto routines
- *
- * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
- * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/ieee80211.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <net/lib80211.h>
-
-#define DRV_DESCRIPTION "common routines for IEEE802.11 drivers"
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR("John W. Linville <linville@tuxdriver.com>");
-MODULE_LICENSE("GPL");
-
-struct lib80211_crypto_alg {
- struct list_head list;
- const struct lib80211_crypto_ops *ops;
-};
-
-static LIST_HEAD(lib80211_crypto_algs);
-static DEFINE_SPINLOCK(lib80211_crypto_lock);
-
-static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
- int force);
-static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
-static void lib80211_crypt_deinit_handler(struct timer_list *t);
-
-int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
- spinlock_t *lock)
-{
- memset(info, 0, sizeof(*info));
-
- info->name = name;
- info->lock = lock;
-
- INIT_LIST_HEAD(&info->crypt_deinit_list);
- timer_setup(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler,
- 0);
-
- return 0;
-}
-EXPORT_SYMBOL(lib80211_crypt_info_init);
-
-void lib80211_crypt_info_free(struct lib80211_crypt_info *info)
-{
- int i;
-
- lib80211_crypt_quiescing(info);
- del_timer_sync(&info->crypt_deinit_timer);
- lib80211_crypt_deinit_entries(info, 1);
-
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- struct lib80211_crypt_data *crypt = info->crypt[i];
- if (crypt) {
- if (crypt->ops) {
- crypt->ops->deinit(crypt->priv);
- module_put(crypt->ops->owner);
- }
- kfree(crypt);
- info->crypt[i] = NULL;
- }
- }
-}
-EXPORT_SYMBOL(lib80211_crypt_info_free);
-
-static void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info,
- int force)
-{
- struct lib80211_crypt_data *entry, *next;
- unsigned long flags;
-
- spin_lock_irqsave(info->lock, flags);
- list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) {
- if (atomic_read(&entry->refcnt) != 0 && !force)
- continue;
-
- list_del(&entry->list);
-
- if (entry->ops) {
- entry->ops->deinit(entry->priv);
- module_put(entry->ops->owner);
- }
- kfree(entry);
- }
- spin_unlock_irqrestore(info->lock, flags);
-}
-
-/* After this, crypt_deinit_list won't accept new members */
-static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info)
-{
- unsigned long flags;
-
- spin_lock_irqsave(info->lock, flags);
- info->crypt_quiesced = 1;
- spin_unlock_irqrestore(info->lock, flags);
-}
-
-static void lib80211_crypt_deinit_handler(struct timer_list *t)
-{
- struct lib80211_crypt_info *info = from_timer(info, t,
- crypt_deinit_timer);
- unsigned long flags;
-
- lib80211_crypt_deinit_entries(info, 0);
-
- spin_lock_irqsave(info->lock, flags);
- if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) {
- printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
- "deletion list\n", info->name);
- info->crypt_deinit_timer.expires = jiffies + HZ;
- add_timer(&info->crypt_deinit_timer);
- }
- spin_unlock_irqrestore(info->lock, flags);
-}
-
-void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info,
- struct lib80211_crypt_data **crypt)
-{
- struct lib80211_crypt_data *tmp;
- unsigned long flags;
-
- if (*crypt == NULL)
- return;
-
- tmp = *crypt;
- *crypt = NULL;
-
- /* must not run ops->deinit() while there may be pending encrypt or
- * decrypt operations. Use a list of delayed deinits to avoid needing
- * locking. */
-
- spin_lock_irqsave(info->lock, flags);
- if (!info->crypt_quiesced) {
- list_add(&tmp->list, &info->crypt_deinit_list);
- if (!timer_pending(&info->crypt_deinit_timer)) {
- info->crypt_deinit_timer.expires = jiffies + HZ;
- add_timer(&info->crypt_deinit_timer);
- }
- }
- spin_unlock_irqrestore(info->lock, flags);
-}
-EXPORT_SYMBOL(lib80211_crypt_delayed_deinit);
-
-int lib80211_register_crypto_ops(const struct lib80211_crypto_ops *ops)
-{
- unsigned long flags;
- struct lib80211_crypto_alg *alg;
-
- alg = kzalloc(sizeof(*alg), GFP_KERNEL);
- if (alg == NULL)
- return -ENOMEM;
-
- alg->ops = ops;
-
- spin_lock_irqsave(&lib80211_crypto_lock, flags);
- list_add(&alg->list, &lib80211_crypto_algs);
- spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
-
- printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
- ops->name);
-
- return 0;
-}
-EXPORT_SYMBOL(lib80211_register_crypto_ops);
-
-int lib80211_unregister_crypto_ops(const struct lib80211_crypto_ops *ops)
-{
- struct lib80211_crypto_alg *alg;
- unsigned long flags;
-
- spin_lock_irqsave(&lib80211_crypto_lock, flags);
- list_for_each_entry(alg, &lib80211_crypto_algs, list) {
- if (alg->ops == ops)
- goto found;
- }
- spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
- return -EINVAL;
-
- found:
- printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n",
- ops->name);
- list_del(&alg->list);
- spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
- kfree(alg);
- return 0;
-}
-EXPORT_SYMBOL(lib80211_unregister_crypto_ops);
-
-const struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name)
-{
- struct lib80211_crypto_alg *alg;
- unsigned long flags;
-
- spin_lock_irqsave(&lib80211_crypto_lock, flags);
- list_for_each_entry(alg, &lib80211_crypto_algs, list) {
- if (strcmp(alg->ops->name, name) == 0)
- goto found;
- }
- spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
- return NULL;
-
- found:
- spin_unlock_irqrestore(&lib80211_crypto_lock, flags);
- return alg->ops;
-}
-EXPORT_SYMBOL(lib80211_get_crypto_ops);
-
-static void *lib80211_crypt_null_init(int keyidx)
-{
- return (void *)1;
-}
-
-static void lib80211_crypt_null_deinit(void *priv)
-{
-}
-
-static const struct lib80211_crypto_ops lib80211_crypt_null = {
- .name = "NULL",
- .init = lib80211_crypt_null_init,
- .deinit = lib80211_crypt_null_deinit,
- .owner = THIS_MODULE,
-};
-
-static int __init lib80211_init(void)
-{
- pr_info(DRV_DESCRIPTION "\n");
- return lib80211_register_crypto_ops(&lib80211_crypt_null);
-}
-
-static void __exit lib80211_exit(void)
-{
- lib80211_unregister_crypto_ops(&lib80211_crypt_null);
- BUG_ON(!list_empty(&lib80211_crypto_algs));
-}
-
-module_init(lib80211_init);
-module_exit(lib80211_exit);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 4dac81854721..a5eb92d93074 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -340,12 +340,6 @@ cfg80211_mlme_check_mlo_compat(const struct ieee80211_multi_link_elem *mle_a,
return -EINVAL;
}
- if (ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_a) !=
- ieee80211_mle_get_eml_med_sync_delay((const u8 *)mle_b)) {
- NL_SET_ERR_MSG(extack, "link EML medium sync delay mismatch");
- return -EINVAL;
- }
-
if (ieee80211_mle_get_eml_cap((const u8 *)mle_a) !=
ieee80211_mle_get_eml_cap((const u8 *)mle_b)) {
NL_SET_ERR_MSG(extack, "link EML capabilities mismatch");
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d7d099f7118a..9d2edb71f981 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -829,6 +829,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
+ [NL80211_ATTR_VIF_RADIO_MASK] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -1285,10 +1286,7 @@ static unsigned int nl80211_link_id(struct nlattr **attrs)
{
struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID];
- if (!linkid)
- return 0;
-
- return nla_get_u8(linkid);
+ return nla_get_u8_default(linkid, 0);
}
static int nl80211_link_id_or_invalid(struct nlattr **attrs)
@@ -2430,6 +2428,11 @@ static int nl80211_put_radio(struct wiphy *wiphy, struct sk_buff *msg, int idx)
if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx))
goto nla_put_failure;
+ if (r->antenna_mask &&
+ nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
+ r->antenna_mask))
+ goto nla_put_failure;
+
for (i = 0; i < r->n_freq_range; i++) {
const struct wiphy_radio_freq_range *range = &r->freq_range[i];
@@ -3408,11 +3411,9 @@ static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
if (attrs[NL80211_ATTR_CENTER_FREQ1]) {
chandef->center_freq1 =
nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1]);
- if (attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET])
- chandef->freq1_offset = nla_get_u32(
- attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET]);
- else
- chandef->freq1_offset = 0;
+ chandef->freq1_offset =
+ nla_get_u32_default(attrs[NL80211_ATTR_CENTER_FREQ1_OFFSET],
+ 0);
}
if (attrs[NL80211_ATTR_CENTER_FREQ2])
chandef->center_freq2 =
@@ -3561,7 +3562,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT:
return cfg80211_set_mesh_channel(rdev, wdev, &chandef);
case NL80211_IFTYPE_MONITOR:
- return cfg80211_set_monitor_channel(rdev, &chandef);
+ return cfg80211_set_monitor_channel(rdev, dev, &chandef);
default:
break;
}
@@ -3996,7 +3997,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
nla_put_u32(msg, NL80211_ATTR_GENERATION,
rdev->devlist_generation ^
(cfg80211_rdev_list_generation << 2)) ||
- nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
+ nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr) ||
+ nla_put_u32(msg, NL80211_ATTR_VIF_RADIO_MASK, wdev->radio_mask))
goto nla_put_failure;
if (rdev->ops->get_channel && !wdev->valid_links) {
@@ -4199,6 +4201,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_SKIP_TX] = { .type = NLA_FLAG },
};
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
@@ -4312,6 +4315,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
return -EOPNOTSUPP;
}
+static int nl80211_parse_vif_radio_mask(struct genl_info *info,
+ u32 *radio_mask)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct nlattr *attr = info->attrs[NL80211_ATTR_VIF_RADIO_MASK];
+ u32 mask, allowed;
+
+ if (!attr) {
+ *radio_mask = 0;
+ return 0;
+ }
+
+ allowed = BIT(rdev->wiphy.n_radio) - 1;
+ mask = nla_get_u32(attr);
+ if (mask & ~allowed)
+ return -EINVAL;
+ if (!mask)
+ mask = allowed;
+ *radio_mask = mask;
+
+ return 1;
+}
+
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4319,6 +4345,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
int err;
enum nl80211_iftype otype, ntype;
struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ u32 radio_mask = 0;
bool change = false;
memset(&params, 0, sizeof(params));
@@ -4332,8 +4360,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_MESH_ID]) {
- struct wireless_dev *wdev = dev->ieee80211_ptr;
-
if (ntype != NL80211_IFTYPE_MESH_POINT)
return -EINVAL;
if (otype != NL80211_IFTYPE_MESH_POINT)
@@ -4364,6 +4390,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (err > 0)
change = true;
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
+ if (err < 0)
+ return err;
+ if (err && netif_running(dev))
+ return -EBUSY;
+
if (change)
err = cfg80211_change_iface(rdev, dev, ntype, &params);
else
@@ -4372,11 +4404,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (!err && params.use_4addr != -1)
dev->ieee80211_ptr->use_4addr = params.use_4addr;
- if (change && !err) {
- struct wireless_dev *wdev = dev->ieee80211_ptr;
+ if (radio_mask)
+ wdev->radio_mask = radio_mask;
+ if (change && !err)
nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
- }
return err;
}
@@ -4387,6 +4419,7 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
struct vif_params params;
struct wireless_dev *wdev;
struct sk_buff *msg;
+ u32 radio_mask;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -4424,6 +4457,10 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
if (err < 0)
return err;
+ err = nl80211_parse_vif_radio_mask(info, &radio_mask);
+ if (err < 0)
+ return err;
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
@@ -4465,6 +4502,9 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
break;
}
+ if (radio_mask)
+ wdev->radio_mask = radio_mask;
+
if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
nlmsg_free(msg);
@@ -6078,6 +6118,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_BEACON_HEAD])
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_SMPS_MODE] &&
+ nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]) != NL80211_SMPS_OFF)
+ return -EOPNOTSUPP;
+
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
@@ -6227,34 +6271,6 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
- params->smps_mode =
- nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
- switch (params->smps_mode) {
- case NL80211_SMPS_OFF:
- break;
- case NL80211_SMPS_STATIC:
- if (!(rdev->wiphy.features &
- NL80211_FEATURE_STATIC_SMPS)) {
- err = -EINVAL;
- goto out;
- }
- break;
- case NL80211_SMPS_DYNAMIC:
- if (!(rdev->wiphy.features &
- NL80211_FEATURE_DYNAMIC_SMPS)) {
- err = -EINVAL;
- goto out;
- }
- break;
- default:
- err = -EINVAL;
- goto out;
- }
- } else {
- params->smps_mode = NL80211_SMPS_OFF;
- }
-
params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
err = -EOPNOTSUPP;
@@ -8244,11 +8260,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
return -EINPROGRESS;
- if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
- user_reg_hint_type =
- nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
- else
- user_reg_hint_type = NL80211_USER_REG_HINT_USER;
+ user_reg_hint_type =
+ nla_get_u32_default(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE],
+ NL80211_USER_REG_HINT_USER);
switch (user_reg_hint_type) {
case NL80211_USER_REG_HINT_USER:
@@ -9180,6 +9194,9 @@ static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev,
lockdep_assert_wiphy(wdev->wiphy);
+ if (!cfg80211_wdev_channel_allowed(wdev, chan))
+ return false;
+
if (!cfg80211_beaconing_iface_active(wdev))
return true;
@@ -9392,7 +9409,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
/* ignore disabled channels */
- if (chan->flags & IEEE80211_CHAN_DISABLED)
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
+ !cfg80211_wdev_channel_allowed(wdev, chan))
continue;
request->channels[i] = chan;
@@ -9412,7 +9430,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
chan = &wiphy->bands[band]->channels[j];
- if (chan->flags & IEEE80211_CHAN_DISABLED)
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
+ !cfg80211_wdev_channel_allowed(wdev, chan))
continue;
request->channels[i] = chan;
@@ -9776,6 +9795,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
request = kzalloc(size, GFP_KERNEL);
if (!request)
return ERR_PTR(-ENOMEM);
+ request->n_channels = n_channels;
if (n_ssids)
request->ssids = (void *)request +
@@ -11061,11 +11081,9 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
nla_len(info->attrs[NL80211_ATTR_SAE_PASSWORD]);
}
- if (info->attrs[NL80211_ATTR_SAE_PWE])
- settings->sae_pwe =
- nla_get_u8(info->attrs[NL80211_ATTR_SAE_PWE]);
- else
- settings->sae_pwe = NL80211_SAE_PWE_UNSPECIFIED;
+ settings->sae_pwe =
+ nla_get_u8_default(info->attrs[NL80211_ATTR_SAE_PWE],
+ NL80211_SAE_PWE_UNSPECIFIED);
return 0;
}
@@ -12321,10 +12339,8 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid)
return -EPERM;
- if (!info->attrs[NL80211_ATTR_REASON_CODE])
- reason = WLAN_REASON_DEAUTH_LEAVING;
- else
- reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+ reason = nla_get_u16_default(info->attrs[NL80211_ATTR_REASON_CODE],
+ WLAN_REASON_DEAUTH_LEAVING);
if (reason == 0)
return -EINVAL;
@@ -12446,7 +12462,7 @@ static int nl80211_del_pmksa(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) {
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
} else if (info->attrs[NL80211_ATTR_SSID]) {
- /* SSID based pmksa flush suppported only for FILS,
+ /* SSID based pmksa flush supported only for FILS,
* OWE/SAE OFFLOAD cases
*/
if (info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
@@ -13670,10 +13686,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
ETH_ALEN);
- if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
- port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]);
- else
- port = 0;
+ port = nla_get_u16_default(tb[NL80211_WOWLAN_TCP_SRC_PORT], 0);
#ifdef CONFIG_INET
/* allocate a socket and port for it and use it */
err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM,
@@ -13884,11 +13897,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
pat_len < wowlan->pattern_min_len)
goto error;
- if (!pat_tb[NL80211_PKTPAT_OFFSET])
- pkt_offset = 0;
- else
- pkt_offset = nla_get_u32(
- pat_tb[NL80211_PKTPAT_OFFSET]);
+ pkt_offset =
+ nla_get_u32_default(pat_tb[NL80211_PKTPAT_OFFSET],
+ 0);
if (pkt_offset > wowlan->max_pkt_offset)
goto error;
new_triggers.patterns[i].pkt_offset = pkt_offset;
@@ -14061,8 +14072,6 @@ void cfg80211_free_coalesce(struct cfg80211_coalesce *coalesce)
for (i = 0; i < coalesce->n_rules; i++) {
rule = &coalesce->rules[i];
- if (!rule)
- continue;
for (j = 0; j < rule->n_patterns; j++)
kfree(rule->patterns[j].mask);
kfree(rule->patterns);
@@ -14134,10 +14143,8 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
pat_len < coalesce->pattern_min_len)
return -EINVAL;
- if (!pat_tb[NL80211_PKTPAT_OFFSET])
- pkt_offset = 0;
- else
- pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
+ pkt_offset = nla_get_u32_default(pat_tb[NL80211_PKTPAT_OFFSET],
+ 0);
if (pkt_offset > coalesce->max_pkt_offset)
return -EINVAL;
new_rule->patterns[i].pkt_offset = pkt_offset;
@@ -15498,7 +15505,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
/* TODO: handle 802.11 TSPEC/admission control
* need more attributes for that (e.g. BA session requirement);
- * change the WMM adminssion test above to allow both then
+ * change the WMM admission test above to allow both then
*/
return -EINVAL;
}
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index b7e3e46ec16d..326faea38ca3 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -200,7 +200,7 @@ static void find_ns(struct ieee80211_radiotap_iterator *iterator,
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
- * little-endian format whatever the endianess of your CPU.
+ * little-endian format whatever the endianness of your CPU.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index f5adbf6b5c84..adb6105bbb7d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -445,11 +445,12 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,
static inline int
rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
struct cfg80211_chan_def *chandef)
{
int ret;
- trace_rdev_set_monitor_channel(&rdev->wiphy, chandef);
- ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef);
+ trace_rdev_set_monitor_channel(&rdev->wiphy, dev, chandef);
+ ret = rdev->ops->set_monitor_channel(&rdev->wiphy, dev, chandef);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6489ba943a63..1df65a5a44f7 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1147,7 +1147,7 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
/*
* Follow the driver's regulatory domain, if present, unless a country
- * IE has been processed or a user wants to help complaince further
+ * IE has been processed or a user wants to help compliance further
*/
if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
lr->initiator != NL80211_REGDOM_SET_BY_USER &&
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 59a90bf3c0d6..1c6fd45aa809 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -956,7 +956,8 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
struct ieee80211_channel *chan =
ieee80211_get_channel(&rdev->wiphy, ap->center_freq);
- if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED ||
+ !cfg80211_wdev_channel_allowed(rdev_req->wdev, chan))
continue;
for (i = 0; i < rdev_req->n_channels; i++) {
@@ -3050,6 +3051,10 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy,
freq = ieee80211_channel_to_freq_khz(ap_info->channel, band);
data.channel = ieee80211_get_channel_khz(wiphy, freq);
+ /* Skip if RNR element specifies an unsupported channel */
+ if (!data.channel)
+ continue;
+
/* Skip if BSS entry generated from MBSSID or DIRECT source
* frame data available already.
*/
@@ -3515,9 +3520,12 @@ int cfg80211_wext_siwscan(struct net_device *dev,
continue;
for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+ struct ieee80211_channel *chan;
+
/* ignore disabled channels */
- if (wiphy->bands[band]->channels[j].flags &
- IEEE80211_CHAN_DISABLED)
+ chan = &wiphy->bands[band]->channels[j];
+ if (chan->flags & IEEE80211_CHAN_DISABLED ||
+ !cfg80211_wdev_channel_allowed(creq->wdev, chan))
continue;
/* If we have a wireless request structure and the
@@ -3594,7 +3602,6 @@ int cfg80211_wext_siwscan(struct net_device *dev,
kfree(creq);
return err;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
static char *ieee80211_scan_add_ies(struct iw_request_info *info,
const struct cfg80211_bss_ies *ies,
@@ -3966,5 +3973,4 @@ int cfg80211_wext_giwscan(struct net_device *dev,
return res;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan);
#endif
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 97c21b627791..d5c9bb614fa6 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1318,19 +1318,21 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel,
);
TRACE_EVENT(rdev_set_monitor_channel,
- TP_PROTO(struct wiphy *wiphy,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_chan_def *chandef),
- TP_ARGS(wiphy, chandef),
+ TP_ARGS(wiphy, netdev, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
+ NETDEV_ENTRY
CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
),
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
);
TRACE_EVENT(rdev_auth,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index f49b55724f83..040d62051eb9 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -743,7 +743,7 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
return NULL;
/*
- * When reusing framents, copy some data to the head to simplify
+ * When reusing fragments, copy some data to the head to simplify
* ethernet header handling and speed up protocol header processing
* in the stack later.
*/
@@ -2923,3 +2923,32 @@ bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
return true;
}
EXPORT_SYMBOL(cfg80211_radio_chandef_valid);
+
+bool cfg80211_wdev_channel_allowed(struct wireless_dev *wdev,
+ struct ieee80211_channel *chan)
+{
+ struct wiphy *wiphy = wdev->wiphy;
+ const struct wiphy_radio *radio;
+ struct cfg80211_chan_def chandef;
+ u32 radio_mask;
+ int i;
+
+ radio_mask = wdev->radio_mask;
+ if (!wiphy->n_radio || radio_mask == BIT(wiphy->n_radio) - 1)
+ return true;
+
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
+ for (i = 0; i < wiphy->n_radio; i++) {
+ if (!(radio_mask & BIT(i)))
+ continue;
+
+ radio = &wiphy->radio[i];
+ if (!cfg80211_radio_chandef_valid(radio, &chandef))
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(cfg80211_wdev_channel_allowed);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 2371069f3c43..90d5c0592667 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -30,7 +30,6 @@ int cfg80211_wext_giwname(struct net_device *dev,
strcpy(wrqu->name, "IEEE 802.11");
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -69,7 +68,6 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
return ret;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -105,7 +103,6 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
}
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode);
int cfg80211_wext_giwrange(struct net_device *dev,
@@ -220,7 +217,6 @@ int cfg80211_wext_giwrange(struct net_device *dev,
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange);
/**
@@ -281,7 +277,6 @@ out:
wiphy_unlock(&rdev->wiphy);
return err;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
int cfg80211_wext_giwrts(struct net_device *dev,
struct iw_request_info *info,
@@ -296,7 +291,6 @@ int cfg80211_wext_giwrts(struct net_device *dev,
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts);
int cfg80211_wext_siwfrag(struct net_device *dev,
struct iw_request_info *info,
@@ -327,7 +321,6 @@ out:
return err;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag);
int cfg80211_wext_giwfrag(struct net_device *dev,
struct iw_request_info *info,
@@ -342,7 +335,6 @@ int cfg80211_wext_giwfrag(struct net_device *dev,
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag);
static int cfg80211_wext_siwretry(struct net_device *dev,
struct iw_request_info *info,
@@ -413,7 +405,6 @@ int cfg80211_wext_giwretry(struct net_device *dev,
return 0;
}
-EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry);
static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool pairwise,
@@ -830,7 +821,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
ret = -EINVAL;
break;
}
- ret = cfg80211_set_monitor_channel(rdev, &chandef);
+ ret = cfg80211_set_monitor_channel(rdev, dev, &chandef);
break;
case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wextfreq);
@@ -1204,7 +1195,7 @@ static int cfg80211_wext_siwpower(struct net_device *dev,
switch (wrq->flags & IW_POWER_MODE) {
case IW_POWER_ON: /* If not specified */
case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitely state all */
+ case IW_POWER_ALL_R: /* If explicitly state all */
ps = true;
break;
default: /* Otherwise we ignore */
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h
index c02eb789e676..8251ca5df8ae 100644
--- a/net/wireless/wext-compat.h
+++ b/net/wireless/wext-compat.h
@@ -5,12 +5,6 @@
#include <net/iw_handler.h>
#include <linux/wireless.h>
-#ifdef CONFIG_CFG80211_WEXT_EXPORT
-#define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h)
-#else
-#define EXPORT_WEXT_HANDLER(h)
-#endif /* CONFIG_CFG80211_WEXT_EXPORT */
-
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *wextfreq, char *extra);
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 838ad6541a17..3bb04b05c5ce 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -1159,7 +1159,7 @@ char *iwe_stream_add_event(struct iw_request_info *info, char *stream,
/* Check if it's possible */
if (likely((stream + event_len) < ends)) {
iwe->len = event_len;
- /* Beware of alignement issues on 64 bits */
+ /* Beware of alignment issues on 64 bits */
memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
memcpy(stream + lcp_len, &iwe->u,
event_len - lcp_len);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 6b0800c7c75e..b2876e09328b 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -200,7 +200,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
struct netlink_ext_ack *extack)
{
int err;
- u8 sa_dir = attrs[XFRMA_SA_DIR] ? nla_get_u8(attrs[XFRMA_SA_DIR]) : 0;
+ u8 sa_dir = nla_get_u8_default(attrs[XFRMA_SA_DIR], 0);
u16 family = p->sel.family;
err = -EINVAL;
@@ -773,10 +773,8 @@ static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m)
{
if (attrs[XFRMA_SET_MARK]) {
m->v = nla_get_u32(attrs[XFRMA_SET_MARK]);
- if (attrs[XFRMA_SET_MARK_MASK])
- m->m = nla_get_u32(attrs[XFRMA_SET_MARK_MASK]);
- else
- m->m = 0xffffffff;
+ m->m = nla_get_u32_default(attrs[XFRMA_SET_MARK_MASK],
+ 0xffffffff);
} else {
m->v = m->m = 0;
}
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index f847e832ba14..57565dfd74a2 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -60,6 +60,25 @@ static inline int landlock_restrict_self(const int ruleset_fd,
#define ENV_SCOPED_NAME "LL_SCOPED"
#define ENV_DELIMITER ":"
+static int str2num(const char *numstr, __u64 *num_dst)
+{
+ char *endptr = NULL;
+ int err = 0;
+ __u64 num;
+
+ errno = 0;
+ num = strtoull(numstr, &endptr, 10);
+ if (errno != 0)
+ err = errno;
+ /* Was the string empty, or not entirely parsed successfully? */
+ else if ((*numstr == '\0') || (*endptr != '\0'))
+ err = EINVAL;
+ else
+ *num_dst = num;
+
+ return err;
+}
+
static int parse_path(char *env_path, const char ***const path_list)
{
int i, num_paths = 0;
@@ -160,7 +179,6 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
char *env_port_name, *env_port_name_next, *strport;
struct landlock_net_port_attr net_port = {
.allowed_access = allowed_access,
- .port = 0,
};
env_port_name = getenv(env_var);
@@ -171,7 +189,17 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
env_port_name_next = env_port_name;
while ((strport = strsep(&env_port_name_next, ENV_DELIMITER))) {
- net_port.port = atoi(strport);
+ __u64 port;
+
+ if (strcmp(strport, "") == 0)
+ continue;
+
+ if (str2num(strport, &port)) {
+ fprintf(stderr, "Failed to parse port at \"%s\"\n",
+ strport);
+ goto out_free_name;
+ }
+ net_port.port = port;
if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&net_port, 0)) {
fprintf(stderr,
@@ -262,6 +290,44 @@ out_unset:
#define LANDLOCK_ABI_LAST 6
+#define XSTR(s) #s
+#define STR(s) XSTR(s)
+
+/* clang-format off */
+
+static const char help[] =
+ "usage: " ENV_FS_RO_NAME "=\"...\" " ENV_FS_RW_NAME "=\"...\" "
+ "[other environment variables] %1$s <cmd> [args]...\n"
+ "\n"
+ "Execute the given command in a restricted environment.\n"
+ "Multi-valued settings (lists of ports, paths, scopes) are colon-delimited.\n"
+ "\n"
+ "Mandatory settings:\n"
+ "* " ENV_FS_RO_NAME ": paths allowed to be used in a read-only way\n"
+ "* " ENV_FS_RW_NAME ": paths allowed to be used in a read-write way\n"
+ "\n"
+ "Optional settings (when not set, their associated access check "
+ "is always allowed, which is different from an empty string which "
+ "means an empty list):\n"
+ "* " ENV_TCP_BIND_NAME ": ports allowed to bind (server)\n"
+ "* " ENV_TCP_CONNECT_NAME ": ports allowed to connect (client)\n"
+ "* " ENV_SCOPED_NAME ": actions denied on the outside of the landlock domain\n"
+ " - \"a\" to restrict opening abstract unix sockets\n"
+ " - \"s\" to restrict sending signals\n"
+ "\n"
+ "Example:\n"
+ ENV_FS_RO_NAME "=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
+ ENV_FS_RW_NAME "=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
+ ENV_TCP_BIND_NAME "=\"9418\" "
+ ENV_TCP_CONNECT_NAME "=\"80:443\" "
+ ENV_SCOPED_NAME "=\"a:s\" "
+ "%1$s bash -i\n"
+ "\n"
+ "This sandboxer can use Landlock features up to ABI version "
+ STR(LANDLOCK_ABI_LAST) ".\n";
+
+/* clang-format on */
+
int main(const int argc, char *const argv[], char *const *const envp)
{
const char *cmd_path;
@@ -280,47 +346,7 @@ int main(const int argc, char *const argv[], char *const *const envp)
};
if (argc < 2) {
- fprintf(stderr,
- "usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s "
- "<cmd> [args]...\n\n",
- ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
- ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
- fprintf(stderr,
- "Execute a command in a restricted environment.\n\n");
- fprintf(stderr,
- "Environment variables containing paths and ports "
- "each separated by a colon:\n");
- fprintf(stderr,
- "* %s: list of paths allowed to be used in a read-only way.\n",
- ENV_FS_RO_NAME);
- fprintf(stderr,
- "* %s: list of paths allowed to be used in a read-write way.\n\n",
- ENV_FS_RW_NAME);
- fprintf(stderr,
- "Environment variables containing ports are optional "
- "and could be skipped.\n");
- fprintf(stderr,
- "* %s: list of ports allowed to bind (server).\n",
- ENV_TCP_BIND_NAME);
- fprintf(stderr,
- "* %s: list of ports allowed to connect (client).\n",
- ENV_TCP_CONNECT_NAME);
- fprintf(stderr, "* %s: list of scoped IPCs.\n",
- ENV_SCOPED_NAME);
- fprintf(stderr,
- "\nexample:\n"
- "%s=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" "
- "%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
- "%s=\"9418\" "
- "%s=\"80:443\" "
- "%s=\"a:s\" "
- "%s bash -i\n\n",
- ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME,
- ENV_TCP_CONNECT_NAME, ENV_SCOPED_NAME, argv[0]);
- fprintf(stderr,
- "This sandboxer can use Landlock features "
- "up to ABI version %d.\n",
- LANDLOCK_ABI_LAST);
+ fprintf(stderr, help, argv[0]);
return 1;
}
diff --git a/samples/pktgen/pktgen_sample01_simple.sh b/samples/pktgen/pktgen_sample01_simple.sh
index cdb9f497f87d..66cb707479e6 100755
--- a/samples/pktgen/pktgen_sample01_simple.sh
+++ b/samples/pktgen/pktgen_sample01_simple.sh
@@ -76,7 +76,7 @@ if [ -n "$DST_PORT" ]; then
pg_set $DEV "udp_dst_max $UDP_DST_MAX"
fi
-[ ! -z "$UDP_CSUM" ] && pg_set $dev "flag UDPCSUM"
+[ ! -z "$UDP_CSUM" ] && pg_set $DEV "flag UDPCSUM"
# Setup random UDP port src range
pg_set $DEV "flag UDPSRC_RND"
diff --git a/scripts/Makefile.package b/scripts/Makefile.package
index 11d53f240a2b..74bcb9e7f7a4 100644
--- a/scripts/Makefile.package
+++ b/scripts/Makefile.package
@@ -62,6 +62,10 @@ rpm-sources: linux.tar.gz
PHONY += rpm-pkg srcrpm-pkg binrpm-pkg
+ifneq ($(CC),$(HOSTCC))
+rpm-no-devel = --without=devel
+endif
+
rpm-pkg: private build-type := a
srcrpm-pkg: private build-type := s
binrpm-pkg: private build-type := b
@@ -72,7 +76,8 @@ rpm-pkg srcrpm-pkg binrpm-pkg: rpmbuild/SPECS/kernel.spec
--define='_topdir $(abspath rpmbuild)' \
$(if $(filter a b, $(build-type)), \
--target $(UTS_MACHINE)-linux --build-in-place --noprep --define='_smp_mflags %{nil}' \
- $$(rpm -q rpm >/dev/null 2>&1 || echo --nodeps)) \
+ $$(rpm -q rpm >/dev/null 2>&1 || echo --nodeps) \
+ $(rpm-no-devel)) \
$(RPMOPTS))
# deb-pkg srcdeb-pkg bindeb-pkg
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 4addd33749bb..6587ac86d0d5 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -533,6 +533,7 @@ bool menu_is_empty(struct menu *menu)
bool menu_is_visible(struct menu *menu)
{
+ struct menu *child;
struct symbol *sym;
tristate visible;
@@ -551,7 +552,17 @@ bool menu_is_visible(struct menu *menu)
} else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
- return visible != no;
+ if (visible != no)
+ return true;
+
+ if (!sym || sym_get_tristate_value(menu->sym) == no)
+ return false;
+
+ for (child = menu->list; child; child = child->next)
+ if (menu_is_visible(child))
+ return true;
+
+ return false;
}
const char *menu_get_prompt(const struct menu *menu)
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 99dce93a4188..c4cc11aa558f 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -567,12 +567,12 @@ static int do_acpi_entry(const char *filename,
void *symval, char *alias)
{
DEF_FIELD_ADDR(symval, acpi_device_id, id);
- DEF_FIELD_ADDR(symval, acpi_device_id, cls);
- DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk);
+ DEF_FIELD(symval, acpi_device_id, cls);
+ DEF_FIELD(symval, acpi_device_id, cls_msk);
if (id && strlen((const char *)*id))
sprintf(alias, "acpi*:%s:*", *id);
- else if (cls) {
+ else {
int i, byte_shift, cnt = 0;
unsigned int msk;
@@ -580,10 +580,10 @@ static int do_acpi_entry(const char *filename,
cnt = 6;
for (i = 1; i <= 3; i++) {
byte_shift = 8 * (3-i);
- msk = (*cls_msk >> byte_shift) & 0xFF;
+ msk = (cls_msk >> byte_shift) & 0xFF;
if (msk)
sprintf(&alias[cnt], "%02x",
- (*cls >> byte_shift) & 0xFF);
+ (cls >> byte_shift) & 0xFF);
else
sprintf(&alias[cnt], "??");
cnt += 2;
@@ -743,7 +743,7 @@ static void do_input(char *alias,
for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++)
arr[i] = TO_NATIVE(arr[i]);
for (i = min; i < max; i++)
- if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG)))
+ if (arr[i / BITS_PER_LONG] & (1ULL << (i%BITS_PER_LONG)))
sprintf(alias + strlen(alias), "%X,*", i);
}
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index e7d2da45b0df..6de9af17599d 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -392,7 +392,7 @@ out_file:
/* Calc and record src checksum. */
void get_src_version(const char *modname, char sum[], unsigned sumlen)
{
- char *buf;
+ char *buf, *pos;
struct md4_ctx md;
char *fname;
char filelist[PATH_MAX + 1];
@@ -401,9 +401,10 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen)
snprintf(filelist, sizeof(filelist), "%s.mod", modname);
buf = read_text_file(filelist);
+ pos = buf;
md4_init(&md);
- while ((fname = strsep(&buf, "\n"))) {
+ while ((fname = strsep(&pos, "\n"))) {
if (!*fname)
continue;
if (!(is_static_library(fname)) &&
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 404587fc71fe..441b0bb66e0d 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -123,7 +123,7 @@ install_kernel_headers () {
pdir=debian/$1
version=${1#linux-headers-}
- "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
mkdir -p $pdir/lib/modules/$version/
ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build
index d2c9cacecc0c..7ec1f061a519 100755
--- a/scripts/package/install-extmod-build
+++ b/scripts/package/install-extmod-build
@@ -44,13 +44,11 @@ mkdir -p "${destdir}"
fi
} | tar -c -f - -T - | tar -xf - -C "${destdir}"
-# When ${CC} and ${HOSTCC} differ, we are likely cross-compiling. Rebuild host
-# programs using ${CC}. This assumes CC=${CROSS_COMPILE}gcc, which is usually
-# the case for package building. It does not cross-compile when CC=clang.
+# When ${CC} and ${HOSTCC} differ, rebuild host programs using ${CC}.
#
# This caters to host programs that participate in Kbuild. objtool and
# resolve_btfids are out of scope.
-if [ "${CC}" != "${HOSTCC}" ] && is_enabled CONFIG_CC_CAN_LINK; then
+if [ "${CC}" != "${HOSTCC}" ]; then
echo "Rebuilding host programs with ${CC}..."
cat <<-'EOF' > "${destdir}/Kbuild"
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
index 10637d403777..fc3b7fa709fc 100755
--- a/scripts/package/mkdebian
+++ b/scripts/package/mkdebian
@@ -179,6 +179,8 @@ fi
echo $debarch > debian/arch
+host_gnu=$(dpkg-architecture -a "${debarch}" -q DEB_HOST_GNU_TYPE | sed 's/_/-/g')
+
# Generate a simple changelog template
cat <<EOF > debian/changelog
$sourcename ($packageversion) $distribution; urgency=low
@@ -196,7 +198,11 @@ Priority: optional
Maintainer: $maintainer
Rules-Requires-Root: no
Build-Depends: debhelper-compat (= 12)
-Build-Depends-Arch: bc, bison, cpio, flex, kmod, libelf-dev:native, libssl-dev:native, rsync
+Build-Depends-Arch: bc, bison, cpio, flex,
+ gcc-${host_gnu} <!pkg.${sourcename}.nokernelheaders>,
+ kmod, libelf-dev:native,
+ libssl-dev:native, libssl-dev <!pkg.${sourcename}.nokernelheaders>,
+ rsync
Homepage: https://www.kernel.org/
Package: $packagename-$version
@@ -224,6 +230,7 @@ cat <<EOF >> debian/control
Package: linux-headers-$version
Architecture: $debarch
+Build-Profiles: <!pkg.${sourcename}.nokernelheaders>
Description: Linux kernel headers for $version on $debarch
This package provides kernel header files for $version on $debarch
.
@@ -238,6 +245,7 @@ cat <<EOF >> debian/control
Package: linux-image-$version-dbg
Section: debug
Architecture: $debarch
+Build-Profiles: <!pkg.${sourcename}.nokerneldbg>
Description: Linux kernel debugging symbols for $version
This package will come in handy if you need to debug the kernel. It provides
all the necessary debug symbols for the kernel and its modules.
diff --git a/scripts/rustc-llvm-version.sh b/scripts/rustc-llvm-version.sh
index b6063cbe5bdc..a500d1ae3101 100755
--- a/scripts/rustc-llvm-version.sh
+++ b/scripts/rustc-llvm-version.sh
@@ -13,7 +13,7 @@ get_canonical_version()
echo $((10000 * $1 + 100 * $2 + $3))
}
-if output=$("$@" --version --verbose 2>/dev/null | grep LLVM); then
+if output=$("$@" --version --verbose 2>/dev/null | grep -E 'LLVM.*[0-9]+\.[0-9]+\.[0-9]+'); then
set -- $output
get_canonical_version $3
else
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 6924ed508ebd..377e57e9084f 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1084,7 +1084,8 @@ static void evm_file_release(struct file *file)
if (!S_ISREG(inode->i_mode) || !(mode & FMODE_WRITE))
return;
- if (iint && atomic_read(&inode->i_writecount) == 1)
+ if (iint && iint->flags & EVM_NEW_FILE &&
+ atomic_read(&inode->i_writecount) == 1)
iint->flags &= ~EVM_NEW_FILE;
}
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 4183956c53af..0e627eac9c33 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -318,15 +318,21 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
hash_algo_name[hash_algo]);
}
- if (digest)
+ if (digest) {
memcpy(buffer + offset, digest, digestsize);
- else
+ } else {
/*
* If digest is NULL, the event being recorded is a violation.
* Make room for the digest by increasing the offset by the
- * hash algorithm digest size.
+ * hash algorithm digest size. If the hash algorithm is not
+ * specified increase the offset by IMA_DIGEST_SIZE which
+ * fits SHA1 or MD5
*/
- offset += hash_digest_size[hash_algo];
+ if (hash_algo < HASH_ALGO__LAST)
+ offset += hash_digest_size[hash_algo];
+ else
+ offset += IMA_DIGEST_SIZE;
+ }
return ima_write_template_field_data(buffer, offset + digestsize,
fmt, field_data);
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 660f76cb69d3..c2c2da691123 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -37,6 +37,8 @@ struct evm_ima_xattr_data {
);
u8 data[];
} __packed;
+static_assert(offsetof(struct evm_ima_xattr_data, data) == sizeof(struct evm_ima_xattr_data_hdr),
+ "struct member likely outside of __struct_group()");
/* Only used in the EVM HMAC code. */
struct evm_xattr {
@@ -65,6 +67,8 @@ struct ima_digest_data {
);
u8 digest[];
} __packed;
+static_assert(offsetof(struct ima_digest_data, digest) == sizeof(struct ima_digest_data_hdr),
+ "struct member likely outside of __struct_group()");
/*
* Instead of wrapping the ima_digest_data struct inside a local structure
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 4448758f643a..f331725d5a37 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -772,8 +772,11 @@ ascend_to_node:
for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = READ_ONCE(node->slots[slot]);
- if (assoc_array_ptr_is_meta(ptr) && node->back_pointer)
- goto descend_to_node;
+ if (assoc_array_ptr_is_meta(ptr)) {
+ if (node->back_pointer ||
+ assoc_array_ptr_is_shortcut(ptr))
+ goto descend_to_node;
+ }
if (!keyring_ptr_is_keyring(ptr))
continue;
diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c
index 4edc5bbbcda3..e908c53a803c 100644
--- a/security/keys/trusted-keys/trusted_dcp.c
+++ b/security/keys/trusted-keys/trusted_dcp.c
@@ -133,6 +133,7 @@ static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce,
struct scatterlist src_sg, dst_sg;
struct crypto_aead *aead;
int ret;
+ DECLARE_CRYPTO_WAIT(wait);
aead = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(aead)) {
@@ -163,8 +164,8 @@ static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce,
}
aead_request_set_crypt(aead_req, &src_sg, &dst_sg, len, nonce);
- aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL,
- NULL);
+ aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP,
+ crypto_req_done, &wait);
aead_request_set_ad(aead_req, 0);
if (crypto_aead_setkey(aead, key, AES_KEYSIZE_128)) {
@@ -174,9 +175,9 @@ static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce,
}
if (do_encrypt)
- ret = crypto_aead_encrypt(aead_req);
+ ret = crypto_wait_req(crypto_aead_encrypt(aead_req), &wait);
else
- ret = crypto_aead_decrypt(aead_req);
+ ret = crypto_wait_req(crypto_aead_decrypt(aead_req), &wait);
free_req:
aead_request_free(aead_req);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 7d79fc8abe21..e31b97a9f175 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -389,37 +389,21 @@ static bool is_nouser_or_private(const struct dentry *dentry)
}
static access_mask_t
-get_raw_handled_fs_accesses(const struct landlock_ruleset *const domain)
-{
- access_mask_t access_dom = 0;
- size_t layer_level;
-
- for (layer_level = 0; layer_level < domain->num_layers; layer_level++)
- access_dom |=
- landlock_get_raw_fs_access_mask(domain, layer_level);
- return access_dom;
-}
-
-static access_mask_t
get_handled_fs_accesses(const struct landlock_ruleset *const domain)
{
/* Handles all initially denied by default access rights. */
- return get_raw_handled_fs_accesses(domain) |
+ return landlock_union_access_masks(domain).fs |
LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
}
-static const struct landlock_ruleset *
-get_fs_domain(const struct landlock_ruleset *const domain)
-{
- if (!domain || !get_raw_handled_fs_accesses(domain))
- return NULL;
-
- return domain;
-}
+static const struct access_masks any_fs = {
+ .fs = ~0,
+};
static const struct landlock_ruleset *get_current_fs_domain(void)
{
- return get_fs_domain(landlock_get_current_domain());
+ return landlock_get_applicable_domain(landlock_get_current_domain(),
+ any_fs);
}
/*
@@ -1517,7 +1501,8 @@ static int hook_file_open(struct file *const file)
access_mask_t open_access_request, full_access_request, allowed_access,
optional_access;
const struct landlock_ruleset *const dom =
- get_fs_domain(landlock_cred(file->f_cred)->domain);
+ landlock_get_applicable_domain(
+ landlock_cred(file->f_cred)->domain, any_fs);
if (!dom)
return 0;
diff --git a/security/landlock/net.c b/security/landlock/net.c
index c8bcd29bde09..d5dcc4407a19 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -39,27 +39,9 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
return err;
}
-static access_mask_t
-get_raw_handled_net_accesses(const struct landlock_ruleset *const domain)
-{
- access_mask_t access_dom = 0;
- size_t layer_level;
-
- for (layer_level = 0; layer_level < domain->num_layers; layer_level++)
- access_dom |= landlock_get_net_access_mask(domain, layer_level);
- return access_dom;
-}
-
-static const struct landlock_ruleset *get_current_net_domain(void)
-{
- const struct landlock_ruleset *const dom =
- landlock_get_current_domain();
-
- if (!dom || !get_raw_handled_net_accesses(dom))
- return NULL;
-
- return dom;
-}
+static const struct access_masks any_net = {
+ .net = ~0,
+};
static int current_check_access_socket(struct socket *const sock,
struct sockaddr *const address,
@@ -72,7 +54,9 @@ static int current_check_access_socket(struct socket *const sock,
struct landlock_id id = {
.type = LANDLOCK_KEY_NET_PORT,
};
- const struct landlock_ruleset *const dom = get_current_net_domain();
+ const struct landlock_ruleset *const dom =
+ landlock_get_applicable_domain(landlock_get_current_domain(),
+ any_net);
if (!dom)
return 0;
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index 61bdbc550172..631e24d4ffe9 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -11,6 +11,7 @@
#include <linux/bitops.h>
#include <linux/build_bug.h>
+#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/refcount.h>
@@ -47,6 +48,15 @@ struct access_masks {
access_mask_t scope : LANDLOCK_NUM_SCOPE;
};
+union access_masks_all {
+ struct access_masks masks;
+ u32 all;
+};
+
+/* Makes sure all fields are covered. */
+static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
+ sizeof(typeof_member(union access_masks_all, all)));
+
typedef u16 layer_mask_t;
/* Makes sure all layers can be checked. */
static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
@@ -260,6 +270,61 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
refcount_inc(&ruleset->usage);
}
+/**
+ * landlock_union_access_masks - Return all access rights handled in the
+ * domain
+ *
+ * @domain: Landlock ruleset (used as a domain)
+ *
+ * Returns: an access_masks result of the OR of all the domain's access masks.
+ */
+static inline struct access_masks
+landlock_union_access_masks(const struct landlock_ruleset *const domain)
+{
+ union access_masks_all matches = {};
+ size_t layer_level;
+
+ for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
+ union access_masks_all layer = {
+ .masks = domain->access_masks[layer_level],
+ };
+
+ matches.all |= layer.all;
+ }
+
+ return matches.masks;
+}
+
+/**
+ * landlock_get_applicable_domain - Return @domain if it applies to (handles)
+ * at least one of the access rights specified
+ * in @masks
+ *
+ * @domain: Landlock ruleset (used as a domain)
+ * @masks: access masks
+ *
+ * Returns: @domain if any access rights specified in @masks is handled, or
+ * NULL otherwise.
+ */
+static inline const struct landlock_ruleset *
+landlock_get_applicable_domain(const struct landlock_ruleset *const domain,
+ const struct access_masks masks)
+{
+ const union access_masks_all masks_all = {
+ .masks = masks,
+ };
+ union access_masks_all merge = {};
+
+ if (!domain)
+ return NULL;
+
+ merge.masks = landlock_union_access_masks(domain);
+ if (merge.all & masks_all.all)
+ return domain;
+
+ return NULL;
+}
+
static inline void
landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
const access_mask_t fs_access_mask,
@@ -296,18 +361,11 @@ landlock_add_scope_mask(struct landlock_ruleset *const ruleset,
}
static inline access_mask_t
-landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset,
- const u16 layer_level)
-{
- return ruleset->access_masks[layer_level].fs;
-}
-
-static inline access_mask_t
landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
const u16 layer_level)
{
/* Handles all initially denied by default access rights. */
- return landlock_get_raw_fs_access_mask(ruleset, layer_level) |
+ return ruleset->access_masks[layer_level].fs |
LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
}
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index f5a0e7182ec0..c097d356fa45 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -329,7 +329,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
return -ENOMSG;
/* Checks that allowed_access matches the @ruleset constraints. */
- mask = landlock_get_raw_fs_access_mask(ruleset, 0);
+ mask = ruleset->access_masks[0].fs;
if ((path_beneath_attr.allowed_access | mask) != mask)
return -EINVAL;
diff --git a/security/landlock/task.c b/security/landlock/task.c
index 4acbd7c40eee..dc7dab78392e 100644
--- a/security/landlock/task.c
+++ b/security/landlock/task.c
@@ -204,12 +204,17 @@ static bool is_abstract_socket(struct sock *const sock)
return false;
}
+static const struct access_masks unix_scope = {
+ .scope = LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
+};
+
static int hook_unix_stream_connect(struct sock *const sock,
struct sock *const other,
struct sock *const newsk)
{
const struct landlock_ruleset *const dom =
- landlock_get_current_domain();
+ landlock_get_applicable_domain(landlock_get_current_domain(),
+ unix_scope);
/* Quick return for non-landlocked tasks. */
if (!dom)
@@ -225,7 +230,8 @@ static int hook_unix_may_send(struct socket *const sock,
struct socket *const other)
{
const struct landlock_ruleset *const dom =
- landlock_get_current_domain();
+ landlock_get_applicable_domain(landlock_get_current_domain(),
+ unix_scope);
if (!dom)
return 0;
@@ -243,6 +249,10 @@ static int hook_unix_may_send(struct socket *const sock,
return 0;
}
+static const struct access_masks signal_scope = {
+ .scope = LANDLOCK_SCOPE_SIGNAL,
+};
+
static int hook_task_kill(struct task_struct *const p,
struct kernel_siginfo *const info, const int sig,
const struct cred *const cred)
@@ -256,6 +266,7 @@ static int hook_task_kill(struct task_struct *const p,
} else {
dom = landlock_get_current_domain();
}
+ dom = landlock_get_applicable_domain(dom, signal_scope);
/* Quick return for non-landlocked tasks. */
if (!dom)
@@ -279,7 +290,8 @@ static int hook_file_send_sigiotask(struct task_struct *tsk,
/* Lock already held by send_sigio() and send_sigurg(). */
lockdep_assert_held(&fown->lock);
- dom = landlock_file(fown->file)->fown_domain;
+ dom = landlock_get_applicable_domain(
+ landlock_file(fown->file)->fown_domain, signal_scope);
/* Quick return for unowned socket. */
if (!dom)
diff --git a/sound/core/ump.c b/sound/core/ump.c
index cf22a17e38dd..7d59a0a9b037 100644
--- a/sound/core/ump.c
+++ b/sound/core/ump.c
@@ -1233,7 +1233,7 @@ static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
num = 0;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++)
- if (group_maps & (1U << i))
+ if ((group_maps & (1U << i)) && ump->groups[i].valid)
ump->legacy_mapping[num++] = i;
return num;
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index c72b2a754775..7fc51f829ecc 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -172,6 +172,9 @@ static int apply_constraint_to_size(struct snd_pcm_hw_params *params,
step = max(step, amdtp_syt_intervals[i]);
}
+ if (step == 0)
+ return -EINVAL;
+
t.min = roundup(s->min, step);
t.max = rounddown(s->max, step);
t.integer = 1;
diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
index 0b42d6559008..079afa4bd381 100644
--- a/sound/firewire/tascam/amdtp-tascam.c
+++ b/sound/firewire/tascam/amdtp-tascam.c
@@ -238,7 +238,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
err = amdtp_stream_init(s, unit, dir, flags, fmt,
process_ctx_payloads, sizeof(struct amdtp_tscm));
if (err < 0)
- return 0;
+ return err;
if (dir == AMDTP_OUT_STREAM) {
// Use fixed value for FDF field.
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index f018bd779862..9f849e05ce79 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -723,6 +723,10 @@ static const struct config_entry acpi_config_table[] = {
/* BayTrail */
{
.flags = FLAG_SST_OR_SOF_BYT,
+ .acpi_hid = "LPE0F28",
+ },
+ {
+ .flags = FLAG_SST_OR_SOF_BYT,
.acpi_hid = "80860F28",
},
/* CherryTrail */
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index bb15a0248250..68f1eee9e5c9 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -198,7 +198,7 @@ config SND_HDA_SCODEC_TAS2781_I2C
depends on SND_SOC
select SND_SOC_TAS2781_COMLIB
select SND_SOC_TAS2781_FMWLIB
- select CRC32_SARWATE
+ select CRC32
help
Say Y or M here to include TAS2781 I2C HD-audio side codec support
in snd-hda-intel driver, such as ALC287.
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c74f6742c359..b2bcdf76da30 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -205,8 +205,6 @@ static void cx_auto_shutdown(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
- snd_hda_gen_shutup_speakers(codec);
-
/* Turn the problematic codec into D3 to avoid spurious noises
from the internal speaker during (and after) reboot */
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 3bbf5fab2881..571fa8a6c9e1 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3868,20 +3868,18 @@ static void alc_default_init(struct hda_codec *codec)
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
- if (hp_pin_sense)
+ if (hp_pin_sense) {
msleep(2);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense)
- msleep(85);
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(75);
- if (hp_pin_sense)
- msleep(100);
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ msleep(75);
+ }
}
static void alc_default_shutup(struct hda_codec *codec)
@@ -3897,22 +3895,20 @@ static void alc_default_shutup(struct hda_codec *codec)
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
- if (hp_pin_sense)
+ if (hp_pin_sense) {
msleep(2);
- snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
- if (hp_pin_sense)
- msleep(85);
-
- if (!spec->no_shutup_pins)
snd_hda_codec_write(codec, hp_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
- if (hp_pin_sense)
- msleep(100);
+ msleep(75);
+
+ if (!spec->no_shutup_pins)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ msleep(75);
+ }
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
}
@@ -7525,6 +7521,7 @@ enum {
ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
@@ -7555,10 +7552,12 @@ enum {
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC269_FIXUP_THINKPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
+ ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13,
ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO,
ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
@@ -7649,6 +7648,7 @@ enum {
ALC286_FIXUP_ACER_AIO_HEADSET_MIC,
ALC256_FIXUP_ASUS_HEADSET_MIC,
ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+ ALC255_FIXUP_PREDATOR_SUBWOOFER,
ALC299_FIXUP_PREDATOR_SPK,
ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,
ALC289_FIXUP_DELL_SPK1,
@@ -7999,6 +7999,16 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_pincfg_U7x7_headset_mic,
},
+ [ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170151 }, /* use as internal speaker (LFE) */
+ { 0x1b, 0x90170152 }, /* use as internal speaker (back) */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
[ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8117,6 +8127,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
[ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -8397,6 +8413,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_HEADSET_MODE
},
+ [ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
[ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -9063,6 +9085,13 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
+ [ALC255_FIXUP_PREDATOR_SUBWOOFER] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170151 }, /* use as internal speaker (LFE) */
+ { 0x1b, 0x90170152 } /* use as internal speaker (back) */
+ }
+ },
[ALC299_FIXUP_PREDATOR_SPK] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -10150,6 +10179,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK),
SND_PCI_QUIRK(0x1025, 0x1167, "Acer Veriton N6640G", ALC269_FIXUP_LIFEBOOK),
+ SND_PCI_QUIRK(0x1025, 0x1177, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
+ SND_PCI_QUIRK(0x1025, 0x1178, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK),
SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
@@ -10719,6 +10750,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10976,6 +11008,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -10983,6 +11016,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
@@ -11070,6 +11104,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
{.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
{.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
+ {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, .name = "dell-headset4-quiet"},
{.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
{.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
@@ -11624,16 +11659,16 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
{0x19, 0x40000000},
{0x1b, 0x40000000}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
{0x19, 0x40000000},
{0x1b, 0x40000000}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
- SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
- SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
+ SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
{0x19, 0x40000000},
{0x1a, 0x40000000}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC,
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index ace6328e91e3..2436e8deb2be 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -231,6 +231,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M4"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21M5"),
}
},
@@ -329,6 +336,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E1404FA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "E1504FA"),
}
},
@@ -342,6 +356,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M3502RA"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 B7ED"),
}
@@ -384,6 +405,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14 2022"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Razer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Blade 14 (2022) - RZ09-0427"),
}
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index 8dc2b8aa6832..bba59885242d 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -656,7 +656,7 @@ static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
if (ret)
return ret;
if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
- ret = -EPERM;
+ return -EPERM;
return 0;
}
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index e4827b8c2bde..6e51954bdb1e 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -747,8 +747,10 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
- if (IS_ERR(cs42l51->reset_gpio))
- return PTR_ERR(cs42l51->reset_gpio);
+ if (IS_ERR(cs42l51->reset_gpio)) {
+ ret = PTR_ERR(cs42l51->reset_gpio);
+ goto error;
+ }
if (cs42l51->reset_gpio) {
dev_dbg(dev, "Release reset gpio\n");
@@ -780,6 +782,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
return 0;
error:
+ gpiod_set_value_cansleep(cs42l51->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
return ret;
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index ef7a70fa6966..febbbe073962 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -202,12 +202,14 @@
#define CDC_RX_RXn_RX_PATH_SEC3(rx, n) (0x042c + rx->rxn_reg_stride * n)
#define CDC_RX_RX0_RX_PATH_SEC4 (0x0430)
#define CDC_RX_RX0_RX_PATH_SEC7 (0x0434)
-#define CDC_RX_RXn_RX_PATH_SEC7(rx, n) (0x0434 + rx->rxn_reg_stride * n)
+#define CDC_RX_RXn_RX_PATH_SEC7(rx, n) \
+ (0x0434 + (rx->rxn_reg_stride * n) + ((n > 1) ? rx->rxn_reg_stride2 : 0))
#define CDC_RX_DSM_OUT_DELAY_SEL_MASK GENMASK(2, 0)
#define CDC_RX_DSM_OUT_DELAY_TWO_SAMPLE 0x2
#define CDC_RX_RX0_RX_PATH_MIX_SEC0 (0x0438)
#define CDC_RX_RX0_RX_PATH_MIX_SEC1 (0x043C)
-#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n) (0x0440 + rx->rxn_reg_stride * n)
+#define CDC_RX_RXn_RX_PATH_DSM_CTL(rx, n) \
+ (0x0440 + (rx->rxn_reg_stride * n) + ((n > 1) ? rx->rxn_reg_stride2 : 0))
#define CDC_RX_RXn_DSM_CLK_EN_MASK BIT(0)
#define CDC_RX_RX0_RX_PATH_DSM_CTL (0x0440)
#define CDC_RX_RX0_RX_PATH_DSM_DATA1 (0x0444)
@@ -645,6 +647,7 @@ struct rx_macro {
int rx_mclk_cnt;
enum lpass_codec_version codec_version;
int rxn_reg_stride;
+ int rxn_reg_stride2;
bool is_ear_mode_on;
bool hph_pwr_mode;
bool hph_hd2_mode;
@@ -1929,9 +1932,6 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
CDC_RX_PATH_PGA_MUTE_MASK, 0x0);
}
- if (j == INTERP_AUX)
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
-
int_mux_cfg0 = CDC_RX_INP_MUX_RX_INT0_CFG0 + j * 8;
int_mux_cfg1 = int_mux_cfg0 + 4;
int_mux_cfg0_val = snd_soc_component_read(component, int_mux_cfg0);
@@ -2702,9 +2702,6 @@ static int rx_macro_enable_interp_clk(struct snd_soc_component *component,
main_reg = CDC_RX_RXn_RX_PATH_CTL(rx, interp_idx);
dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, interp_idx);
- if (interp_idx == INTERP_AUX)
- dsm_reg = CDC_RX_RXn_RX_PATH_DSM_CTL(rx, 2);
-
rx_cfg2_reg = CDC_RX_RXn_RX_PATH_CFG2(rx, interp_idx);
if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -3821,6 +3818,7 @@ static int rx_macro_probe(struct platform_device *pdev)
case LPASS_CODEC_VERSION_2_0:
case LPASS_CODEC_VERSION_2_1:
rx->rxn_reg_stride = 0x80;
+ rx->rxn_reg_stride2 = 0xc;
def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_pre_2_5_defaults);
reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
if (!reg_defaults)
@@ -3834,6 +3832,7 @@ static int rx_macro_probe(struct platform_device *pdev)
case LPASS_CODEC_VERSION_2_7:
case LPASS_CODEC_VERSION_2_8:
rx->rxn_reg_stride = 0xc0;
+ rx->rxn_reg_stride2 = 0x0;
def_count = ARRAY_SIZE(rx_defaults) + ARRAY_SIZE(rx_2_5_defaults);
reg_defaults = kmalloc_array(def_count, sizeof(struct reg_default), GFP_KERNEL);
if (!reg_defaults)
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index b847d7c59ec0..99986090b4a6 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -763,6 +763,7 @@ static int max98388_dai_tdm_slot(struct snd_soc_dai *dai,
addr = MAX98388_R2044_PCM_TX_CTRL1 + (cnt / 8);
bits = cnt % 8;
regmap_update_bits(max98388->regmap, addr, bits, bits);
+ slot_found++;
if (slot_found >= MAX_NUM_CH)
break;
}
diff --git a/sound/soc/codecs/pcm3060-i2c.c b/sound/soc/codecs/pcm3060-i2c.c
index 5330cf46b127..3816b25a8ead 100644
--- a/sound/soc/codecs/pcm3060-i2c.c
+++ b/sound/soc/codecs/pcm3060-i2c.c
@@ -2,7 +2,7 @@
//
// PCM3060 I2C driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/i2c.h>
#include <linux/module.h>
@@ -55,5 +55,5 @@ static struct i2c_driver pcm3060_i2c_driver = {
module_i2c_driver(pcm3060_i2c_driver);
MODULE_DESCRIPTION("PCM3060 I2C driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060-spi.c b/sound/soc/codecs/pcm3060-spi.c
index 3b79734b832b..6095841f2f56 100644
--- a/sound/soc/codecs/pcm3060-spi.c
+++ b/sound/soc/codecs/pcm3060-spi.c
@@ -2,7 +2,7 @@
//
// PCM3060 SPI driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/module.h>
#include <linux/spi/spi.h>
@@ -55,5 +55,5 @@ static struct spi_driver pcm3060_spi_driver = {
module_spi_driver(pcm3060_spi_driver);
MODULE_DESCRIPTION("PCM3060 SPI driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 586ec8c7246c..8974200652e7 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -2,7 +2,7 @@
//
// PCM3060 codec driver
//
-// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+// Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
#include <linux/module.h>
#include <sound/pcm_params.h>
@@ -343,5 +343,5 @@ int pcm3060_probe(struct device *dev)
EXPORT_SYMBOL(pcm3060_probe);
MODULE_DESCRIPTION("PCM3060 codec driver");
-MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
+MODULE_AUTHOR("Kirill Marinushkin <k.marinushkin@gmail.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h
index 5e1185e7b03d..1b96835600b4 100644
--- a/sound/soc/codecs/pcm3060.h
+++ b/sound/soc/codecs/pcm3060.h
@@ -2,7 +2,7 @@
/*
* PCM3060 codec driver
*
- * Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
+ * Copyright (C) 2018 Kirill Marinushkin <k.marinushkin@gmail.com>
*/
#ifndef _SND_SOC_PCM3060_H
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 16f3425a3e35..855139348edb 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2419,10 +2419,20 @@ static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void rt5640_cancel_work(void *data)
+static void rt5640_disable_irq_and_cancel_work(void *data)
{
struct rt5640_priv *rt5640 = data;
+ if (rt5640->jd_gpio_irq_requested) {
+ free_irq(rt5640->jd_gpio_irq, rt5640);
+ rt5640->jd_gpio_irq_requested = false;
+ }
+
+ if (rt5640->irq_requested) {
+ free_irq(rt5640->irq, rt5640);
+ rt5640->irq_requested = false;
+ }
+
cancel_delayed_work_sync(&rt5640->jack_work);
cancel_delayed_work_sync(&rt5640->bp_work);
}
@@ -2463,13 +2473,7 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
if (!rt5640->jack)
return;
- if (rt5640->jd_gpio_irq_requested)
- free_irq(rt5640->jd_gpio_irq, rt5640);
-
- if (rt5640->irq_requested)
- free_irq(rt5640->irq, rt5640);
-
- rt5640_cancel_work(rt5640);
+ rt5640_disable_irq_and_cancel_work(rt5640);
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_disable_micbias1_ovcd_irq(component);
@@ -2477,8 +2481,6 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
- rt5640->jd_gpio_irq_requested = false;
- rt5640->irq_requested = false;
rt5640->jd_gpio = NULL;
rt5640->jack = NULL;
}
@@ -2798,7 +2800,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
if (rt5640->jack) {
/* disable jack interrupts during system suspend */
disable_irq(rt5640->irq);
- rt5640_cancel_work(rt5640);
+ cancel_delayed_work_sync(&rt5640->jack_work);
+ cancel_delayed_work_sync(&rt5640->bp_work);
}
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
@@ -3032,7 +3035,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */
- ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
+ ret = devm_add_action_or_reset(&i2c->dev, rt5640_disable_irq_and_cancel_work, rt5640);
if (ret)
return ret;
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 87354bb1564e..d5c985ff5ac5 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -253,7 +253,7 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave)
}
/* set the timeout values */
- prop->clk_stop_timeout = 200;
+ prop->clk_stop_timeout = 900;
/* wake-up event */
prop->wake_capable = 1;
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index ae360c97fe1e..0aeb88abbf52 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -1992,6 +1992,7 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
break;
case 0x202:
case 0x400:
+ case 0x401:
tas_priv->fw_parse_variable_header =
fw_parse_variable_header_git;
tas_priv->fw_parse_program_data =
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index 45f32d281908..08fb13a334a4 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -715,12 +715,17 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
int hph_mode = wcd937x->hph_mode;
+ u8 val;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ val = WCD937X_DIGITAL_PDM_WD_CTL2_EN |
+ WCD937X_DIGITAL_PDM_WD_CTL2_TIMEOUT_SEL |
+ WCD937X_DIGITAL_PDM_WD_CTL2_HOLD_OFF;
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_PDM_WD_CTL2,
- BIT(0), BIT(0));
+ WCD937X_DIGITAL_PDM_WD_CTL2_MASK,
+ val);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(1000, 1010);
@@ -741,7 +746,8 @@ static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
hph_mode);
snd_soc_component_update_bits(component,
WCD937X_DIGITAL_PDM_WD_CTL2,
- BIT(0), 0x00);
+ WCD937X_DIGITAL_PDM_WD_CTL2_MASK,
+ 0x00);
break;
}
@@ -2049,6 +2055,8 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("HPHR Switch", WCD937X_HPH_R, 0, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
+ SOC_SINGLE_EXT("LO Switch", WCD937X_LO, 0, 1, 0,
+ wcd937x_get_swr_port, wcd937x_set_swr_port),
SOC_SINGLE_EXT("ADC1 Switch", WCD937X_ADC1, 1, 1, 0,
wcd937x_get_swr_port, wcd937x_set_swr_port),
diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h
index 35f3d48bd7dd..4afa48dcaf74 100644
--- a/sound/soc/codecs/wcd937x.h
+++ b/sound/soc/codecs/wcd937x.h
@@ -391,6 +391,10 @@
#define WCD937X_DIGITAL_PDM_WD_CTL0 0x3465
#define WCD937X_DIGITAL_PDM_WD_CTL1 0x3466
#define WCD937X_DIGITAL_PDM_WD_CTL2 0x3467
+#define WCD937X_DIGITAL_PDM_WD_CTL2_HOLD_OFF BIT(2)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_TIMEOUT_SEL BIT(1)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_EN BIT(0)
+#define WCD937X_DIGITAL_PDM_WD_CTL2_MASK GENMASK(2, 0)
#define WCD937X_DIGITAL_INTR_MODE 0x346A
#define WCD937X_DIGITAL_INTR_MASK_0 0x346B
#define WCD937X_DIGITAL_INTR_MASK_1 0x346C
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index a65f5b9935a2..0b247f16a163 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -119,10 +119,10 @@ static irqreturn_t esai_isr(int irq, void *devid)
dev_dbg(&pdev->dev, "isr: Transmission Initialized\n");
if (esr & ESAI_ESR_RFF_MASK)
- dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+ dev_dbg(&pdev->dev, "isr: Receiving overrun\n");
if (esr & ESAI_ESR_TFE_MASK)
- dev_warn(&pdev->dev, "isr: Transmission underrun\n");
+ dev_dbg(&pdev->dev, "isr: Transmission underrun\n");
if (esr & ESAI_ESR_TLS_MASK)
dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 193be098fa5e..0c71a73476df 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -28,6 +28,13 @@
#define MICFIL_OSR_DEFAULT 16
+#define MICFIL_NUM_RATES 7
+#define MICFIL_CLK_SRC_NUM 3
+/* clock source ids */
+#define MICFIL_AUDIO_PLL1 0
+#define MICFIL_AUDIO_PLL2 1
+#define MICFIL_CLK_EXT3 2
+
enum quality {
QUALITY_HIGH,
QUALITY_MEDIUM,
@@ -45,9 +52,12 @@ struct fsl_micfil {
struct clk *mclk;
struct clk *pll8k_clk;
struct clk *pll11k_clk;
+ struct clk *clk_src[MICFIL_CLK_SRC_NUM];
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct sdma_peripheral_config sdmacfg;
struct snd_soc_card *card;
+ struct snd_pcm_hw_constraint_list constraint_rates;
+ unsigned int constraint_rates_list[MICFIL_NUM_RATES];
unsigned int dataline;
char name[32];
int irq[MICFIL_IRQ_LINES];
@@ -67,6 +77,7 @@ struct fsl_micfil_soc_data {
bool imx;
bool use_edma;
bool use_verid;
+ bool volume_sx;
u64 formats;
};
@@ -76,6 +87,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
.fifo_depth = 8,
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .volume_sx = true,
};
static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
@@ -84,6 +96,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
.fifo_depth = 32,
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .volume_sx = false,
};
static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
@@ -94,6 +107,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.use_edma = true,
.use_verid = true,
+ .volume_sx = false,
};
static const struct of_device_id fsl_micfil_dt_ids[] = {
@@ -317,7 +331,26 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
+static const struct snd_kcontrol_new fsl_micfil_volume_controls[] = {
+ SOC_SINGLE_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, gain_tlv),
+ SOC_SINGLE_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
+ MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, gain_tlv),
+};
+
+static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
@@ -334,6 +367,9 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv),
SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv),
+};
+
+static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum,
micfil_quality_get, micfil_quality_set),
@@ -449,12 +485,34 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
+ unsigned int rates[MICFIL_NUM_RATES] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
+ int i, j, k = 0;
+ u64 clk_rate;
if (!micfil) {
dev_err(dai->dev, "micfil dai priv_data not set\n");
return -EINVAL;
}
+ micfil->constraint_rates.list = micfil->constraint_rates_list;
+ micfil->constraint_rates.count = 0;
+
+ for (j = 0; j < MICFIL_NUM_RATES; j++) {
+ for (i = 0; i < MICFIL_CLK_SRC_NUM; i++) {
+ clk_rate = clk_get_rate(micfil->clk_src[i]);
+ if (clk_rate != 0 && do_div(clk_rate, rates[j]) == 0) {
+ micfil->constraint_rates_list[k++] = rates[j];
+ micfil->constraint_rates.count++;
+ break;
+ }
+ }
+ }
+
+ if (micfil->constraint_rates.count > 0)
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &micfil->constraint_rates);
+
return 0;
}
@@ -801,6 +859,20 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static int fsl_micfil_component_probe(struct snd_soc_component *component)
+{
+ struct fsl_micfil *micfil = snd_soc_component_get_drvdata(component);
+
+ if (micfil->soc->volume_sx)
+ snd_soc_add_component_controls(component, fsl_micfil_volume_sx_controls,
+ ARRAY_SIZE(fsl_micfil_volume_sx_controls));
+ else
+ snd_soc_add_component_controls(component, fsl_micfil_volume_controls,
+ ARRAY_SIZE(fsl_micfil_volume_controls));
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
.probe = fsl_micfil_dai_probe,
.startup = fsl_micfil_startup,
@@ -821,6 +893,7 @@ static struct snd_soc_dai_driver fsl_micfil_dai = {
static const struct snd_soc_component_driver fsl_micfil_component = {
.name = "fsl-micfil-dai",
+ .probe = fsl_micfil_component_probe,
.controls = fsl_micfil_snd_controls,
.num_controls = ARRAY_SIZE(fsl_micfil_snd_controls),
.legacy_dai_naming = 1,
@@ -1134,6 +1207,12 @@ static int fsl_micfil_probe(struct platform_device *pdev)
fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk,
&micfil->pll11k_clk);
+ micfil->clk_src[MICFIL_AUDIO_PLL1] = micfil->pll8k_clk;
+ micfil->clk_src[MICFIL_AUDIO_PLL2] = micfil->pll11k_clk;
+ micfil->clk_src[MICFIL_CLK_EXT3] = devm_clk_get(&pdev->dev, "clkext3");
+ if (IS_ERR(micfil->clk_src[MICFIL_CLK_EXT3]))
+ micfil->clk_src[MICFIL_CLK_EXT3] = NULL;
+
/* init regmap */
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs))
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 9956dc63db74..257180630475 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -125,6 +125,28 @@ static const struct sst_res_info bytcr_res_info = {
.acpi_ipc_irq_index = 0
};
+/* For "LPE0F28" ACPI device found on some Android factory OS models */
+static const struct sst_res_info lpe8086_res_info = {
+ .shim_offset = 0x140000,
+ .shim_size = 0x000100,
+ .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
+ .ssp0_offset = 0xa0000,
+ .ssp0_size = 0x1000,
+ .dma0_offset = 0x98000,
+ .dma0_size = 0x4000,
+ .dma1_offset = 0x9c000,
+ .dma1_size = 0x4000,
+ .iram_offset = 0x0c0000,
+ .iram_size = 0x14000,
+ .dram_offset = 0x100000,
+ .dram_size = 0x28000,
+ .mbox_offset = 0x144000,
+ .mbox_size = 0x1000,
+ .acpi_lpe_res_index = 1,
+ .acpi_ddr_index = 0,
+ .acpi_ipc_irq_index = 0
+};
+
static struct sst_platform_info byt_rvp_platform_data = {
.probe_data = &byt_fwparse_info,
.ipc_info = &byt_ipc_info,
@@ -268,10 +290,38 @@ static int sst_acpi_probe(struct platform_device *pdev)
mach->pdata = &chv_platform_data;
pdata = mach->pdata;
- ret = kstrtouint(id->id, 16, &dev_id);
- if (ret < 0) {
- dev_err(dev, "Unique device id conversion error: %d\n", ret);
- return ret;
+ if (!strcmp(id->id, "LPE0F28")) {
+ struct resource *rsrc;
+
+ /* Use regular BYT SST PCI VID:PID */
+ dev_id = 0x80860F28;
+ byt_rvp_platform_data.res_info = &lpe8086_res_info;
+
+ /*
+ * The "LPE0F28" ACPI device has separate IO-mem resources for:
+ * DDR, SHIM, MBOX, IRAM, DRAM, CFG
+ * None of which covers the entire LPE base address range.
+ * lpe8086_res_info.acpi_lpe_res_index points to the SHIM.
+ * Patch this to cover the entire base address range as expected
+ * by sst_platform_get_resources().
+ */
+ rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+ pdata->res_info->acpi_lpe_res_index);
+ if (!rsrc) {
+ dev_err(dev, "Invalid SHIM base\n");
+ return -EIO;
+ }
+ rsrc->start -= pdata->res_info->shim_offset;
+ rsrc->end = rsrc->start + 0x200000 - 1;
+ } else {
+ ret = kstrtouint(id->id, 16, &dev_id);
+ if (ret < 0) {
+ dev_err(dev, "Unique device id conversion error: %d\n", ret);
+ return ret;
+ }
+
+ if (soc_intel_is_byt_cr(pdev))
+ byt_rvp_platform_data.res_info = &bytcr_res_info;
}
dev_dbg(dev, "ACPI device id: %x\n", dev_id);
@@ -280,11 +330,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (soc_intel_is_byt_cr(pdev)) {
- /* override resource info */
- byt_rvp_platform_data.res_info = &bytcr_res_info;
- }
-
/* update machine parameters */
mach->mach_params.acpi_ipc_irq_index =
pdata->res_info->acpi_ipc_irq_index;
@@ -344,6 +389,7 @@ static void sst_acpi_remove(struct platform_device *pdev)
}
static const struct acpi_device_id sst_acpi_ids[] = {
+ { "LPE0F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
{ "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines},
{ "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines},
{ },
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index da7bac09acb4..73d4bde9b2f7 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -28,6 +28,7 @@
#include "avs.h"
#include "cldma.h"
#include "messages.h"
+#include "pcm.h"
static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
module_param(pgctl_mask, uint, 0444);
@@ -247,7 +248,7 @@ static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
{
if (stream->substream) {
- snd_pcm_period_elapsed(stream->substream);
+ avs_period_elapsed(stream->substream);
} else if (stream->cstream) {
u64 buffer_size = stream->cstream->runtime->buffer_size;
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index afc0fc74cf94..4af811580356 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -16,6 +16,7 @@
#include <sound/soc-component.h>
#include "avs.h"
#include "path.h"
+#include "pcm.h"
#include "topology.h"
#include "../../codecs/hda.h"
@@ -30,6 +31,7 @@ struct avs_dma_data {
struct hdac_ext_stream *host_stream;
};
+ struct work_struct period_elapsed_work;
struct snd_pcm_substream *substream;
};
@@ -56,6 +58,22 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
return dw->priv;
}
+static void avs_period_elapsed_work(struct work_struct *work)
+{
+ struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work);
+
+ snd_pcm_period_elapsed(data->substream);
+}
+
+void avs_period_elapsed(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);
+
+ schedule_work(&data->period_elapsed_work);
+}
+
static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
@@ -77,6 +95,7 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
data->substream = substream;
data->template = template;
data->adev = adev;
+ INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work);
snd_soc_dai_set_dma_data(dai, substream, data);
if (rtd->dai_link->ignore_suspend)
diff --git a/sound/soc/intel/avs/pcm.h b/sound/soc/intel/avs/pcm.h
new file mode 100644
index 000000000000..0f3615c90398
--- /dev/null
+++ b/sound/soc/intel/avs/pcm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2024 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_PCM_H
+#define __SOUND_SOC_INTEL_AVS_PCM_H
+
+#include <sound/pcm.h>
+
+void avs_period_elapsed(struct snd_pcm_substream *substream);
+
+#endif
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 2ed49acb4e36..54f77f57ec8e 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/device.h>
+#include <linux/device/bus.h>
#include <linux/dmi.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
@@ -32,6 +33,8 @@
#include "../atom/sst-atom-controls.h"
#include "../common/soc-intel-quirks.h"
+#define BYT_RT5640_FALLBACK_CODEC_DEV_NAME "i2c-rt5640"
+
enum {
BYT_RT5640_DMIC1_MAP,
BYT_RT5640_DMIC2_MAP,
@@ -1129,6 +1132,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
+ { /* Vexia Edu Atla 10 tablet */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+ /* Above strings are too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"),
+ },
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF2 |
+ BYT_RT5640_MCLK_EN),
+ },
{ /* Voyo Winpad A15 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
@@ -1698,9 +1716,33 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
codec_dev = acpi_get_first_physical_node(adev);
acpi_dev_put(adev);
- if (!codec_dev)
- return -EPROBE_DEFER;
- priv->codec_dev = get_device(codec_dev);
+
+ if (codec_dev) {
+ priv->codec_dev = get_device(codec_dev);
+ } else {
+ /*
+ * Special case for Android tablets where the codec i2c_client
+ * has been manually instantiated by x86_android_tablets.ko due
+ * to a broken DSDT.
+ */
+ codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL,
+ BYT_RT5640_FALLBACK_CODEC_DEV_NAME);
+ if (!codec_dev)
+ return -EPROBE_DEFER;
+
+ if (!i2c_verify_client(codec_dev)) {
+ dev_err(dev, "Error '%s' is not an i2c_client\n",
+ BYT_RT5640_FALLBACK_CODEC_DEV_NAME);
+ put_device(codec_dev);
+ }
+
+ /* fixup codec name */
+ strscpy(byt_rt5640_codec_name, BYT_RT5640_FALLBACK_CODEC_DEV_NAME,
+ sizeof(byt_rt5640_codec_name));
+
+ /* bus_find_device() returns a reference no need to get() */
+ priv->codec_dev = codec_dev;
+ }
/*
* swap SSP0 if bytcr is detected
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
index 3c4e0c7ca8ee..094ed4b27cb0 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -225,6 +225,15 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1318_1_adr[] = {
+ {
+ .adr = 0x000133025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
{
.adr = 0x000130025D131801ull,
@@ -243,6 +252,15 @@ static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt713_0_adr[] = {
+ {
+ .adr = 0x000031025D071301ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt713"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
{
.adr = 0x000030025D071401ull,
@@ -378,6 +396,20 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = {
{}
};
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_adr),
+ .adr_d = rt713_0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_adr),
+ .adr_d = rt1318_1_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -447,6 +479,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg"
},
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = lnl_sdw_rt713_l0_rt1318_l1,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines);
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 7379f24d385c..7910d5d9ac4f 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -144,6 +144,7 @@ static int loongson_card_parse_of(struct loongson_card_data *data)
dev_err(dev, "getting cpu dlc error (%d)\n", ret);
goto err;
}
+ loongson_dai_links[i].platforms->of_node = loongson_dai_links[i].cpus->of_node;
ret = snd_soc_of_get_dlc(codec, NULL, loongson_dai_links[i].codecs, 0);
if (ret < 0) {
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 762491d6f2f2..ca7a30ebd26a 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -157,6 +157,7 @@ config SND_SOC_SDM845
depends on COMMON_CLK
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
+ select SND_SOC_QCOM_SDW
select SND_SOC_RT5663
select SND_SOC_MAX98927
imply SND_SOC_CROS_EC_CODEC
@@ -208,6 +209,7 @@ config SND_SOC_SC7280
tristate "SoC Machine driver for SC7280 boards"
depends on I2C && SOUNDWIRE
select SND_SOC_QCOM_COMMON
+ select SND_SOC_QCOM_SDW
select SND_SOC_LPASS_SC7280
select SND_SOC_MAX98357A
select SND_SOC_WCD938X_SDW
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 5a47f661e0c6..242bc16da36d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -1242,6 +1242,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
/* Allocation for i2sctl regmap fields */
drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
GFP_KERNEL);
+ if (!drvdata->i2sctl)
+ return -ENOMEM;
/* Initialize bitfields for dai I2SCTL register */
ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c
index 207ac5da4dd4..230af8d7b205 100644
--- a/sound/soc/qcom/sc7280.c
+++ b/sound/soc/qcom/sc7280.c
@@ -23,6 +23,7 @@
#include "common.h"
#include "lpass.h"
#include "qdsp6/q6afe.h"
+#include "sdw.h"
#define DEFAULT_MCLK_RATE 19200000
#define RT5682_PLL_FREQ (48000 * 512)
@@ -316,6 +317,7 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
switch (cpu_dai->id) {
case MI2S_PRIMARY:
@@ -333,6 +335,9 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
default:
break;
}
+
+ data->sruntime[cpu_dai->id] = NULL;
+ sdw_release_stream(sruntime);
}
static int sc7280_snd_startup(struct snd_pcm_substream *substream)
@@ -347,6 +352,8 @@ static int sc7280_snd_startup(struct snd_pcm_substream *substream)
switch (cpu_dai->id) {
case MI2S_PRIMARY:
ret = sc7280_rt5682_init(rtd);
+ if (ret)
+ return ret;
break;
case SECONDARY_MI2S_RX:
codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
@@ -360,7 +367,8 @@ static int sc7280_snd_startup(struct snd_pcm_substream *substream)
default:
break;
}
- return ret;
+
+ return qcom_snd_sdw_startup(substream);
}
static const struct snd_soc_ops sc7280_ops = {
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 75701546b6ea..a479d7e5b7fb 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -15,6 +15,7 @@
#include <uapi/linux/input-event-codes.h>
#include "common.h"
#include "qdsp6/q6afe.h"
+#include "sdw.h"
#include "../codecs/rt5663.h"
#define DRIVER_NAME "sdm845"
@@ -416,7 +417,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
}
- return 0;
+ return qcom_snd_sdw_startup(substream);
}
static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
@@ -425,6 +426,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
@@ -463,6 +465,9 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
}
+
+ data->sruntime[cpu_dai->id] = NULL;
+ sdw_release_stream(sruntime);
}
static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 9784718a2b6f..eca5ce096e54 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1281,7 +1281,9 @@ audio_graph:
if (!of_node_name_eq(ports, "ports") &&
!of_node_name_eq(ports, "port"))
continue;
- priv->component_dais[i] = of_graph_get_endpoint_count(ports);
+ priv->component_dais[i] =
+ of_graph_get_endpoint_count(of_node_name_eq(ports, "ports") ?
+ ports : np);
nr += priv->component_dais[i];
i++;
if (i >= RSND_MAX_COMPONENT) {
@@ -1493,7 +1495,8 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
if (!of_node_name_eq(ports, "ports") &&
!of_node_name_eq(ports, "port"))
continue;
- for_each_endpoint_of_node(ports, dai_np) {
+ for_each_endpoint_of_node(of_node_name_eq(ports, "ports") ?
+ ports : np, dai_np) {
__rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
rdai = rsnd_rdai_get(priv, dai_i);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 9330f1a3f758..99521c784a9b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1147,6 +1147,8 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
if (*list == NULL)
return -ENOMEM;
+ (*list)->num_widgets = size;
+
list_for_each_entry(w, widgets, work_list)
(*list)->widgets[i++] = w;
@@ -2785,10 +2787,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s)
{
- struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
+ struct snd_soc_component *component = widget->dapm->component;
const char *wname = widget->name;
- if (component->name_prefix)
+ if (component && component->name_prefix)
wname += strlen(component->name_prefix) + 1; /* plus space */
return strcmp(wname, s);
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index 19f10dd77e4b..077af9e2af8d 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -206,7 +206,10 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
configure_pte_for_fw_loading(FW_SRAM_DATA_BIN, ACP_SRAM_PAGE_COUNT, adata);
src_addr = ACP_SYSTEM_MEMORY_WINDOW + ACP_DEFAULT_SRAM_LENGTH +
(page_count * ACP_PAGE_SIZE);
- dest_addr = ACP_SRAM_BASE_ADDRESS;
+ if (adata->pci_rev > ACP63_PCI_ID)
+ dest_addr = ACP7X_SRAM_BASE_ADDRESS;
+ else
+ dest_addr = ACP_SRAM_BASE_ADDRESS;
ret = configure_and_run_dma(adata, src_addr, dest_addr,
adata->fw_sram_data_bin_size);
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index d579c3849392..95d4762c9d93 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -329,7 +329,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
fw_qualifier, fw_qualifier & DSP_FW_RUN_ENABLE,
ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US);
if (ret < 0) {
- dev_err(sdev->dev, "PSP validation failed\n");
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SHA_PSP_ACK);
+ dev_err(sdev->dev, "PSP validation failed: fw_qualifier = %#x, ACP_SHA_PSP_ACK = %#x\n",
+ fw_qualifier, val);
return ret;
}
@@ -340,11 +342,19 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)
{
struct snd_sof_dev *sdev = adata->dev;
unsigned int val;
+ unsigned int acp_dma_ch_sts;
int ret = 0;
+ switch (adata->pci_rev) {
+ case ACP70_PCI_ID:
+ acp_dma_ch_sts = ACP70_DMA_CH_STS;
+ break;
+ default:
+ acp_dma_ch_sts = ACP_DMA_CH_STS;
+ }
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DMA_CNTL_0 + ch * sizeof(u32));
if (val & ACP_DMA_CH_RUN) {
- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_DMA_CH_STS, val, !val,
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, acp_dma_ch_sts, val, !val,
ACP_REG_POLL_INTERVAL,
ACP_DMA_COMPLETE_TIMEOUT_US);
if (ret < 0)
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index 484c76147885..92681ca7f24d 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -346,20 +346,21 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_stream_start(hext_stream);
break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_hdac_ext_stream_clear(hext_stream);
-
/*
- * Save the LLP registers in case the stream is
- * restarting due PAUSE_RELEASE, or START without a pcm
- * close/open since in this case the LLP register is not reset
- * to 0 and the delay calculation will return with invalid
- * results.
+ * Save the LLP registers since in case of PAUSE the LLP
+ * register are not reset to 0, the delay calculation will use
+ * the saved offsets for compensating the delay calculation.
*/
hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
+ snd_hdac_ext_stream_clear(hext_stream);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ hext_stream->pplcllpl = 0;
+ hext_stream->pplcllpu = 0;
+ snd_hdac_ext_stream_clear(hext_stream);
break;
default:
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
@@ -512,7 +513,6 @@ static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
- struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
switch (cmd) {
@@ -527,9 +527,6 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
if (ret < 0)
return ret;
- if (cmd == SNDRV_PCM_TRIGGER_STOP)
- return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
-
break;
}
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 1c823f9eea57..ac505c7ad342 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -302,6 +302,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
}
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
ret = hda_link_dma_cleanup(substream, hext_stream, dai);
if (ret < 0) {
@@ -370,6 +371,13 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
/* use HDaudio stream handling */
ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
if (ret < 0) {
@@ -377,7 +385,6 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
return ret;
}
- sdev = widget_to_sdev(w);
if (sdev->dspless_mode_selected)
return 0;
@@ -482,6 +489,31 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int ret;
int i;
+ ops = hda_dai_get_ops(substream, cpu_dai);
+ if (!ops) {
+ dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+ return -EINVAL;
+ }
+
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
+ /*
+ * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
+ * due to xruns or after a call to snd_pcm_drain/drop()
+ */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ 0, 0, substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
data.dai_index = (link_id << 8) | cpu_dai->id;
data.dai_node_id = intel_alh_id;
ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
@@ -490,10 +522,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ops = hda_dai_get_ops(substream, cpu_dai);
- sdev = widget_to_sdev(w);
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
-
if (!hext_stream)
return -ENODEV;
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 75f6240cf3e1..9d8ebb7c6a10 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -294,14 +294,9 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
- struct sof_intel_hda_stream *hda_stream;
- unsigned long time_left;
unsigned int reg;
int ret, status;
- hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
- hext_stream);
-
dev_dbg(sdev->dev, "Code loader DMA starting\n");
ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
@@ -310,18 +305,6 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
return ret;
}
- if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
- /* Wait for completion of transfer */
- time_left = wait_for_completion_timeout(&hda_stream->ioc,
- msecs_to_jiffies(HDA_CL_DMA_IOC_TIMEOUT_MS));
-
- if (!time_left) {
- dev_err(sdev->dev, "Code loader DMA did not complete\n");
- return -ETIMEDOUT;
- }
- dev_dbg(sdev->dev, "Code loader DMA done\n");
- }
-
dev_dbg(sdev->dev, "waiting for FW_ENTERED status\n");
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 87be7f16e8c2..240fee2166d1 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -3129,9 +3129,20 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
* group_id during copier's ipc_prepare op.
*/
if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
+ struct sof_ipc4_alh_configuration_blob *blob;
+
+ blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
ipc4_copier->dai_index = data->dai_node_id;
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_node_id);
+
+ /*
+ * no need to set the node_id for aggregated DAI's. These will be assigned
+ * a group_id during widget ipc_prepare
+ */
+ if (blob->alh_cfg.device_count == 1) {
+ copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+ copier_data->gtw_cfg.node_id |=
+ SOF_IPC4_NODE_INDEX(data->dai_node_id);
+ }
}
break;
diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c
index 796eac0a2e74..603aed222480 100644
--- a/sound/soc/sof/sof-client-probes-ipc4.c
+++ b/sound/soc/sof/sof-client-probes-ipc4.c
@@ -125,6 +125,7 @@ static int ipc4_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
msg.extension = SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(INVALID_PIPELINE_ID);
msg.extension |= SOF_IPC4_MOD_EXT_CORE_ID(0);
+ msg.extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(sizeof(cfg) / sizeof(uint32_t));
msg.data_size = sizeof(cfg);
msg.data_ptr = &cfg;
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 7bc4a96b7503..5828f9dd866e 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -317,7 +317,7 @@ static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai,
int div;
div = DIV_ROUND_CLOSEST(input_rate, output_rate);
- if (div > SAI_XCR1_MCKDIV_MAX(version)) {
+ if (div > SAI_XCR1_MCKDIV_MAX(version) || div <= 0) {
dev_err(&sai->pdev->dev, "Divider %d out of range\n", div);
return -EINVAL;
}
@@ -378,8 +378,8 @@ static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
int div;
div = stm32_sai_get_clk_div(sai, *prate, rate);
- if (div < 0)
- return div;
+ if (div <= 0)
+ return -EINVAL;
mclk->freq = *prate / div;
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index d1b32ba1e1a2..9e30852de93c 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -939,7 +939,7 @@ static void stm32_spdifrx_remove(struct platform_device *pdev)
{
struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev);
- if (spdifrx->ctrl_chan)
+ if (!IS_ERR(spdifrx->ctrl_chan))
dma_release_channel(spdifrx->ctrl_chan);
if (spdifrx->dmab)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 9945ae55b0d0..bd67027c7677 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1205,6 +1205,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
}
break;
case USB_ID(0x1bcf, 0x2283): /* NexiGo N930AF FHD Webcam */
+ case USB_ID(0x03f0, 0x654a): /* HP 320 FHD Webcam */
if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
usb_audio_info(chip,
"set resolution quirk: cval->res = 16\n");
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 2a9594f34dac..6456e87e2f39 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -4042,6 +4042,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
break;
err = dell_dock_mixer_init(mixer);
break;
+ case USB_ID(0x0bda, 0x402e): /* Dell WD19 dock */
+ err = dell_dock_mixer_create(mixer);
+ break;
case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */
case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e6278a245795..c5fd180357d1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2114,6 +2114,8 @@ struct usb_audio_quirk_flags_table {
static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
/* Device matches */
+ DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */
diff --git a/tools/arch/arm64/include/asm/cputype.h b/tools/arch/arm64/include/asm/cputype.h
index 5a7dfeb8e8eb..488f8e751349 100644
--- a/tools/arch/arm64/include/asm/cputype.h
+++ b/tools/arch/arm64/include/asm/cputype.h
@@ -94,6 +94,7 @@
#define ARM_CPU_PART_NEOVERSE_V3 0xD84
#define ARM_CPU_PART_CORTEX_X925 0xD85
#define ARM_CPU_PART_CORTEX_A725 0xD87
+#define ARM_CPU_PART_NEOVERSE_N3 0xD8E
#define APM_CPU_PART_XGENE 0x000
#define APM_CPU_VAR_POTENZA 0x00
@@ -176,6 +177,7 @@
#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
#define MIDR_CORTEX_A725 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A725)
+#define MIDR_NEOVERSE_N3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N3)
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
diff --git a/tools/arch/x86/include/asm/msr-index.h b/tools/arch/x86/include/asm/msr-index.h
index a7c06a46fb76..3ae84c3b8e6d 100644
--- a/tools/arch/x86/include/asm/msr-index.h
+++ b/tools/arch/x86/include/asm/msr-index.h
@@ -36,6 +36,20 @@
#define EFER_FFXSR (1<<_EFER_FFXSR)
#define EFER_AUTOIBRS (1<<_EFER_AUTOIBRS)
+/*
+ * Architectural memory types that are common to MTRRs, PAT, VMX MSRs, etc.
+ * Most MSRs support/allow only a subset of memory types, but the values
+ * themselves are common across all relevant MSRs.
+ */
+#define X86_MEMTYPE_UC 0ull /* Uncacheable, a.k.a. Strong Uncacheable */
+#define X86_MEMTYPE_WC 1ull /* Write Combining */
+/* RESERVED 2 */
+/* RESERVED 3 */
+#define X86_MEMTYPE_WT 4ull /* Write Through */
+#define X86_MEMTYPE_WP 5ull /* Write Protected */
+#define X86_MEMTYPE_WB 6ull /* Write Back */
+#define X86_MEMTYPE_UC_MINUS 7ull /* Weak Uncacheabled (PAT only) */
+
/* FRED MSRs */
#define MSR_IA32_FRED_RSP0 0x1cc /* Level 0 stack pointer */
#define MSR_IA32_FRED_RSP1 0x1cd /* Level 1 stack pointer */
@@ -365,6 +379,12 @@
#define MSR_IA32_CR_PAT 0x00000277
+#define PAT_VALUE(p0, p1, p2, p3, p4, p5, p6, p7) \
+ ((X86_MEMTYPE_ ## p0) | (X86_MEMTYPE_ ## p1 << 8) | \
+ (X86_MEMTYPE_ ## p2 << 16) | (X86_MEMTYPE_ ## p3 << 24) | \
+ (X86_MEMTYPE_ ## p4 << 32) | (X86_MEMTYPE_ ## p5 << 40) | \
+ (X86_MEMTYPE_ ## p6 << 48) | (X86_MEMTYPE_ ## p7 << 56))
+
#define MSR_IA32_DEBUGCTLMSR 0x000001d9
#define MSR_IA32_LASTBRANCHFROMIP 0x000001db
#define MSR_IA32_LASTBRANCHTOIP 0x000001dc
@@ -1159,15 +1179,6 @@
#define MSR_IA32_VMX_VMFUNC 0x00000491
#define MSR_IA32_VMX_PROCBASED_CTLS3 0x00000492
-/* VMX_BASIC bits and bitmasks */
-#define VMX_BASIC_VMCS_SIZE_SHIFT 32
-#define VMX_BASIC_TRUE_CTLS (1ULL << 55)
-#define VMX_BASIC_64 0x0001000000000000LLU
-#define VMX_BASIC_MEM_TYPE_SHIFT 50
-#define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU
-#define VMX_BASIC_MEM_TYPE_WB 6LLU
-#define VMX_BASIC_INOUT 0x0040000000000000LLU
-
/* Resctrl MSRs: */
/* - Intel: */
#define MSR_IA32_L3_QOS_CFG 0xc81
@@ -1185,11 +1196,6 @@
#define MSR_IA32_SMBA_BW_BASE 0xc0000280
#define MSR_IA32_EVT_CFG_BASE 0xc0000400
-/* MSR_IA32_VMX_MISC bits */
-#define MSR_IA32_VMX_MISC_INTEL_PT (1ULL << 14)
-#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29)
-#define MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE 0x1F
-
/* AMD-V MSRs */
#define MSR_VM_CR 0xc0010114
#define MSR_VM_IGNNE 0xc0010115
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h
index bf57a824f722..a8debbf2f702 100644
--- a/tools/arch/x86/include/uapi/asm/kvm.h
+++ b/tools/arch/x86/include/uapi/asm/kvm.h
@@ -439,6 +439,7 @@ struct kvm_sync_regs {
#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4)
#define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5)
#define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6)
+#define KVM_X86_QUIRK_SLOT_ZAP_ALL (1 << 7)
#define KVM_STATE_NESTED_FORMAT_VMX 0
#define KVM_STATE_NESTED_FORMAT_SVM 1
diff --git a/tools/arch/x86/include/uapi/asm/unistd_32.h b/tools/arch/x86/include/uapi/asm/unistd_32.h
index 9de35df1afc3..63182a023e9d 100644
--- a/tools/arch/x86/include/uapi/asm/unistd_32.h
+++ b/tools/arch/x86/include/uapi/asm/unistd_32.h
@@ -11,6 +11,9 @@
#ifndef __NR_getpgid
#define __NR_getpgid 132
#endif
+#ifndef __NR_capget
+#define __NR_capget 184
+#endif
#ifndef __NR_gettid
#define __NR_gettid 224
#endif
diff --git a/tools/arch/x86/include/uapi/asm/unistd_64.h b/tools/arch/x86/include/uapi/asm/unistd_64.h
index d0f2043d7132..77311e8d1b5d 100644
--- a/tools/arch/x86/include/uapi/asm/unistd_64.h
+++ b/tools/arch/x86/include/uapi/asm/unistd_64.h
@@ -11,6 +11,9 @@
#ifndef __NR_getpgid
#define __NR_getpgid 121
#endif
+#ifndef __NR_capget
+#define __NR_capget 125
+#endif
#ifndef __NR_gettid
#define __NR_gettid 186
#endif
diff --git a/tools/include/linux/bits.h b/tools/include/linux/bits.h
index 0eb24d21aac2..60044b608817 100644
--- a/tools/include/linux/bits.h
+++ b/tools/include/linux/bits.h
@@ -36,4 +36,19 @@
#define GENMASK_ULL(h, l) \
(GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l))
+#if !defined(__ASSEMBLY__)
+/*
+ * Missing asm support
+ *
+ * __GENMASK_U128() depends on _BIT128() which would not work
+ * in the asm code, as it shifts an 'unsigned __init128' data
+ * type instead of direct representation of 128 bit constants
+ * such as long and unsigned long. The fundamental problem is
+ * that a 128 bit constant will get silently truncated by the
+ * gcc compiler.
+ */
+#define GENMASK_U128(h, l) \
+ (GENMASK_INPUT_CHECK(h, l) + __GENMASK_U128(h, l))
+#endif
+
#endif /* __LINUX_BITS_H */
diff --git a/tools/include/linux/unaligned.h b/tools/include/linux/unaligned.h
index bc0633bc4650..395a4464fe73 100644
--- a/tools/include/linux/unaligned.h
+++ b/tools/include/linux/unaligned.h
@@ -9,16 +9,7 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpacked"
#pragma GCC diagnostic ignored "-Wattributes"
-
-#define __get_unaligned_t(type, ptr) ({ \
- const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
- __pptr->x; \
-})
-
-#define __put_unaligned_t(type, val, ptr) do { \
- struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
- __pptr->x = (val); \
-} while (0)
+#include <vdso/unaligned.h>
#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
#define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr))
diff --git a/tools/include/uapi/linux/bits.h b/tools/include/uapi/linux/bits.h
index 3c2a101986a3..5ee30f882736 100644
--- a/tools/include/uapi/linux/bits.h
+++ b/tools/include/uapi/linux/bits.h
@@ -12,4 +12,7 @@
(((~_ULL(0)) - (_ULL(1) << (l)) + 1) & \
(~_ULL(0) >> (__BITS_PER_LONG_LONG - 1 - (h))))
+#define __GENMASK_U128(h, l) \
+ ((_BIT128((h)) << 1) - (_BIT128(l)))
+
#endif /* _UAPI_LINUX_BITS_H */
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index e8241b320c6d..4a939c90dc2e 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1121,6 +1121,9 @@ enum bpf_attach_type {
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
+/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
+ * in sync with the definitions below.
+ */
enum bpf_link_type {
BPF_LINK_TYPE_UNSPEC = 0,
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
diff --git a/tools/include/uapi/linux/const.h b/tools/include/uapi/linux/const.h
index a429381e7ca5..e16be0d37746 100644
--- a/tools/include/uapi/linux/const.h
+++ b/tools/include/uapi/linux/const.h
@@ -28,6 +28,23 @@
#define _BITUL(x) (_UL(1) << (x))
#define _BITULL(x) (_ULL(1) << (x))
+#if !defined(__ASSEMBLY__)
+/*
+ * Missing asm support
+ *
+ * __BIT128() would not work in the asm code, as it shifts an
+ * 'unsigned __init128' data type as direct representation of
+ * 128 bit constants is not supported in the gcc compiler, as
+ * they get silently truncated.
+ *
+ * TODO: Please revisit this implementation when gcc compiler
+ * starts representing 128 bit constants directly like long
+ * and unsigned long etc. Subsequently drop the comment for
+ * GENMASK_U128() which would then start supporting asm code.
+ */
+#define _BIT128(x) ((unsigned __int128)(1) << (x))
+#endif
+
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index e3ebb49f60d2..e4be227d3ad6 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -124,6 +124,7 @@ enum {
NETDEV_A_NAPI_PID,
NETDEV_A_NAPI_DEFER_HARD_IRQS,
NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT,
+ NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT,
__NETDEV_A_NAPI_MAX,
NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1)
diff --git a/tools/include/vdso/unaligned.h b/tools/include/vdso/unaligned.h
new file mode 100644
index 000000000000..eee3d2a4dbe4
--- /dev/null
+++ b/tools/include/vdso/unaligned.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_UNALIGNED_H
+#define __VDSO_UNALIGNED_H
+
+#define __get_unaligned_t(type, ptr) ({ \
+ const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
+ __pptr->x; \
+})
+
+#define __put_unaligned_t(type, val, ptr) do { \
+ struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
+ __pptr->x = (val); \
+} while (0)
+
+#endif /* __VDSO_UNALIGNED_H */
diff --git a/tools/lib/thermal/Makefile b/tools/lib/thermal/Makefile
index 2d0d255fd0e1..8890fd57b110 100644
--- a/tools/lib/thermal/Makefile
+++ b/tools/lib/thermal/Makefile
@@ -121,7 +121,9 @@ all: fixdep
clean:
$(call QUIET_CLEAN, libthermal) $(RM) $(LIBTHERMAL_A) \
- *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBTHERMAL_VERSION) .*.d .*.cmd LIBTHERMAL-CFLAGS $(LIBTHERMAL_PC)
+ *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBTHERMAL_VERSION) \
+ .*.d .*.cmd LIBTHERMAL-CFLAGS $(LIBTHERMAL_PC) \
+ $(srctree)/tools/$(THERMAL_UAPI)
$(LIBTHERMAL_PC):
$(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \
diff --git a/tools/lib/thermal/sampling.c b/tools/lib/thermal/sampling.c
index 70577423a9f0..f67c1f9ea1d7 100644
--- a/tools/lib/thermal/sampling.c
+++ b/tools/lib/thermal/sampling.c
@@ -16,6 +16,8 @@ static int handle_thermal_sample(struct nl_msg *n, void *arg)
struct thermal_handler_param *thp = arg;
struct thermal_handler *th = thp->th;
+ arg = thp->arg;
+
genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
switch (genlhdr->cmd) {
diff --git a/tools/mm/page-types.c b/tools/mm/page-types.c
index fa050d5a48cd..6eb17cc1a06c 100644
--- a/tools/mm/page-types.c
+++ b/tools/mm/page-types.c
@@ -22,6 +22,7 @@
#include <time.h>
#include <setjmp.h>
#include <signal.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
@@ -391,9 +392,9 @@ static void show_page_range(unsigned long voffset, unsigned long offset,
if (opt_file)
printf("%lx\t", voff);
if (opt_list_cgroup)
- printf("@%llu\t", (unsigned long long)cgroup0);
+ printf("@%" PRIu64 "\t", cgroup0);
if (opt_list_mapcnt)
- printf("%lu\t", mapcnt0);
+ printf("%" PRIu64 "\t", mapcnt0);
printf("%lx\t%lx\t%s\n",
index, count, page_flag_name(flags0));
}
@@ -419,9 +420,9 @@ static void show_page(unsigned long voffset, unsigned long offset,
if (opt_file)
printf("%lx\t", voffset);
if (opt_list_cgroup)
- printf("@%llu\t", (unsigned long long)cgroup);
+ printf("@%" PRIu64 "\t", cgroup)
if (opt_list_mapcnt)
- printf("%lu\t", mapcnt);
+ printf("%" PRIu64 "\t", mapcnt);
printf("%lx\t%s\n", offset, page_flag_name(flags));
}
diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c
index cfaeaea71042..04e9e6ba86ea 100644
--- a/tools/mm/slabinfo.c
+++ b/tools/mm/slabinfo.c
@@ -1297,7 +1297,9 @@ static void read_slab_dir(void)
slab->cpu_partial_free = get_obj("cpu_partial_free");
slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
slab->deactivate_bypass = get_obj("deactivate_bypass");
- chdir("..");
+ if (chdir(".."))
+ fatal("Unable to chdir from slab ../%s\n",
+ slab->name);
if (slab->name[0] == ':')
alias_targets++;
slab++;
diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py
index 9e95016b85b3..41d9fa5c818d 100755
--- a/tools/net/ynl/cli.py
+++ b/tools/net/ynl/cli.py
@@ -3,10 +3,11 @@
import argparse
import json
+import pathlib
import pprint
-import time
-import signal
+import sys
+sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import YnlFamily, Netlink, NlError
@@ -18,8 +19,6 @@ class YnlEncoder(json.JSONEncoder):
return list(obj)
return json.JSONEncoder.default(self, obj)
-def handle_timeout(sig, frame):
- exit(0)
def main():
description = """
@@ -46,7 +45,10 @@ def main():
group.add_argument('--list-ops', action='store_true')
group.add_argument('--list-msgs', action='store_true')
- parser.add_argument('--sleep', dest='sleep', type=int)
+ parser.add_argument('--duration', dest='duration', type=int,
+ help='when subscribed, watch for DURATION seconds')
+ parser.add_argument('--sleep', dest='duration', type=int,
+ help='alias for duration')
parser.add_argument('--subscribe', dest='ntf', type=str)
parser.add_argument('--replace', dest='flags', action='append_const',
const=Netlink.NLM_F_REPLACE)
@@ -83,10 +85,6 @@ def main():
if args.ntf:
ynl.ntf_subscribe(args.ntf)
- if args.sleep:
- signal.signal(signal.SIGALRM, handle_timeout)
- signal.alarm(args.sleep)
-
if args.list_ops:
for op_name, op in ynl.ops.items():
print(op_name, " [", ", ".join(op.modes), "]")
@@ -110,8 +108,11 @@ def main():
exit(1)
if args.ntf:
- for msg in ynl.check_ntf():
- output(msg)
+ try:
+ for msg in ynl.poll_ntf(duration=args.duration):
+ output(msg)
+ except KeyboardInterrupt:
+ pass
if __name__ == "__main__":
diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/ethtool.py
index 63c471f075ab..ebb0a11f67bf 100755
--- a/tools/net/ynl/ethtool.py
+++ b/tools/net/ynl/ethtool.py
@@ -3,11 +3,13 @@
import argparse
import json
+import pathlib
import pprint
import sys
import re
import os
+sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import YnlFamily
def args_to_req(ynl, op_name, args, req):
diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile
index 713f5fb9cc2d..7db5240de58a 100644
--- a/tools/net/ynl/generated/Makefile
+++ b/tools/net/ynl/generated/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
CC=gcc
-CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \
+CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \
-I../lib/ -idirafter $(UAPI_PATH)
ifeq ("$(DEBUG)","1")
CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile
index 2887cc5de530..94c49cca3dca 100644
--- a/tools/net/ynl/lib/Makefile
+++ b/tools/net/ynl/lib/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
CC=gcc
-CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow
+CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow
ifeq ("$(DEBUG)","1")
CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
endif
diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py
index b6d6f8aef423..a745739655ad 100644
--- a/tools/net/ynl/lib/nlspec.py
+++ b/tools/net/ynl/lib/nlspec.py
@@ -131,6 +131,9 @@ class SpecEnumSet(SpecElement):
def has_doc(self):
if 'doc' in self.yaml:
return True
+ return self.has_entry_doc()
+
+ def has_entry_doc(self):
for entry in self.entries.values():
if entry.has_doc():
return True
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 92f85698c50e..01ec01a90e76 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -13,6 +13,7 @@ import yaml
import ipaddress
import uuid
import queue
+import selectors
import time
from .nlspec import SpecFamily
@@ -907,37 +908,49 @@ class YnlFamily(SpecFamily):
msg['msg'] = attrs
self.async_msg_queue.put(msg)
- def check_ntf(self, interval=0.1):
+ def check_ntf(self):
while True:
try:
reply = self.sock.recv(self._recv_size, socket.MSG_DONTWAIT)
- nms = NlMsgs(reply)
- self._recv_dbg_print(reply, nms)
- for nl_msg in nms:
- if nl_msg.error:
- print("Netlink error in ntf!?", os.strerror(-nl_msg.error))
- print(nl_msg)
- continue
- if nl_msg.done:
- print("Netlink done while checking for ntf!?")
- continue
+ except BlockingIOError:
+ return
- decoded = self.nlproto.decode(self, nl_msg, None)
- if decoded.cmd() not in self.async_msg_ids:
- print("Unexpected msg id while checking for ntf", decoded)
- continue
+ nms = NlMsgs(reply)
+ self._recv_dbg_print(reply, nms)
+ for nl_msg in nms:
+ if nl_msg.error:
+ print("Netlink error in ntf!?", os.strerror(-nl_msg.error))
+ print(nl_msg)
+ continue
+ if nl_msg.done:
+ print("Netlink done while checking for ntf!?")
+ continue
- self.handle_ntf(decoded)
- except BlockingIOError:
- pass
+ decoded = self.nlproto.decode(self, nl_msg, None)
+ if decoded.cmd() not in self.async_msg_ids:
+ print("Unexpected msg id while checking for ntf", decoded)
+ continue
+
+ self.handle_ntf(decoded)
+ def poll_ntf(self, duration=None):
+ start_time = time.time()
+ selector = selectors.DefaultSelector()
+ selector.register(self.sock, selectors.EVENT_READ)
+
+ while True:
try:
yield self.async_msg_queue.get_nowait()
except queue.Empty:
- try:
- time.sleep(interval)
- except KeyboardInterrupt:
- return
+ if duration is not None:
+ timeout = start_time + duration - time.time()
+ if timeout <= 0:
+ return
+ else:
+ timeout = None
+ events = selector.select(timeout)
+ if events:
+ self.check_ntf()
def operation_do_attributes(self, name):
"""
diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile
index e194a7565861..c9494a564da4 100644
--- a/tools/net/ynl/samples/Makefile
+++ b/tools/net/ynl/samples/Makefile
@@ -3,7 +3,7 @@
include ../Makefile.deps
CC=gcc
-CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \
+CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \
-I../lib/ -I../generated/ -idirafter $(UAPI_PATH)
ifeq ("$(DEBUG)","1")
CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan
diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c
index 332f281ee5cb..e5d521320fbf 100644
--- a/tools/net/ynl/samples/page-pool.c
+++ b/tools/net/ynl/samples/page-pool.c
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
name = if_indextoname(s->ifc, ifname);
if (name)
printf("%8s", name);
- printf("[%d]\t", s->ifc);
+ printf("[%u]\t", s->ifc);
}
printf("page pools: %u (zombies: %u)\n",
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 1a825b4081b2..394b0023b9a3 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -4,12 +4,15 @@
import argparse
import collections
import filecmp
+import pathlib
import os
import re
import shutil
+import sys
import tempfile
import yaml
+sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix())
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
@@ -481,7 +484,7 @@ class TypeBinary(Type):
pass
elif len(self.checks) == 1:
check_name = list(self.checks)[0]
- if check_name not in {'exact-len', 'min-len'}:
+ if check_name not in {'exact-len', 'min-len', 'max-len'}:
raise Exception('Unsupported check for binary type: ' + check_name)
else:
raise Exception('More than one check for binary type not implemented, yet')
@@ -492,6 +495,8 @@ class TypeBinary(Type):
mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')'
elif 'min-len' in self.checks:
mem = '{ .len = ' + self.get_limit_str('min-len') + ', }'
+ elif 'max-len' in self.checks:
+ mem = 'NLA_POLICY_MAX_LEN(' + self.get_limit_str('max-len') + ')'
return mem
@@ -2435,11 +2440,15 @@ def render_uapi(family, cw):
enum = family.consts[const['name']]
if enum.has_doc():
- cw.p('/**')
- doc = ''
- if 'doc' in enum:
- doc = ' - ' + enum['doc']
- cw.write_doc_line(enum.enum_name + doc)
+ if enum.has_entry_doc():
+ cw.p('/**')
+ doc = ''
+ if 'doc' in enum:
+ doc = ' - ' + enum['doc']
+ cw.write_doc_line(enum.enum_name + doc)
+ else:
+ cw.p('/*')
+ cw.write_doc_line(enum['doc'], indent=False)
for entry in enum.entries.values():
if entry.has_doc():
doc = '@' + entry.c_name + ': ' + entry['doc']
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 4ddb27a48eed..d4332675babb 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -704,8 +704,8 @@ ifeq ($(BUILD_BPF_SKEL),1)
BUILD_BPF_SKEL := 0
else
CLANG_VERSION := $(shell $(CLANG) --version | head -1 | sed 's/.*clang version \([[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\).*/\1/g')
- ifeq ($(call version-lt3,$(CLANG_VERSION),16.0.6),1)
- $(warning Warning: Disabled BPF skeletons as at least $(CLANG) version 16.0.6 is reported to be a working setup with the current of BPF based perf features)
+ ifeq ($(call version-lt3,$(CLANG_VERSION),12.0.1),1)
+ $(warning Warning: Disabled BPF skeletons as reliable BTF generation needs at least $(CLANG) version 12.0.1)
BUILD_BPF_SKEL := 0
endif
endif
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index f6e847529073..d3f11b90d025 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1399,7 +1399,7 @@ static const struct syscall_fmt syscall_fmts[] = {
.arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
{ .name = "waitid", .errpid = true,
.arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
- { .name = "write", .errpid = true,
+ { .name = "write",
.arg = { [1] = { .scnprintf = SCA_BUF /* buf */, .from_user = true, }, }, },
};
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 29adbb423327..a05c1c105c51 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -22,6 +22,7 @@ FILES=(
"include/vdso/bits.h"
"include/linux/const.h"
"include/vdso/const.h"
+ "include/vdso/unaligned.h"
"include/linux/hash.h"
"include/linux/list-sort.h"
"include/uapi/linux/hw_breakpoint.h"
diff --git a/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh b/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh
index b5dc10b2a738..bead723e34af 100755
--- a/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh
+++ b/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh
@@ -19,35 +19,74 @@
TEST_RESULT=0
# skip if not supported
-BLACKFUNC=`head -n 1 /sys/kernel/debug/kprobes/blacklist 2> /dev/null | cut -f2`
-if [ -z "$BLACKFUNC" ]; then
+BLACKFUNC_LIST=`head -n 5 /sys/kernel/debug/kprobes/blacklist 2> /dev/null | cut -f2`
+if [ -z "$BLACKFUNC_LIST" ]; then
print_overall_skipped
exit 0
fi
+# try to find vmlinux with DWARF debug info
+VMLINUX_FILE=$(perf probe -v random_probe |& grep "Using.*for symbols" | sed -r 's/^Using (.*) for symbols$/\1/')
+
# remove all previously added probes
clear_all_probes
### adding blacklisted function
-
-# functions from blacklist should be skipped by perf probe
-! $CMD_PERF probe $BLACKFUNC > $LOGS_DIR/adding_blacklisted.log 2> $LOGS_DIR/adding_blacklisted.err
-PERF_EXIT_CODE=$?
-
REGEX_SCOPE_FAIL="Failed to find scope of probe point"
REGEX_SKIP_MESSAGE=" is blacklisted function, skip it\."
-REGEX_NOT_FOUND_MESSAGE="Probe point \'$BLACKFUNC\' not found."
+REGEX_NOT_FOUND_MESSAGE="Probe point \'$RE_EVENT\' not found."
REGEX_ERROR_MESSAGE="Error: Failed to add events."
REGEX_INVALID_ARGUMENT="Failed to write event: Invalid argument"
REGEX_SYMBOL_FAIL="Failed to find symbol at $RE_ADDRESS"
-REGEX_OUT_SECTION="$BLACKFUNC is out of \.\w+, skip it"
-../common/check_all_lines_matched.pl "$REGEX_SKIP_MESSAGE" "$REGEX_NOT_FOUND_MESSAGE" "$REGEX_ERROR_MESSAGE" "$REGEX_SCOPE_FAIL" "$REGEX_INVALID_ARGUMENT" "$REGEX_SYMBOL_FAIL" "$REGEX_OUT_SECTION" < $LOGS_DIR/adding_blacklisted.err
-CHECK_EXIT_CODE=$?
-
-print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "adding blacklisted function $BLACKFUNC"
-(( TEST_RESULT += $? ))
-
+REGEX_OUT_SECTION="$RE_EVENT is out of \.\w+, skip it"
+REGEX_MISSING_DECL_LINE="A function DIE doesn't have decl_line. Maybe broken DWARF?"
+
+BLACKFUNC=""
+SKIP_DWARF=0
+
+for BLACKFUNC in $BLACKFUNC_LIST; do
+ echo "Probing $BLACKFUNC"
+
+ # functions from blacklist should be skipped by perf probe
+ ! $CMD_PERF probe $BLACKFUNC > $LOGS_DIR/adding_blacklisted.log 2> $LOGS_DIR/adding_blacklisted.err
+ PERF_EXIT_CODE=$?
+
+ # check for bad DWARF polluting the result
+ ../common/check_all_patterns_found.pl "$REGEX_MISSING_DECL_LINE" >/dev/null < $LOGS_DIR/adding_blacklisted.err
+
+ if [ $? -eq 0 ]; then
+ SKIP_DWARF=1
+ echo "Result polluted by broken DWARF, trying another probe"
+
+ # confirm that the broken DWARF comes from assembler
+ if [ -n "$VMLINUX_FILE" ]; then
+ readelf -wi "$VMLINUX_FILE" |
+ awk -v probe="$BLACKFUNC" '/DW_AT_language/ { comp_lang = $0 }
+ $0 ~ probe { if (comp_lang) { print comp_lang }; exit }' |
+ grep -q "MIPS assembler"
+
+ CHECK_EXIT_CODE=$?
+ if [ $CHECK_EXIT_CODE -ne 0 ]; then
+ SKIP_DWARF=0 # broken DWARF while available
+ break
+ fi
+ fi
+ else
+ ../common/check_all_lines_matched.pl "$REGEX_SKIP_MESSAGE" "$REGEX_NOT_FOUND_MESSAGE" "$REGEX_ERROR_MESSAGE" "$REGEX_SCOPE_FAIL" "$REGEX_INVALID_ARGUMENT" "$REGEX_SYMBOL_FAIL" "$REGEX_OUT_SECTION" < $LOGS_DIR/adding_blacklisted.err
+ CHECK_EXIT_CODE=$?
+
+ SKIP_DWARF=0
+ break
+ fi
+done
+
+if [ $SKIP_DWARF -eq 1 ]; then
+ print_testcase_skipped "adding blacklisted function $BLACKFUNC"
+else
+ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "adding blacklisted function $BLACKFUNC"
+ (( TEST_RESULT += $? ))
+fi
### listing not-added probe
diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
index b2f17cca014b..4a62ed593e84 100644
--- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
+++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
@@ -288,6 +288,10 @@ int sys_enter_rename(struct syscall_enter_args *args)
augmented_args->arg.size = PERF_ALIGN(oldpath_len + 1, sizeof(u64));
len += augmented_args->arg.size;
+ /* Every read from userspace is limited to value size */
+ if (augmented_args->arg.size > sizeof(augmented_args->arg.value))
+ return 1; /* Failure: don't filter */
+
struct augmented_arg *arg2 = (void *)&augmented_args->arg.value + augmented_args->arg.size;
newpath_len = augmented_arg__read_str(arg2, newpath_arg, sizeof(augmented_args->arg.value));
@@ -315,6 +319,10 @@ int sys_enter_renameat2(struct syscall_enter_args *args)
augmented_args->arg.size = PERF_ALIGN(oldpath_len + 1, sizeof(u64));
len += augmented_args->arg.size;
+ /* Every read from userspace is limited to value size */
+ if (augmented_args->arg.size > sizeof(augmented_args->arg.value))
+ return 1; /* Failure: don't filter */
+
struct augmented_arg *arg2 = (void *)&augmented_args->arg.value + augmented_args->arg.size;
newpath_len = augmented_arg__read_str(arg2, newpath_arg, sizeof(augmented_args->arg.value));
@@ -423,8 +431,9 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
{
bool augmented, do_output = false;
- int zero = 0, size, aug_size, index, output = 0,
+ int zero = 0, size, aug_size, index,
value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value);
+ u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */
unsigned int nr, *beauty_map;
struct beauty_payload_enter *payload;
void *arg, *payload_offset;
@@ -477,6 +486,8 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
augmented = true;
} else if (size < 0 && size >= -6) { /* buffer */
index = -(size + 1);
+ barrier_var(index); // Prevent clang (noticed with v18) from removing the &= 7 trick.
+ index &= 7; // Satisfy the bounds checking with the verifier in some kernels.
aug_size = args->args[index];
if (aug_size > TRACE_AUG_MAX_BUF)
@@ -488,10 +499,17 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
}
}
+ /* Augmented data size is limited to sizeof(augmented_arg->unnamed union with value field) */
+ if (aug_size > value_size)
+ aug_size = value_size;
+
/* write data to payload */
if (augmented) {
int written = offsetof(struct augmented_arg, value) + aug_size;
+ if (written < 0 || written > sizeof(struct augmented_arg))
+ return 1;
+
((struct augmented_arg *)payload_offset)->size = aug_size;
output += written;
payload_offset += written;
@@ -499,7 +517,7 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
}
}
- if (!do_output)
+ if (!do_output || (sizeof(struct syscall_enter_args) + output) > sizeof(struct beauty_payload_enter))
return 1;
return augmented__beauty_output(ctx, payload, sizeof(struct syscall_enter_args) + output);
diff --git a/tools/perf/util/cap.c b/tools/perf/util/cap.c
index 7574a67651bc..69d9a2bcd40b 100644
--- a/tools/perf/util/cap.c
+++ b/tools/perf/util/cap.c
@@ -7,13 +7,9 @@
#include "debug.h"
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include <linux/capability.h>
#include <sys/syscall.h>
-
-#ifndef SYS_capget
-#define SYS_capget 90
-#endif
+#include <unistd.h>
#define MAX_LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
@@ -21,9 +17,9 @@ bool perf_cap__capable(int cap, bool *used_root)
{
struct __user_cap_header_struct header = {
.version = _LINUX_CAPABILITY_VERSION_3,
- .pid = getpid(),
+ .pid = 0,
};
- struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S];
+ struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S] = {};
__u32 cap_val;
*used_root = false;
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 31a223eaf8e6..ee3d43a7ba45 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -19,6 +19,7 @@
#include "util/bpf-filter.h"
#include "util/env.h"
#include "util/kvm-stat.h"
+#include "util/stat.h"
#include "util/kwork.h"
#include "util/sample.h"
#include "util/lock-contention.h"
@@ -1355,6 +1356,7 @@ error:
unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
+#ifdef HAVE_KVM_STAT_SUPPORT
bool kvm_entry_event(struct evsel *evsel __maybe_unused)
{
return false;
@@ -1384,6 +1386,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
char *decode __maybe_unused)
{
}
+#endif // HAVE_KVM_STAT_SUPPORT
int find_scripts(char **scripts_array __maybe_unused, char **scripts_path_array __maybe_unused,
int num __maybe_unused, int pathlen __maybe_unused)
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c
index 7c15dec6900d..6c45ded922b6 100644
--- a/tools/perf/util/syscalltbl.c
+++ b/tools/perf/util/syscalltbl.c
@@ -46,6 +46,11 @@ static const char *const *syscalltbl_native = syscalltbl_mips_n64;
#include <asm/syscalls.c>
const int syscalltbl_native_max_id = SYSCALLTBL_LOONGARCH_MAX_ID;
static const char *const *syscalltbl_native = syscalltbl_loongarch;
+#else
+const int syscalltbl_native_max_id = 0;
+static const char *const syscalltbl_native[] = {
+ [0] = "unknown",
+};
#endif
struct syscall {
@@ -182,6 +187,11 @@ int syscalltbl__id(struct syscalltbl *tbl, const char *name)
return audit_name_to_syscall(name, tbl->audit_machine);
}
+int syscalltbl__id_at_idx(struct syscalltbl *tbl __maybe_unused, int idx)
+{
+ return idx;
+}
+
int syscalltbl__strglobmatch_next(struct syscalltbl *tbl __maybe_unused,
const char *syscall_glob __maybe_unused, int *idx __maybe_unused)
{
diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index 27749c51c3ec..248ab790d143 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -320,7 +320,7 @@ u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym;
/*
* Access a cpumask in read-only mode (typically to check bits).
*/
-const struct cpumask *cast_mask(struct bpf_cpumask *mask)
+static __always_inline const struct cpumask *cast_mask(struct bpf_cpumask *mask)
{
return (const struct cpumask *)mask;
}
diff --git a/tools/sched_ext/scx_show_state.py b/tools/sched_ext/scx_show_state.py
index 8bc626ede1c4..c4b3fdda9a0b 100644
--- a/tools/sched_ext/scx_show_state.py
+++ b/tools/sched_ext/scx_show_state.py
@@ -35,6 +35,6 @@ print(f'enabled : {read_static_key("__scx_ops_enabled")}')
print(f'switching_all : {read_int("scx_switching_all")}')
print(f'switched_all : {read_static_key("__scx_switched_all")}')
print(f'enable_state : {ops_state_str(enable_state)} ({enable_state})')
-print(f'bypass_depth : {read_atomic("scx_ops_bypass_depth")}')
+print(f'bypass_depth : {prog["scx_ops_bypass_depth"].value_()}')
print(f'nr_rejected : {read_atomic("scx_nr_rejected")}')
print(f'enable_seq : {read_atomic("scx_enable_seq")}')
diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
index 90d5afd52dd0..050725afa45d 100644
--- a/tools/testing/cxl/test/cxl.c
+++ b/tools/testing/cxl/test/cxl.c
@@ -693,26 +693,22 @@ static int mock_decoder_commit(struct cxl_decoder *cxld)
return 0;
}
-static int mock_decoder_reset(struct cxl_decoder *cxld)
+static void mock_decoder_reset(struct cxl_decoder *cxld)
{
struct cxl_port *port = to_cxl_port(cxld->dev.parent);
int id = cxld->id;
if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
- return 0;
+ return;
dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
- if (port->commit_end != id) {
+ if (port->commit_end == id)
+ cxl_port_commit_reap(cxld);
+ else
dev_dbg(&port->dev,
"%s: out of order reset, expected decoder%d.%d\n",
dev_name(&cxld->dev), port->id, port->commit_end);
- return -EBUSY;
- }
-
- port->commit_end--;
cxld->flags &= ~CXL_DECODER_F_ENABLE;
-
- return 0;
}
static void default_mock_decoder(struct cxl_decoder *cxld)
@@ -1062,7 +1058,7 @@ static void mock_companion(struct acpi_device *adev, struct device *dev)
#define SZ_64G (SZ_32G * 2)
#endif
-static __init int cxl_rch_init(void)
+static __init int cxl_rch_topo_init(void)
{
int rc, i;
@@ -1090,30 +1086,8 @@ static __init int cxl_rch_init(void)
goto err_bridge;
}
- for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
- int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
- struct platform_device *rch = cxl_rch[i];
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("cxl_rcd", idx);
- if (!pdev)
- goto err_mem;
- pdev->dev.parent = &rch->dev;
- set_dev_node(&pdev->dev, i % 2);
-
- rc = platform_device_add(pdev);
- if (rc) {
- platform_device_put(pdev);
- goto err_mem;
- }
- cxl_rcd[i] = pdev;
- }
-
return 0;
-err_mem:
- for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
- platform_device_unregister(cxl_rcd[i]);
err_bridge:
for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
struct platform_device *pdev = cxl_rch[i];
@@ -1127,12 +1101,10 @@ err_bridge:
return rc;
}
-static void cxl_rch_exit(void)
+static void cxl_rch_topo_exit(void)
{
int i;
- for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
- platform_device_unregister(cxl_rcd[i]);
for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
struct platform_device *pdev = cxl_rch[i];
@@ -1143,7 +1115,7 @@ static void cxl_rch_exit(void)
}
}
-static __init int cxl_single_init(void)
+static __init int cxl_single_topo_init(void)
{
int i, rc;
@@ -1228,29 +1200,8 @@ static __init int cxl_single_init(void)
cxl_swd_single[i] = pdev;
}
- for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {
- struct platform_device *dport = cxl_swd_single[i];
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);
- if (!pdev)
- goto err_mem;
- pdev->dev.parent = &dport->dev;
- set_dev_node(&pdev->dev, i % 2);
-
- rc = platform_device_add(pdev);
- if (rc) {
- platform_device_put(pdev);
- goto err_mem;
- }
- cxl_mem_single[i] = pdev;
- }
-
return 0;
-err_mem:
- for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
- platform_device_unregister(cxl_mem_single[i]);
err_dport:
for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
platform_device_unregister(cxl_swd_single[i]);
@@ -1273,12 +1224,10 @@ err_bridge:
return rc;
}
-static void cxl_single_exit(void)
+static void cxl_single_topo_exit(void)
{
int i;
- for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
- platform_device_unregister(cxl_mem_single[i]);
for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
platform_device_unregister(cxl_swd_single[i]);
for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
@@ -1295,6 +1244,91 @@ static void cxl_single_exit(void)
}
}
+static void cxl_mem_exit(void)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_rcd[i]);
+ for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_mem_single[i]);
+ for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_mem[i]);
+}
+
+static int cxl_mem_init(void)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
+ struct platform_device *dport = cxl_switch_dport[i];
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("cxl_mem", i);
+ if (!pdev)
+ goto err_mem;
+ pdev->dev.parent = &dport->dev;
+ set_dev_node(&pdev->dev, i % 2);
+
+ rc = platform_device_add(pdev);
+ if (rc) {
+ platform_device_put(pdev);
+ goto err_mem;
+ }
+ cxl_mem[i] = pdev;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {
+ struct platform_device *dport = cxl_swd_single[i];
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);
+ if (!pdev)
+ goto err_single;
+ pdev->dev.parent = &dport->dev;
+ set_dev_node(&pdev->dev, i % 2);
+
+ rc = platform_device_add(pdev);
+ if (rc) {
+ platform_device_put(pdev);
+ goto err_single;
+ }
+ cxl_mem_single[i] = pdev;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
+ int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
+ struct platform_device *rch = cxl_rch[i];
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("cxl_rcd", idx);
+ if (!pdev)
+ goto err_rcd;
+ pdev->dev.parent = &rch->dev;
+ set_dev_node(&pdev->dev, i % 2);
+
+ rc = platform_device_add(pdev);
+ if (rc) {
+ platform_device_put(pdev);
+ goto err_rcd;
+ }
+ cxl_rcd[i] = pdev;
+ }
+
+ return 0;
+
+err_rcd:
+ for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_rcd[i]);
+err_single:
+ for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_mem_single[i]);
+err_mem:
+ for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
+ platform_device_unregister(cxl_mem[i]);
+ return rc;
+}
+
static __init int cxl_test_init(void)
{
int rc, i;
@@ -1407,29 +1441,11 @@ static __init int cxl_test_init(void)
cxl_switch_dport[i] = pdev;
}
- for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
- struct platform_device *dport = cxl_switch_dport[i];
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("cxl_mem", i);
- if (!pdev)
- goto err_mem;
- pdev->dev.parent = &dport->dev;
- set_dev_node(&pdev->dev, i % 2);
-
- rc = platform_device_add(pdev);
- if (rc) {
- platform_device_put(pdev);
- goto err_mem;
- }
- cxl_mem[i] = pdev;
- }
-
- rc = cxl_single_init();
+ rc = cxl_single_topo_init();
if (rc)
- goto err_mem;
+ goto err_dport;
- rc = cxl_rch_init();
+ rc = cxl_rch_topo_init();
if (rc)
goto err_single;
@@ -1442,19 +1458,20 @@ static __init int cxl_test_init(void)
rc = platform_device_add(cxl_acpi);
if (rc)
- goto err_add;
+ goto err_root;
+
+ rc = cxl_mem_init();
+ if (rc)
+ goto err_root;
return 0;
-err_add:
+err_root:
platform_device_put(cxl_acpi);
err_rch:
- cxl_rch_exit();
+ cxl_rch_topo_exit();
err_single:
- cxl_single_exit();
-err_mem:
- for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
- platform_device_unregister(cxl_mem[i]);
+ cxl_single_topo_exit();
err_dport:
for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
platform_device_unregister(cxl_switch_dport[i]);
@@ -1486,11 +1503,10 @@ static __exit void cxl_test_exit(void)
{
int i;
+ cxl_mem_exit();
platform_device_unregister(cxl_acpi);
- cxl_rch_exit();
- cxl_single_exit();
- for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
- platform_device_unregister(cxl_mem[i]);
+ cxl_rch_topo_exit();
+ cxl_single_topo_exit();
for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
platform_device_unregister(cxl_switch_dport[i]);
for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index ad5c4c18c5c6..71916e0e1546 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -1673,6 +1673,7 @@ static struct platform_driver cxl_mock_mem_driver = {
.name = KBUILD_MODNAME,
.dev_groups = cxl_mock_mem_groups,
.groups = cxl_mock_mem_core_groups,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index e6533b3400de..7e88551f2d38 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -24,7 +24,6 @@ test_flow_dissector
flow_dissector_load
test_tcpnotify_user
test_libbpf
-test_tcp_check_syncookie_user
test_sysctl
xdping
test_cpp
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 75016962f795..9ec53c858d8d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -137,7 +137,6 @@ TEST_PROGS := test_kmod.sh \
test_xdp_vlan_mode_generic.sh \
test_xdp_vlan_mode_native.sh \
test_lwt_ip_encap.sh \
- test_tcp_check_syncookie.sh \
test_tc_tunnel.sh \
test_tc_edt.sh \
test_xdping.sh \
@@ -154,11 +153,23 @@ TEST_PROGS_EXTENDED := with_addr.sh \
# Compile but not part of 'make run_tests'
TEST_GEN_PROGS_EXTENDED = \
- flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
- test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
- xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \
- xdp_features bpf_test_no_cfi.ko bpf_test_modorder_x.ko \
- bpf_test_modorder_y.ko
+ bench \
+ bpf_testmod.ko \
+ bpf_test_modorder_x.ko \
+ bpf_test_modorder_y.ko \
+ bpf_test_no_cfi.ko \
+ flow_dissector_load \
+ runqslower \
+ test_cpp \
+ test_flow_dissector \
+ test_lirc_mode2_user \
+ veristat \
+ xdp_features \
+ xdp_hw_metadata \
+ xdp_redirect_multi \
+ xdp_synproxy \
+ xdping \
+ xskxceiver
TEST_GEN_FILES += liburandom_read.so urandom_read sign-file uprobe_multi
@@ -361,7 +372,6 @@ $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
$(OUTPUT)/test_maps: $(TESTING_HELPERS)
$(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS)
$(OUTPUT)/xsk.o: $(BPFOBJ)
-$(OUTPUT)/test_tcp_check_syncookie_user: $(NETWORK_HELPERS)
BPFTOOL ?= $(DEFAULT_BPFTOOL)
$(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
diff --git a/tools/testing/selftests/bpf/map_tests/lpm_trie_map_get_next_key.c b/tools/testing/selftests/bpf/map_tests/lpm_trie_map_get_next_key.c
new file mode 100644
index 000000000000..0ba015686492
--- /dev/null
+++ b/tools/testing/selftests/bpf/map_tests/lpm_trie_map_get_next_key.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <linux/bpf.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+#include <test_maps.h>
+
+struct test_lpm_key {
+ __u32 prefix;
+ __u32 data;
+};
+
+struct get_next_key_ctx {
+ struct test_lpm_key key;
+ bool start;
+ bool stop;
+ int map_fd;
+ int loop;
+};
+
+static void *get_next_key_fn(void *arg)
+{
+ struct get_next_key_ctx *ctx = arg;
+ struct test_lpm_key next_key;
+ int i = 0;
+
+ while (!ctx->start)
+ usleep(1);
+
+ while (!ctx->stop && i++ < ctx->loop)
+ bpf_map_get_next_key(ctx->map_fd, &ctx->key, &next_key);
+
+ return NULL;
+}
+
+static void abort_get_next_key(struct get_next_key_ctx *ctx, pthread_t *tids,
+ unsigned int nr)
+{
+ unsigned int i;
+
+ ctx->stop = true;
+ ctx->start = true;
+ for (i = 0; i < nr; i++)
+ pthread_join(tids[i], NULL);
+}
+
+/* This test aims to prevent regression of future. As long as the kernel does
+ * not panic, it is considered as success.
+ */
+void test_lpm_trie_map_get_next_key(void)
+{
+#define MAX_NR_THREADS 8
+ LIBBPF_OPTS(bpf_map_create_opts, create_opts,
+ .map_flags = BPF_F_NO_PREALLOC);
+ struct test_lpm_key key = {};
+ __u32 val = 0;
+ int map_fd;
+ const __u32 max_prefixlen = 8 * (sizeof(key) - sizeof(key.prefix));
+ const __u32 max_entries = max_prefixlen + 1;
+ unsigned int i, nr = MAX_NR_THREADS, loop = 65536;
+ pthread_t tids[MAX_NR_THREADS];
+ struct get_next_key_ctx ctx;
+ int err;
+
+ map_fd = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE, "lpm_trie_map",
+ sizeof(struct test_lpm_key), sizeof(__u32),
+ max_entries, &create_opts);
+ CHECK(map_fd == -1, "bpf_map_create()", "error:%s\n",
+ strerror(errno));
+
+ for (i = 0; i <= max_prefixlen; i++) {
+ key.prefix = i;
+ err = bpf_map_update_elem(map_fd, &key, &val, BPF_ANY);
+ CHECK(err, "bpf_map_update_elem()", "error:%s\n",
+ strerror(errno));
+ }
+
+ ctx.start = false;
+ ctx.stop = false;
+ ctx.map_fd = map_fd;
+ ctx.loop = loop;
+ memcpy(&ctx.key, &key, sizeof(key));
+
+ for (i = 0; i < nr; i++) {
+ err = pthread_create(&tids[i], NULL, get_next_key_fn, &ctx);
+ if (err) {
+ abort_get_next_key(&ctx, tids, i);
+ CHECK(err, "pthread_create", "error %d\n", err);
+ }
+ }
+
+ ctx.start = true;
+ for (i = 0; i < nr; i++)
+ pthread_join(tids[i], NULL);
+
+ printf("%s:PASS\n", __func__);
+
+ close(map_fd);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c b/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
index ef4d6a3ae423..cf15cc3be491 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
@@ -17,32 +17,37 @@
#include "test_progs.h"
#include "test_btf_skc_cls_ingress.skel.h"
-static struct test_btf_skc_cls_ingress *skel;
-static struct sockaddr_in6 srv_sa6;
-static __u32 duration;
+#define TEST_NS "skc_cls_ingress"
-static int prepare_netns(void)
+#define BIT(n) (1 << (n))
+#define TEST_MODE_IPV4 BIT(0)
+#define TEST_MODE_IPV6 BIT(1)
+#define TEST_MODE_DUAL (TEST_MODE_IPV4 | TEST_MODE_IPV6)
+
+#define SERVER_ADDR_IPV4 "127.0.0.1"
+#define SERVER_ADDR_IPV6 "::1"
+#define SERVER_ADDR_DUAL "::0"
+/* RFC791, 576 for minimal IPv4 datagram, minus 40 bytes of TCP header */
+#define MIN_IPV4_MSS 536
+
+static struct netns_obj *prepare_netns(struct test_btf_skc_cls_ingress *skel)
{
LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS);
LIBBPF_OPTS(bpf_tc_opts, tc_attach,
.prog_fd = bpf_program__fd(skel->progs.cls_ingress));
+ struct netns_obj *ns = NULL;
- if (CHECK(unshare(CLONE_NEWNET), "create netns",
- "unshare(CLONE_NEWNET): %s (%d)",
- strerror(errno), errno))
- return -1;
-
- if (CHECK(system("ip link set dev lo up"),
- "ip link set dev lo up", "failed\n"))
- return -1;
+ ns = netns_new(TEST_NS, true);
+ if (!ASSERT_OK_PTR(ns, "create and join netns"))
+ return ns;
qdisc_lo.ifindex = if_nametoindex("lo");
if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact"))
- return -1;
+ goto free_ns;
if (!ASSERT_OK(bpf_tc_attach(&qdisc_lo, &tc_attach),
"filter add dev lo ingress"))
- return -1;
+ goto free_ns;
/* Ensure 20 bytes options (i.e. in total 40 bytes tcp header) for the
* bpf_tcp_gen_syncookie() helper.
@@ -50,71 +55,142 @@ static int prepare_netns(void)
if (write_sysctl("/proc/sys/net/ipv4/tcp_window_scaling", "1") ||
write_sysctl("/proc/sys/net/ipv4/tcp_timestamps", "1") ||
write_sysctl("/proc/sys/net/ipv4/tcp_sack", "1"))
- return -1;
+ goto free_ns;
+
+ return ns;
- return 0;
+free_ns:
+ netns_free(ns);
+ return NULL;
}
-static void reset_test(void)
+static void reset_test(struct test_btf_skc_cls_ingress *skel)
{
+ memset(&skel->bss->srv_sa4, 0, sizeof(skel->bss->srv_sa4));
memset(&skel->bss->srv_sa6, 0, sizeof(skel->bss->srv_sa6));
skel->bss->listen_tp_sport = 0;
skel->bss->req_sk_sport = 0;
skel->bss->recv_cookie = 0;
skel->bss->gen_cookie = 0;
skel->bss->linum = 0;
+ skel->bss->mss = 0;
}
-static void print_err_line(void)
+static void print_err_line(struct test_btf_skc_cls_ingress *skel)
{
if (skel->bss->linum)
printf("bpf prog error at line %u\n", skel->bss->linum);
}
-static void test_conn(void)
+static int v6only_true(int fd, void *opts)
+{
+ int mode = true;
+
+ return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));
+}
+
+static int v6only_false(int fd, void *opts)
{
+ int mode = false;
+
+ return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));
+}
+
+static void run_test(struct test_btf_skc_cls_ingress *skel, bool gen_cookies,
+ int ip_mode)
+{
+ const char *tcp_syncookies = gen_cookies ? "2" : "1";
int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
- socklen_t addrlen = sizeof(srv_sa6);
+ struct network_helper_opts opts = { 0 };
+ struct sockaddr_storage *addr;
+ struct sockaddr_in6 srv_sa6;
+ struct sockaddr_in srv_sa4;
+ socklen_t addr_len;
+ int sock_family;
+ char *srv_addr;
int srv_port;
- if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
+ switch (ip_mode) {
+ case TEST_MODE_IPV4:
+ sock_family = AF_INET;
+ srv_addr = SERVER_ADDR_IPV4;
+ addr = (struct sockaddr_storage *)&srv_sa4;
+ addr_len = sizeof(srv_sa4);
+ break;
+ case TEST_MODE_IPV6:
+ opts.post_socket_cb = v6only_true;
+ sock_family = AF_INET6;
+ srv_addr = SERVER_ADDR_IPV6;
+ addr = (struct sockaddr_storage *)&srv_sa6;
+ addr_len = sizeof(srv_sa6);
+ break;
+ case TEST_MODE_DUAL:
+ opts.post_socket_cb = v6only_false;
+ sock_family = AF_INET6;
+ srv_addr = SERVER_ADDR_DUAL;
+ addr = (struct sockaddr_storage *)&srv_sa6;
+ addr_len = sizeof(srv_sa6);
+ break;
+ default:
+ PRINT_FAIL("Unknown IP mode %d", ip_mode);
return;
+ }
- listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
- if (CHECK_FAIL(listen_fd == -1))
+ if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", tcp_syncookies))
return;
- err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen);
- if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err,
- errno))
- goto done;
- memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6));
- srv_port = ntohs(srv_sa6.sin6_port);
+ listen_fd = start_server_str(sock_family, SOCK_STREAM, srv_addr, 0,
+ &opts);
+ if (!ASSERT_OK_FD(listen_fd, "start server"))
+ return;
- cli_fd = connect_to_fd(listen_fd, 0);
- if (CHECK_FAIL(cli_fd == -1))
+ err = getsockname(listen_fd, (struct sockaddr *)addr, &addr_len);
+ if (!ASSERT_OK(err, "getsockname(listen_fd)"))
goto done;
- srv_fd = accept(listen_fd, NULL, NULL);
- if (CHECK_FAIL(srv_fd == -1))
+ switch (ip_mode) {
+ case TEST_MODE_IPV4:
+ memcpy(&skel->bss->srv_sa4, &srv_sa4, sizeof(srv_sa4));
+ srv_port = ntohs(srv_sa4.sin_port);
+ break;
+ case TEST_MODE_IPV6:
+ case TEST_MODE_DUAL:
+ memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6));
+ srv_port = ntohs(srv_sa6.sin6_port);
+ break;
+ default:
goto done;
+ }
- if (CHECK(skel->bss->listen_tp_sport != srv_port ||
- skel->bss->req_sk_sport != srv_port,
- "Unexpected sk src port",
- "listen_tp_sport:%u req_sk_sport:%u expected:%u\n",
- skel->bss->listen_tp_sport, skel->bss->req_sk_sport,
- srv_port))
+ cli_fd = connect_to_fd(listen_fd, 0);
+ if (!ASSERT_OK_FD(cli_fd, "connect client"))
goto done;
- if (CHECK(skel->bss->gen_cookie || skel->bss->recv_cookie,
- "Unexpected syncookie states",
- "gen_cookie:%u recv_cookie:%u\n",
- skel->bss->gen_cookie, skel->bss->recv_cookie))
+ srv_fd = accept(listen_fd, NULL, NULL);
+ if (!ASSERT_OK_FD(srv_fd, "accept connection"))
goto done;
- CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n",
- skel->bss->linum);
+ ASSERT_EQ(skel->bss->listen_tp_sport, srv_port, "listen tp src port");
+
+ if (!gen_cookies) {
+ ASSERT_EQ(skel->bss->req_sk_sport, srv_port,
+ "request socket source port with syncookies disabled");
+ ASSERT_EQ(skel->bss->gen_cookie, 0,
+ "generated syncookie with syncookies disabled");
+ ASSERT_EQ(skel->bss->recv_cookie, 0,
+ "received syncookie with syncookies disabled");
+ } else {
+ ASSERT_EQ(skel->bss->req_sk_sport, 0,
+ "request socket source port with syncookies enabled");
+ ASSERT_NEQ(skel->bss->gen_cookie, 0,
+ "syncookie properly generated");
+ ASSERT_EQ(skel->bss->gen_cookie, skel->bss->recv_cookie,
+ "matching syncookies on client and server");
+ ASSERT_GT(skel->bss->mss, MIN_IPV4_MSS,
+ "MSS in cookie min value");
+ ASSERT_LT(skel->bss->mss, USHRT_MAX,
+ "MSS in cookie max value");
+ }
done:
if (listen_fd != -1)
@@ -125,96 +201,74 @@ done:
close(srv_fd);
}
-static void test_syncookie(void)
+static void test_conn_ipv4(struct test_btf_skc_cls_ingress *skel)
{
- int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
- socklen_t addrlen = sizeof(srv_sa6);
- int srv_port;
-
- /* Enforce syncookie mode */
- if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
- return;
-
- listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
- if (CHECK_FAIL(listen_fd == -1))
- return;
-
- err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen);
- if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err,
- errno))
- goto done;
- memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6));
- srv_port = ntohs(srv_sa6.sin6_port);
-
- cli_fd = connect_to_fd(listen_fd, 0);
- if (CHECK_FAIL(cli_fd == -1))
- goto done;
-
- srv_fd = accept(listen_fd, NULL, NULL);
- if (CHECK_FAIL(srv_fd == -1))
- goto done;
+ run_test(skel, false, TEST_MODE_IPV4);
+}
- if (CHECK(skel->bss->listen_tp_sport != srv_port,
- "Unexpected tp src port",
- "listen_tp_sport:%u expected:%u\n",
- skel->bss->listen_tp_sport, srv_port))
- goto done;
+static void test_conn_ipv6(struct test_btf_skc_cls_ingress *skel)
+{
+ run_test(skel, false, TEST_MODE_IPV6);
+}
- if (CHECK(skel->bss->req_sk_sport,
- "Unexpected req_sk src port",
- "req_sk_sport:%u expected:0\n",
- skel->bss->req_sk_sport))
- goto done;
+static void test_conn_dual(struct test_btf_skc_cls_ingress *skel)
+{
+ run_test(skel, false, TEST_MODE_DUAL);
+}
- if (CHECK(!skel->bss->gen_cookie ||
- skel->bss->gen_cookie != skel->bss->recv_cookie,
- "Unexpected syncookie states",
- "gen_cookie:%u recv_cookie:%u\n",
- skel->bss->gen_cookie, skel->bss->recv_cookie))
- goto done;
+static void test_syncookie_ipv4(struct test_btf_skc_cls_ingress *skel)
+{
+ run_test(skel, true, TEST_MODE_IPV4);
+}
- CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n",
- skel->bss->linum);
+static void test_syncookie_ipv6(struct test_btf_skc_cls_ingress *skel)
+{
+ run_test(skel, true, TEST_MODE_IPV6);
+}
-done:
- if (listen_fd != -1)
- close(listen_fd);
- if (cli_fd != -1)
- close(cli_fd);
- if (srv_fd != -1)
- close(srv_fd);
+static void test_syncookie_dual(struct test_btf_skc_cls_ingress *skel)
+{
+ run_test(skel, true, TEST_MODE_DUAL);
}
struct test {
const char *desc;
- void (*run)(void);
+ void (*run)(struct test_btf_skc_cls_ingress *skel);
};
#define DEF_TEST(name) { #name, test_##name }
static struct test tests[] = {
- DEF_TEST(conn),
- DEF_TEST(syncookie),
+ DEF_TEST(conn_ipv4),
+ DEF_TEST(conn_ipv6),
+ DEF_TEST(conn_dual),
+ DEF_TEST(syncookie_ipv4),
+ DEF_TEST(syncookie_ipv6),
+ DEF_TEST(syncookie_dual),
};
void test_btf_skc_cls_ingress(void)
{
+ struct test_btf_skc_cls_ingress *skel;
+ struct netns_obj *ns;
int i;
skel = test_btf_skc_cls_ingress__open_and_load();
- if (CHECK(!skel, "test_btf_skc_cls_ingress__open_and_load", "failed\n"))
+ if (!ASSERT_OK_PTR(skel, "test_btf_skc_cls_ingress__open_and_load"))
return;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
if (!test__start_subtest(tests[i].desc))
continue;
- if (prepare_netns())
+ ns = prepare_netns(skel);
+ if (!ns)
break;
- tests[i].run();
+ tests[i].run(skel);
- print_err_line();
- reset_test();
+ print_err_line(skel);
+ reset_test(skel);
+ netns_free(ns);
}
test_btf_skc_cls_ingress__destroy(skel);
diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
index be3cad2aff77..f8eb7f9d4fd2 100644
--- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
+++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c
@@ -69,24 +69,6 @@ struct mptcp_storage {
char ca_name[TCP_CA_NAME_MAX];
};
-static struct nstoken *create_netns(void)
-{
- SYS(fail, "ip netns add %s", NS_TEST);
- SYS(fail, "ip -net %s link set dev lo up", NS_TEST);
-
- return open_netns(NS_TEST);
-fail:
- return NULL;
-}
-
-static void cleanup_netns(struct nstoken *nstoken)
-{
- if (nstoken)
- close_netns(nstoken);
-
- SYS_NOFAIL("ip netns del %s", NS_TEST);
-}
-
static int start_mptcp_server(int family, const char *addr_str, __u16 port,
int timeout_ms)
{
@@ -206,15 +188,15 @@ out:
static void test_base(void)
{
- struct nstoken *nstoken = NULL;
+ struct netns_obj *netns = NULL;
int server_fd, cgroup_fd;
cgroup_fd = test__join_cgroup("/mptcp");
if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))
return;
- nstoken = create_netns();
- if (!ASSERT_OK_PTR(nstoken, "create_netns"))
+ netns = netns_new(NS_TEST, true);
+ if (!ASSERT_OK_PTR(netns, "netns_new"))
goto fail;
/* without MPTCP */
@@ -237,7 +219,7 @@ with_mptcp:
close(server_fd);
fail:
- cleanup_netns(nstoken);
+ netns_free(netns);
close(cgroup_fd);
}
@@ -322,21 +304,21 @@ out:
static void test_mptcpify(void)
{
- struct nstoken *nstoken = NULL;
+ struct netns_obj *netns = NULL;
int cgroup_fd;
cgroup_fd = test__join_cgroup("/mptcpify");
if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))
return;
- nstoken = create_netns();
- if (!ASSERT_OK_PTR(nstoken, "create_netns"))
+ netns = netns_new(NS_TEST, true);
+ if (!ASSERT_OK_PTR(netns, "netns_new"))
goto fail;
ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify");
fail:
- cleanup_netns(nstoken);
+ netns_free(netns);
close(cgroup_fd);
}
@@ -414,7 +396,7 @@ close_server:
static void test_subflow(void)
{
struct mptcp_subflow *skel;
- struct nstoken *nstoken;
+ struct netns_obj *netns;
int cgroup_fd;
cgroup_fd = test__join_cgroup("/mptcp_subflow");
@@ -437,8 +419,8 @@ static void test_subflow(void)
if (!ASSERT_OK_PTR(skel->links._getsockopt_subflow, "attach _getsockopt_subflow"))
goto skel_destroy;
- nstoken = create_netns();
- if (!ASSERT_OK_PTR(nstoken, "create_netns: mptcp_subflow"))
+ netns = netns_new(NS_TEST, true);
+ if (!ASSERT_OK_PTR(netns, "netns_new: mptcp_subflow"))
goto skel_destroy;
if (endpoint_init("subflow") < 0)
@@ -447,7 +429,7 @@ static void test_subflow(void)
run_subflow();
close_netns:
- cleanup_netns(nstoken);
+ netns_free(netns);
skel_destroy:
mptcp_subflow__destroy(skel);
close_cgroup:
diff --git a/tools/testing/selftests/bpf/prog_tests/test_csum_diff.c b/tools/testing/selftests/bpf/prog_tests/test_csum_diff.c
new file mode 100644
index 000000000000..107b20d43e83
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/test_csum_diff.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates */
+#include <test_progs.h>
+#include "csum_diff_test.skel.h"
+
+#define BUFF_SZ 512
+
+struct testcase {
+ unsigned long long to_buff[BUFF_SZ / 8];
+ unsigned int to_buff_len;
+ unsigned long long from_buff[BUFF_SZ / 8];
+ unsigned int from_buff_len;
+ unsigned short seed;
+ unsigned short result;
+};
+
+#define NUM_PUSH_TESTS 4
+
+struct testcase push_tests[NUM_PUSH_TESTS] = {
+ {
+ .to_buff = {
+ 0xdeadbeefdeadbeef,
+ },
+ .to_buff_len = 8,
+ .from_buff = {},
+ .from_buff_len = 0,
+ .seed = 0,
+ .result = 0x3b3b
+ },
+ {
+ .to_buff = {
+ 0xdeadbeefdeadbeef,
+ 0xbeefdeadbeefdead,
+ },
+ .to_buff_len = 16,
+ .from_buff = {},
+ .from_buff_len = 0,
+ .seed = 0x1234,
+ .result = 0x88aa
+ },
+ {
+ .to_buff = {
+ 0xdeadbeefdeadbeef,
+ 0xbeefdeadbeefdead,
+ },
+ .to_buff_len = 15,
+ .from_buff = {},
+ .from_buff_len = 0,
+ .seed = 0x1234,
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ .result = 0xcaa9
+#else
+ .result = 0x87fd
+#endif
+ },
+ {
+ .to_buff = {
+ 0x327b23c66b8b4567,
+ 0x66334873643c9869,
+ 0x19495cff74b0dc51,
+ 0x625558ec2ae8944a,
+ 0x46e87ccd238e1f29,
+ 0x507ed7ab3d1b58ba,
+ 0x41b71efb2eb141f2,
+ 0x7545e14679e2a9e3,
+ 0x5bd062c2515f007c,
+ 0x4db127f812200854,
+ 0x1f16e9e80216231b,
+ 0x66ef438d1190cde7,
+ 0x3352255a140e0f76,
+ 0x0ded7263109cf92e,
+ 0x1befd79f7fdcc233,
+ 0x6b68079a41a7c4c9,
+ 0x25e45d324e6afb66,
+ 0x431bd7b7519b500d,
+ 0x7c83e4583f2dba31,
+ 0x62bbd95a257130a3,
+ 0x628c895d436c6125,
+ 0x721da317333ab105,
+ 0x2d1d5ae92443a858,
+ 0x75a2a8d46763845e,
+ 0x79838cb208edbdab,
+ 0x0b03e0c64353d0cd,
+ 0x54e49eb4189a769b,
+ 0x2ca8861171f32454,
+ 0x02901d820836c40e,
+ 0x081386413a95f874,
+ 0x7c3dbd3d1e7ff521,
+ 0x6ceaf087737b8ddc,
+ 0x4516dde922221a70,
+ 0x614fd4a13006c83e,
+ 0x5577f8e1419ac241,
+ 0x05072367440badfc,
+ 0x77465f013804823e,
+ 0x5c482a977724c67e,
+ 0x5e884adc2463b9ea,
+ 0x2d51779651ead36b,
+ 0x153ea438580bd78f,
+ 0x70a64e2a3855585c,
+ 0x2a487cb06a2342ec,
+ 0x725a06fb1d4ed43b,
+ 0x57e4ccaf2cd89a32,
+ 0x4b588f547a6d8d3c,
+ 0x6de91b18542289ec,
+ 0x7644a45c38437fdb,
+ 0x684a481a32fff902,
+ 0x749abb43579478fe,
+ 0x1ba026fa3dc240fb,
+ 0x75c6c33a79a1deaa,
+ 0x70c6a52912e685fb,
+ 0x374a3fe6520eedd1,
+ 0x23f9c13c4f4ef005,
+ 0x275ac794649bb77c,
+ 0x1cf10fd839386575,
+ 0x235ba861180115be,
+ 0x354fe9f947398c89,
+ 0x741226bb15b5af5c,
+ 0x10233c990d34b6a8,
+ 0x615740953f6ab60f,
+ 0x77ae35eb7e0c57b1,
+ 0x310c50b3579be4f1,
+ },
+ .to_buff_len = 512,
+ .from_buff = {},
+ .from_buff_len = 0,
+ .seed = 0xffff,
+ .result = 0xca45
+ },
+};
+
+#define NUM_PULL_TESTS 4
+
+struct testcase pull_tests[NUM_PULL_TESTS] = {
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef,
+ },
+ .from_buff_len = 8,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0,
+ .result = 0xc4c4
+ },
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef,
+ 0xbeefdeadbeefdead,
+ },
+ .from_buff_len = 16,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0x1234,
+ .result = 0x9bbd
+ },
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef,
+ 0xbeefdeadbeefdead,
+ },
+ .from_buff_len = 15,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0x1234,
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ .result = 0x59be
+#else
+ .result = 0x9c6a
+#endif
+ },
+ {
+ .from_buff = {
+ 0x327b23c66b8b4567,
+ 0x66334873643c9869,
+ 0x19495cff74b0dc51,
+ 0x625558ec2ae8944a,
+ 0x46e87ccd238e1f29,
+ 0x507ed7ab3d1b58ba,
+ 0x41b71efb2eb141f2,
+ 0x7545e14679e2a9e3,
+ 0x5bd062c2515f007c,
+ 0x4db127f812200854,
+ 0x1f16e9e80216231b,
+ 0x66ef438d1190cde7,
+ 0x3352255a140e0f76,
+ 0x0ded7263109cf92e,
+ 0x1befd79f7fdcc233,
+ 0x6b68079a41a7c4c9,
+ 0x25e45d324e6afb66,
+ 0x431bd7b7519b500d,
+ 0x7c83e4583f2dba31,
+ 0x62bbd95a257130a3,
+ 0x628c895d436c6125,
+ 0x721da317333ab105,
+ 0x2d1d5ae92443a858,
+ 0x75a2a8d46763845e,
+ 0x79838cb208edbdab,
+ 0x0b03e0c64353d0cd,
+ 0x54e49eb4189a769b,
+ 0x2ca8861171f32454,
+ 0x02901d820836c40e,
+ 0x081386413a95f874,
+ 0x7c3dbd3d1e7ff521,
+ 0x6ceaf087737b8ddc,
+ 0x4516dde922221a70,
+ 0x614fd4a13006c83e,
+ 0x5577f8e1419ac241,
+ 0x05072367440badfc,
+ 0x77465f013804823e,
+ 0x5c482a977724c67e,
+ 0x5e884adc2463b9ea,
+ 0x2d51779651ead36b,
+ 0x153ea438580bd78f,
+ 0x70a64e2a3855585c,
+ 0x2a487cb06a2342ec,
+ 0x725a06fb1d4ed43b,
+ 0x57e4ccaf2cd89a32,
+ 0x4b588f547a6d8d3c,
+ 0x6de91b18542289ec,
+ 0x7644a45c38437fdb,
+ 0x684a481a32fff902,
+ 0x749abb43579478fe,
+ 0x1ba026fa3dc240fb,
+ 0x75c6c33a79a1deaa,
+ 0x70c6a52912e685fb,
+ 0x374a3fe6520eedd1,
+ 0x23f9c13c4f4ef005,
+ 0x275ac794649bb77c,
+ 0x1cf10fd839386575,
+ 0x235ba861180115be,
+ 0x354fe9f947398c89,
+ 0x741226bb15b5af5c,
+ 0x10233c990d34b6a8,
+ 0x615740953f6ab60f,
+ 0x77ae35eb7e0c57b1,
+ 0x310c50b3579be4f1,
+ },
+ .from_buff_len = 512,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0xffff,
+ .result = 0x35ba
+ },
+};
+
+#define NUM_DIFF_TESTS 4
+
+struct testcase diff_tests[NUM_DIFF_TESTS] = {
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef,
+ },
+ .from_buff_len = 8,
+ .to_buff = {
+ 0xabababababababab,
+ },
+ .to_buff_len = 8,
+ .seed = 0,
+ .result = 0x7373
+ },
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef,
+ },
+ .from_buff_len = 7,
+ .to_buff = {
+ 0xabababababababab,
+ },
+ .to_buff_len = 7,
+ .seed = 0,
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ .result = 0xa673
+#else
+ .result = 0x73b7
+#endif
+ },
+ {
+ .from_buff = {
+ 0,
+ },
+ .from_buff_len = 8,
+ .to_buff = {
+ 0xabababababababab,
+ },
+ .to_buff_len = 8,
+ .seed = 0,
+ .result = 0xaeae
+ },
+ {
+ .from_buff = {
+ 0xdeadbeefdeadbeef
+ },
+ .from_buff_len = 8,
+ .to_buff = {
+ 0,
+ },
+ .to_buff_len = 8,
+ .seed = 0xffff,
+ .result = 0xc4c4
+ },
+};
+
+#define NUM_EDGE_TESTS 4
+
+struct testcase edge_tests[NUM_EDGE_TESTS] = {
+ {
+ .from_buff = {},
+ .from_buff_len = 0,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0,
+ .result = 0
+ },
+ {
+ .from_buff = {
+ 0x1234
+ },
+ .from_buff_len = 0,
+ .to_buff = {
+ 0x1234
+ },
+ .to_buff_len = 0,
+ .seed = 0,
+ .result = 0
+ },
+ {
+ .from_buff = {},
+ .from_buff_len = 0,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0x1234,
+ .result = 0x1234
+ },
+ {
+ .from_buff = {},
+ .from_buff_len = 512,
+ .to_buff = {},
+ .to_buff_len = 0,
+ .seed = 0xffff,
+ .result = 0xffff
+ },
+};
+
+static unsigned short trigger_csum_diff(const struct csum_diff_test *skel)
+{
+ u8 tmp_out[64 << 2] = {};
+ u8 tmp_in[64] = {};
+ int err;
+ int pfd;
+
+ LIBBPF_OPTS(bpf_test_run_opts, topts,
+ .data_in = tmp_in,
+ .data_size_in = sizeof(tmp_in),
+ .data_out = tmp_out,
+ .data_size_out = sizeof(tmp_out),
+ .repeat = 1,
+ );
+ pfd = bpf_program__fd(skel->progs.compute_checksum);
+ err = bpf_prog_test_run_opts(pfd, &topts);
+ if (err)
+ return -1;
+
+ return skel->bss->result;
+}
+
+static void test_csum_diff(struct testcase *tests, int num_tests)
+{
+ struct csum_diff_test *skel;
+ unsigned short got;
+ int err;
+
+ for (int i = 0; i < num_tests; i++) {
+ skel = csum_diff_test__open();
+ if (!ASSERT_OK_PTR(skel, "csum_diff_test open"))
+ return;
+
+ skel->rodata->to_buff_len = tests[i].to_buff_len;
+ skel->rodata->from_buff_len = tests[i].from_buff_len;
+
+ err = csum_diff_test__load(skel);
+ if (!ASSERT_EQ(err, 0, "csum_diff_test load"))
+ goto out;
+
+ memcpy(skel->bss->to_buff, tests[i].to_buff, tests[i].to_buff_len);
+ memcpy(skel->bss->from_buff, tests[i].from_buff, tests[i].from_buff_len);
+ skel->bss->seed = tests[i].seed;
+
+ got = trigger_csum_diff(skel);
+ ASSERT_EQ(got, tests[i].result, "csum_diff result");
+
+ csum_diff_test__destroy(skel);
+ }
+
+ return;
+out:
+ csum_diff_test__destroy(skel);
+}
+
+void test_test_csum_diff(void)
+{
+ if (test__start_subtest("csum_diff_push"))
+ test_csum_diff(push_tests, NUM_PUSH_TESTS);
+ if (test__start_subtest("csum_diff_pull"))
+ test_csum_diff(pull_tests, NUM_PULL_TESTS);
+ if (test__start_subtest("csum_diff_diff"))
+ test_csum_diff(diff_tests, NUM_DIFF_TESTS);
+ if (test__start_subtest("csum_diff_edge"))
+ test_csum_diff(edge_tests, NUM_EDGE_TESTS);
+}
diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index 5356f26bbb3f..75f7a2ce334b 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -54,6 +54,7 @@
#include "verifier_masking.skel.h"
#include "verifier_meta_access.skel.h"
#include "verifier_movsx.skel.h"
+#include "verifier_mtu.skel.h"
#include "verifier_netfilter_ctx.skel.h"
#include "verifier_netfilter_retcode.skel.h"
#include "verifier_bpf_fastcall.skel.h"
@@ -223,6 +224,24 @@ void test_verifier_xdp_direct_packet_access(void) { RUN(verifier_xdp_direct_pack
void test_verifier_bits_iter(void) { RUN(verifier_bits_iter); }
void test_verifier_lsm(void) { RUN(verifier_lsm); }
+void test_verifier_mtu(void)
+{
+ __u64 caps = 0;
+ int ret;
+
+ /* In case CAP_BPF and CAP_PERFMON is not set */
+ ret = cap_enable_effective(1ULL << CAP_BPF | 1ULL << CAP_NET_ADMIN, &caps);
+ if (!ASSERT_OK(ret, "set_cap_bpf_cap_net_admin"))
+ return;
+ ret = cap_disable_effective(1ULL << CAP_SYS_ADMIN | 1ULL << CAP_PERFMON, NULL);
+ if (!ASSERT_OK(ret, "disable_cap_sys_admin"))
+ goto restore_cap;
+ RUN(verifier_mtu);
+restore_cap:
+ if (caps)
+ cap_enable_effective(caps, NULL);
+}
+
static int init_test_val_map(struct bpf_object *obj, char *map_name)
{
struct test_val value = {
diff --git a/tools/testing/selftests/bpf/progs/csum_diff_test.c b/tools/testing/selftests/bpf/progs/csum_diff_test.c
new file mode 100644
index 000000000000..9438f1773a58
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/csum_diff_test.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates */
+#include <linux/types.h>
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+#define BUFF_SZ 512
+
+/* Will be updated by benchmark before program loading */
+char to_buff[BUFF_SZ];
+const volatile unsigned int to_buff_len = 0;
+char from_buff[BUFF_SZ];
+const volatile unsigned int from_buff_len = 0;
+unsigned short seed = 0;
+
+short result;
+
+char _license[] SEC("license") = "GPL";
+
+SEC("tc")
+int compute_checksum(void *ctx)
+{
+ int to_len_half = to_buff_len / 2;
+ int from_len_half = from_buff_len / 2;
+ short result2;
+
+ /* Calculate checksum in one go */
+ result2 = bpf_csum_diff((void *)from_buff, from_buff_len,
+ (void *)to_buff, to_buff_len, seed);
+
+ /* Calculate checksum by concatenating bpf_csum_diff()*/
+ result = bpf_csum_diff((void *)from_buff, from_buff_len - from_len_half,
+ (void *)to_buff, to_buff_len - to_len_half, seed);
+
+ result = bpf_csum_diff((void *)from_buff + (from_buff_len - from_len_half), from_len_half,
+ (void *)to_buff + (to_buff_len - to_len_half), to_len_half, result);
+
+ result = (result == result2) ? result : 0;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c b/tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c
index f0759efff6ef..1cd1a1b72cb5 100644
--- a/tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c
+++ b/tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c
@@ -10,16 +10,18 @@
#endif
struct sockaddr_in6 srv_sa6 = {};
+struct sockaddr_in srv_sa4 = {};
__u16 listen_tp_sport = 0;
__u16 req_sk_sport = 0;
__u32 recv_cookie = 0;
__u32 gen_cookie = 0;
+__u32 mss = 0;
__u32 linum = 0;
#define LOG() ({ if (!linum) linum = __LINE__; })
-static void test_syncookie_helper(struct ipv6hdr *ip6h, struct tcphdr *th,
- struct tcp_sock *tp,
+static void test_syncookie_helper(void *iphdr, int iphdr_size,
+ struct tcphdr *th, struct tcp_sock *tp,
struct __sk_buff *skb)
{
if (th->syn) {
@@ -38,17 +40,18 @@ static void test_syncookie_helper(struct ipv6hdr *ip6h, struct tcphdr *th,
return;
}
- mss_cookie = bpf_tcp_gen_syncookie(tp, ip6h, sizeof(*ip6h),
+ mss_cookie = bpf_tcp_gen_syncookie(tp, iphdr, iphdr_size,
th, 40);
if (mss_cookie < 0) {
if (mss_cookie != -ENOENT)
LOG();
} else {
gen_cookie = (__u32)mss_cookie;
+ mss = mss_cookie >> 32;
}
} else if (gen_cookie) {
/* It was in cookie mode */
- int ret = bpf_tcp_check_syncookie(tp, ip6h, sizeof(*ip6h),
+ int ret = bpf_tcp_check_syncookie(tp, iphdr, iphdr_size,
th, sizeof(*th));
if (ret < 0) {
@@ -60,26 +63,58 @@ static void test_syncookie_helper(struct ipv6hdr *ip6h, struct tcphdr *th,
}
}
-static int handle_ip6_tcp(struct ipv6hdr *ip6h, struct __sk_buff *skb)
+static int handle_ip_tcp(struct ethhdr *eth, struct __sk_buff *skb)
{
- struct bpf_sock_tuple *tuple;
+ struct bpf_sock_tuple *tuple = NULL;
+ unsigned int tuple_len = 0;
struct bpf_sock *bpf_skc;
- unsigned int tuple_len;
+ void *data_end, *iphdr;
+ struct ipv6hdr *ip6h;
+ struct iphdr *ip4h;
struct tcphdr *th;
- void *data_end;
+ int iphdr_size;
data_end = (void *)(long)(skb->data_end);
- th = (struct tcphdr *)(ip6h + 1);
- if (th + 1 > data_end)
- return TC_ACT_OK;
-
- /* Is it the testing traffic? */
- if (th->dest != srv_sa6.sin6_port)
+ switch (eth->h_proto) {
+ case bpf_htons(ETH_P_IP):
+ ip4h = (struct iphdr *)(eth + 1);
+ if (ip4h + 1 > data_end)
+ return TC_ACT_OK;
+ if (ip4h->protocol != IPPROTO_TCP)
+ return TC_ACT_OK;
+ th = (struct tcphdr *)(ip4h + 1);
+ if (th + 1 > data_end)
+ return TC_ACT_OK;
+ /* Is it the testing traffic? */
+ if (th->dest != srv_sa4.sin_port)
+ return TC_ACT_OK;
+ tuple_len = sizeof(tuple->ipv4);
+ tuple = (struct bpf_sock_tuple *)&ip4h->saddr;
+ iphdr = ip4h;
+ iphdr_size = sizeof(*ip4h);
+ break;
+ case bpf_htons(ETH_P_IPV6):
+ ip6h = (struct ipv6hdr *)(eth + 1);
+ if (ip6h + 1 > data_end)
+ return TC_ACT_OK;
+ if (ip6h->nexthdr != IPPROTO_TCP)
+ return TC_ACT_OK;
+ th = (struct tcphdr *)(ip6h + 1);
+ if (th + 1 > data_end)
+ return TC_ACT_OK;
+ /* Is it the testing traffic? */
+ if (th->dest != srv_sa6.sin6_port)
+ return TC_ACT_OK;
+ tuple_len = sizeof(tuple->ipv6);
+ tuple = (struct bpf_sock_tuple *)&ip6h->saddr;
+ iphdr = ip6h;
+ iphdr_size = sizeof(*ip6h);
+ break;
+ default:
return TC_ACT_OK;
+ }
- tuple_len = sizeof(tuple->ipv6);
- tuple = (struct bpf_sock_tuple *)&ip6h->saddr;
if ((void *)tuple + tuple_len > data_end) {
LOG();
return TC_ACT_OK;
@@ -126,7 +161,7 @@ static int handle_ip6_tcp(struct ipv6hdr *ip6h, struct __sk_buff *skb)
listen_tp_sport = tp->inet_conn.icsk_inet.sk.__sk_common.skc_num;
- test_syncookie_helper(ip6h, th, tp, skb);
+ test_syncookie_helper(iphdr, iphdr_size, th, tp, skb);
bpf_sk_release(tp);
return TC_ACT_OK;
}
@@ -142,7 +177,6 @@ release:
SEC("tc")
int cls_ingress(struct __sk_buff *skb)
{
- struct ipv6hdr *ip6h;
struct ethhdr *eth;
void *data_end;
@@ -152,17 +186,11 @@ int cls_ingress(struct __sk_buff *skb)
if (eth + 1 > data_end)
return TC_ACT_OK;
- if (eth->h_proto != bpf_htons(ETH_P_IPV6))
- return TC_ACT_OK;
-
- ip6h = (struct ipv6hdr *)(eth + 1);
- if (ip6h + 1 > data_end)
+ if (eth->h_proto != bpf_htons(ETH_P_IP) &&
+ eth->h_proto != bpf_htons(ETH_P_IPV6))
return TC_ACT_OK;
- if (ip6h->nexthdr == IPPROTO_TCP)
- return handle_ip6_tcp(ip6h, skb);
-
- return TC_ACT_OK;
+ return handle_ip_tcp(eth, skb);
}
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c b/tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c
deleted file mode 100644
index 6edebce563b5..000000000000
--- a/tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c
+++ /dev/null
@@ -1,167 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018 Facebook
-// Copyright (c) 2019 Cloudflare
-
-#include <string.h>
-
-#include <linux/bpf.h>
-#include <linux/pkt_cls.h>
-#include <linux/if_ether.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <sys/socket.h>
-#include <linux/tcp.h>
-
-#include <bpf/bpf_helpers.h>
-#include <bpf/bpf_endian.h>
-
-struct {
- __uint(type, BPF_MAP_TYPE_ARRAY);
- __type(key, __u32);
- __type(value, __u32);
- __uint(max_entries, 3);
-} results SEC(".maps");
-
-static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk,
- void *iph, __u32 ip_size,
- struct tcphdr *tcph)
-{
- __u32 thlen = tcph->doff * 4;
-
- if (tcph->syn && !tcph->ack) {
- // packet should only have an MSS option
- if (thlen != 24)
- return 0;
-
- if ((void *)tcph + thlen > data_end)
- return 0;
-
- return bpf_tcp_gen_syncookie(sk, iph, ip_size, tcph, thlen);
- }
- return 0;
-}
-
-static __always_inline void check_syncookie(void *ctx, void *data,
- void *data_end)
-{
- struct bpf_sock_tuple tup;
- struct bpf_sock *sk;
- struct ethhdr *ethh;
- struct iphdr *ipv4h;
- struct ipv6hdr *ipv6h;
- struct tcphdr *tcph;
- int ret;
- __u32 key_mss = 2;
- __u32 key_gen = 1;
- __u32 key = 0;
- __s64 seq_mss;
-
- ethh = data;
- if (ethh + 1 > data_end)
- return;
-
- switch (bpf_ntohs(ethh->h_proto)) {
- case ETH_P_IP:
- ipv4h = data + sizeof(struct ethhdr);
- if (ipv4h + 1 > data_end)
- return;
-
- if (ipv4h->ihl != 5)
- return;
-
- tcph = data + sizeof(struct ethhdr) + sizeof(struct iphdr);
- if (tcph + 1 > data_end)
- return;
-
- tup.ipv4.saddr = ipv4h->saddr;
- tup.ipv4.daddr = ipv4h->daddr;
- tup.ipv4.sport = tcph->source;
- tup.ipv4.dport = tcph->dest;
-
- sk = bpf_skc_lookup_tcp(ctx, &tup, sizeof(tup.ipv4),
- BPF_F_CURRENT_NETNS, 0);
- if (!sk)
- return;
-
- if (sk->state != BPF_TCP_LISTEN)
- goto release;
-
- seq_mss = gen_syncookie(data_end, sk, ipv4h, sizeof(*ipv4h),
- tcph);
-
- ret = bpf_tcp_check_syncookie(sk, ipv4h, sizeof(*ipv4h),
- tcph, sizeof(*tcph));
- break;
-
- case ETH_P_IPV6:
- ipv6h = data + sizeof(struct ethhdr);
- if (ipv6h + 1 > data_end)
- return;
-
- if (ipv6h->nexthdr != IPPROTO_TCP)
- return;
-
- tcph = data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
- if (tcph + 1 > data_end)
- return;
-
- memcpy(tup.ipv6.saddr, &ipv6h->saddr, sizeof(tup.ipv6.saddr));
- memcpy(tup.ipv6.daddr, &ipv6h->daddr, sizeof(tup.ipv6.daddr));
- tup.ipv6.sport = tcph->source;
- tup.ipv6.dport = tcph->dest;
-
- sk = bpf_skc_lookup_tcp(ctx, &tup, sizeof(tup.ipv6),
- BPF_F_CURRENT_NETNS, 0);
- if (!sk)
- return;
-
- if (sk->state != BPF_TCP_LISTEN)
- goto release;
-
- seq_mss = gen_syncookie(data_end, sk, ipv6h, sizeof(*ipv6h),
- tcph);
-
- ret = bpf_tcp_check_syncookie(sk, ipv6h, sizeof(*ipv6h),
- tcph, sizeof(*tcph));
- break;
-
- default:
- return;
- }
-
- if (seq_mss > 0) {
- __u32 cookie = (__u32)seq_mss;
- __u32 mss = seq_mss >> 32;
-
- bpf_map_update_elem(&results, &key_gen, &cookie, 0);
- bpf_map_update_elem(&results, &key_mss, &mss, 0);
- }
-
- if (ret == 0) {
- __u32 cookie = bpf_ntohl(tcph->ack_seq) - 1;
-
- bpf_map_update_elem(&results, &key, &cookie, 0);
- }
-
-release:
- bpf_sk_release(sk);
-}
-
-SEC("tc")
-int check_syncookie_clsact(struct __sk_buff *skb)
-{
- check_syncookie(skb, (void *)(long)skb->data,
- (void *)(long)skb->data_end);
- return TC_ACT_OK;
-}
-
-SEC("xdp")
-int check_syncookie_xdp(struct xdp_md *ctx)
-{
- check_syncookie(ctx, (void *)(long)ctx->data,
- (void *)(long)ctx->data_end);
- return XDP_PASS;
-}
-
-char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_array_access.c b/tools/testing/selftests/bpf/progs/verifier_array_access.c
index 95d7ecc12963..4195aa824ba5 100644
--- a/tools/testing/selftests/bpf/progs/verifier_array_access.c
+++ b/tools/testing/selftests/bpf/progs/verifier_array_access.c
@@ -368,8 +368,7 @@ __naked void a_read_only_array_2_1(void)
r4 = 0; \
r5 = 0; \
call %[bpf_csum_diff]; \
-l0_%=: r0 &= 0xffff; \
- exit; \
+l0_%=: exit; \
" :
: __imm(bpf_csum_diff),
__imm(bpf_map_lookup_elem),
diff --git a/tools/testing/selftests/bpf/progs/verifier_bits_iter.c b/tools/testing/selftests/bpf/progs/verifier_bits_iter.c
index f4da4d508ddb..7c881bca9af5 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bits_iter.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bits_iter.c
@@ -15,6 +15,8 @@ int bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign,
int *bpf_iter_bits_next(struct bpf_iter_bits *it) __ksym __weak;
void bpf_iter_bits_destroy(struct bpf_iter_bits *it) __ksym __weak;
+u64 bits_array[511] = {};
+
SEC("iter.s/cgroup")
__description("bits iter without destroy")
__failure __msg("Unreleased reference")
@@ -55,9 +57,15 @@ __description("null pointer")
__success __retval(0)
int null_pointer(void)
{
- int nr = 0;
+ struct bpf_iter_bits iter;
+ int err, nr = 0;
int *bit;
+ err = bpf_iter_bits_new(&iter, NULL, 1);
+ bpf_iter_bits_destroy(&iter);
+ if (err != -EINVAL)
+ return 1;
+
bpf_for_each(bits, bit, NULL, 1)
nr++;
return nr;
@@ -110,16 +118,16 @@ int bit_index(void)
}
SEC("syscall")
-__description("bits nomem")
+__description("bits too big")
__success __retval(0)
-int bits_nomem(void)
+int bits_too_big(void)
{
u64 data[4];
int nr = 0;
int *bit;
__builtin_memset(&data, 0xff, sizeof(data));
- bpf_for_each(bits, bit, &data[0], 513) /* Be greater than 512 */
+ bpf_for_each(bits, bit, &data[0], 512) /* Be greater than 511 */
nr++;
return nr;
}
@@ -151,3 +159,74 @@ int zero_words(void)
nr++;
return nr;
}
+
+SEC("syscall")
+__description("huge words")
+__success __retval(0)
+int huge_words(void)
+{
+ u64 data[8] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
+ int nr = 0;
+ int *bit;
+
+ bpf_for_each(bits, bit, &data[0], 67108865)
+ nr++;
+ return nr;
+}
+
+SEC("syscall")
+__description("max words")
+__success __retval(4)
+int max_words(void)
+{
+ volatile int nr = 0;
+ int *bit;
+
+ bits_array[0] = (1ULL << 63) | 1U;
+ bits_array[510] = (1ULL << 33) | (1ULL << 32);
+
+ bpf_for_each(bits, bit, bits_array, 511) {
+ if (nr == 0 && *bit != 0)
+ break;
+ if (nr == 2 && *bit != 32672)
+ break;
+ nr++;
+ }
+ return nr;
+}
+
+SEC("syscall")
+__description("bad words")
+__success __retval(0)
+int bad_words(void)
+{
+ void *bad_addr = (void *)-4095;
+ struct bpf_iter_bits iter;
+ volatile int nr;
+ int *bit;
+ int err;
+
+ err = bpf_iter_bits_new(&iter, bad_addr, 1);
+ bpf_iter_bits_destroy(&iter);
+ if (err != -EFAULT)
+ return 1;
+
+ nr = 0;
+ bpf_for_each(bits, bit, bad_addr, 1)
+ nr++;
+ if (nr != 0)
+ return 2;
+
+ err = bpf_iter_bits_new(&iter, bad_addr, 4);
+ bpf_iter_bits_destroy(&iter);
+ if (err != -EFAULT)
+ return 3;
+
+ nr = 0;
+ bpf_for_each(bits, bit, bad_addr, 4)
+ nr++;
+ if (nr != 0)
+ return 4;
+
+ return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
index 9da97d2efcd9..5094c288cfd7 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
@@ -790,61 +790,6 @@ __naked static void cumulative_stack_depth_subprog(void)
:: __imm(bpf_get_smp_processor_id) : __clobber_all);
}
-SEC("raw_tp")
-__arch_x86_64
-__log_level(4)
-__msg("stack depth 512")
-__xlated("0: r1 = 42")
-__xlated("1: *(u64 *)(r10 -512) = r1")
-__xlated("2: w0 = ")
-__xlated("3: r0 = &(void __percpu *)(r0)")
-__xlated("4: r0 = *(u32 *)(r0 +0)")
-__xlated("5: exit")
-__success
-__naked int bpf_fastcall_max_stack_ok(void)
-{
- asm volatile(
- "r1 = 42;"
- "*(u64 *)(r10 - %[max_bpf_stack]) = r1;"
- "*(u64 *)(r10 - %[max_bpf_stack_8]) = r1;"
- "call %[bpf_get_smp_processor_id];"
- "r1 = *(u64 *)(r10 - %[max_bpf_stack_8]);"
- "exit;"
- :
- : __imm_const(max_bpf_stack, MAX_BPF_STACK),
- __imm_const(max_bpf_stack_8, MAX_BPF_STACK + 8),
- __imm(bpf_get_smp_processor_id)
- : __clobber_all
- );
-}
-
-SEC("raw_tp")
-__arch_x86_64
-__log_level(4)
-__msg("stack depth 520")
-__failure
-__naked int bpf_fastcall_max_stack_fail(void)
-{
- asm volatile(
- "r1 = 42;"
- "*(u64 *)(r10 - %[max_bpf_stack]) = r1;"
- "*(u64 *)(r10 - %[max_bpf_stack_8]) = r1;"
- "call %[bpf_get_smp_processor_id];"
- "r1 = *(u64 *)(r10 - %[max_bpf_stack_8]);"
- /* call to prandom blocks bpf_fastcall rewrite */
- "*(u64 *)(r10 - %[max_bpf_stack_8]) = r1;"
- "call %[bpf_get_prandom_u32];"
- "r1 = *(u64 *)(r10 - %[max_bpf_stack_8]);"
- "exit;"
- :
- : __imm_const(max_bpf_stack, MAX_BPF_STACK),
- __imm_const(max_bpf_stack_8, MAX_BPF_STACK + 8),
- __imm(bpf_get_smp_processor_id),
- __imm(bpf_get_prandom_u32)
- : __clobber_all
- );
-}
-
SEC("cgroup/getsockname_unix")
__xlated("0: r2 = 1")
/* bpf_cast_to_kern_ctx is replaced by a single assignment */
diff --git a/tools/testing/selftests/bpf/progs/verifier_const.c b/tools/testing/selftests/bpf/progs/verifier_const.c
index 2e533d7eec2f..e118dbb768bf 100644
--- a/tools/testing/selftests/bpf/progs/verifier_const.c
+++ b/tools/testing/selftests/bpf/progs/verifier_const.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024 Isovalent */
-#include <linux/bpf.h>
+#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
#include "bpf_misc.h"
const volatile long foo = 42;
@@ -66,4 +67,32 @@ int tcx6(struct __sk_buff *skb)
return TCX_PASS;
}
+static inline void write_fixed(volatile void *p, __u32 val)
+{
+ *(volatile __u32 *)p = val;
+}
+
+static inline void write_dyn(void *p, void *val, int len)
+{
+ bpf_copy_from_user(p, len, val);
+}
+
+SEC("tc/ingress")
+__description("rodata/mark: write with unknown reg rejected")
+__failure __msg("write into map forbidden")
+int tcx7(struct __sk_buff *skb)
+{
+ write_fixed((void *)&foo, skb->mark);
+ return TCX_PASS;
+}
+
+SEC("lsm.s/bprm_committed_creds")
+__description("rodata/mark: write with unknown reg rejected")
+__failure __msg("write into map forbidden")
+int BPF_PROG(bprm, struct linux_binprm *bprm)
+{
+ write_dyn((void *)&foo, &bart, bpf_get_prandom_u32() & 3);
+ return 0;
+}
+
char LICENSE[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_mtu.c b/tools/testing/selftests/bpf/progs/verifier_mtu.c
new file mode 100644
index 000000000000..70c7600a26a0
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_mtu.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+SEC("tc/ingress")
+__description("uninit/mtu: write rejected")
+__failure __msg("invalid indirect read from stack")
+int tc_uninit_mtu(struct __sk_buff *ctx)
+{
+ __u32 mtu;
+
+ bpf_check_mtu(ctx, 0, &mtu, 0, 0);
+ return TCX_PASS;
+}
+
+char LICENSE[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_search_pruning.c b/tools/testing/selftests/bpf/progs/verifier_search_pruning.c
index 5a14498d352f..f40e57251e94 100644
--- a/tools/testing/selftests/bpf/progs/verifier_search_pruning.c
+++ b/tools/testing/selftests/bpf/progs/verifier_search_pruning.c
@@ -2,6 +2,7 @@
/* Converted from tools/testing/selftests/bpf/verifier/search_pruning.c */
#include <linux/bpf.h>
+#include <../../../include/linux/filter.h>
#include <bpf/bpf_helpers.h>
#include "bpf_misc.h"
@@ -336,4 +337,26 @@ l0_%=: r1 = 42; \
: __clobber_all);
}
+/* Without checkpoint forcibly inserted at the back-edge a loop this
+ * test would take a very long time to verify.
+ */
+SEC("kprobe")
+__failure __log_level(4)
+__msg("BPF program is too large.")
+__naked void short_loop1(void)
+{
+ asm volatile (
+ " r7 = *(u16 *)(r1 +0);"
+ "1: r7 += 0x1ab064b9;"
+ " .8byte %[jset];" /* same as 'if r7 & 0x702000 goto 1b;' */
+ " r7 &= 0x1ee60e;"
+ " r7 += r1;"
+ " if r7 s> 0x37d2 goto +0;"
+ " r0 = 0;"
+ " exit;"
+ :
+ : __imm_insn(jset, BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x702000, -2))
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
index f8f5dc9f72b8..62b8e29ced9f 100644
--- a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
+++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
@@ -21,7 +21,6 @@
#define tcp_flag_word(tp) (((union tcp_word_hdr *)(tp))->words[3])
-#define IP_DF 0x4000
#define IP_MF 0x2000
#define IP_OFFSET 0x1fff
@@ -442,7 +441,7 @@ static __always_inline int tcp_lookup(void *ctx, struct header_pointers *hdr, bo
/* TCP doesn't normally use fragments, and XDP can't reassemble
* them.
*/
- if ((hdr->ipv4->frag_off & bpf_htons(IP_DF | IP_MF | IP_OFFSET)) != bpf_htons(IP_DF))
+ if ((hdr->ipv4->frag_off & bpf_htons(IP_MF | IP_OFFSET)) != 0)
return XDP_DROP;
tup.ipv4.saddr = hdr->ipv4->saddr;
diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c
index 3e02d7267de8..e5c7ecbe57e3 100644
--- a/tools/testing/selftests/bpf/test_sockmap.c
+++ b/tools/testing/selftests/bpf/test_sockmap.c
@@ -56,6 +56,8 @@ static void running_handler(int a);
#define BPF_SOCKHASH_FILENAME "test_sockhash_kern.bpf.o"
#define CG_PATH "/sockmap"
+#define EDATAINTEGRITY 2001
+
/* global sockets */
int s1, s2, c1, c2, p1, p2;
int test_cnt;
@@ -86,6 +88,10 @@ int ktls;
int peek_flag;
int skb_use_parser;
int txmsg_omit_skb_parser;
+int verify_push_start;
+int verify_push_len;
+int verify_pop_start;
+int verify_pop_len;
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h' },
@@ -418,16 +424,18 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
{
bool drop = opt->drop_expected;
unsigned char k = 0;
+ int i, j, fp;
FILE *file;
- int i, fp;
file = tmpfile();
if (!file) {
perror("create file for sendpage");
return 1;
}
- for (i = 0; i < iov_length * cnt; i++, k++)
- fwrite(&k, sizeof(char), 1, file);
+ for (i = 0; i < cnt; i++, k = 0) {
+ for (j = 0; j < iov_length; j++, k++)
+ fwrite(&k, sizeof(char), 1, file);
+ }
fflush(file);
fseek(file, 0, SEEK_SET);
@@ -510,42 +518,111 @@ unwind_iov:
return -ENOMEM;
}
-static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
+/* In push or pop test, we need to do some calculations for msg_verify_data */
+static void msg_verify_date_prep(void)
{
- int i, j = 0, bytes_cnt = 0;
- unsigned char k = 0;
+ int push_range_end = txmsg_start_push + txmsg_end_push - 1;
+ int pop_range_end = txmsg_start_pop + txmsg_pop - 1;
+
+ if (txmsg_end_push && txmsg_pop &&
+ txmsg_start_push <= pop_range_end && txmsg_start_pop <= push_range_end) {
+ /* The push range and the pop range overlap */
+ int overlap_len;
+
+ verify_push_start = txmsg_start_push;
+ verify_pop_start = txmsg_start_pop;
+ if (txmsg_start_push < txmsg_start_pop)
+ overlap_len = min(push_range_end - txmsg_start_pop + 1, txmsg_pop);
+ else
+ overlap_len = min(pop_range_end - txmsg_start_push + 1, txmsg_end_push);
+ verify_push_len = max(txmsg_end_push - overlap_len, 0);
+ verify_pop_len = max(txmsg_pop - overlap_len, 0);
+ } else {
+ /* Otherwise */
+ verify_push_start = txmsg_start_push;
+ verify_pop_start = txmsg_start_pop;
+ verify_push_len = txmsg_end_push;
+ verify_pop_len = txmsg_pop;
+ }
+}
+
+static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz,
+ unsigned char *k_p, int *bytes_cnt_p,
+ int *check_cnt_p, int *push_p)
+{
+ int bytes_cnt = *bytes_cnt_p, check_cnt = *check_cnt_p, push = *push_p;
+ unsigned char k = *k_p;
+ int i, j;
- for (i = 0; i < msg->msg_iovlen; i++) {
+ for (i = 0, j = 0; i < msg->msg_iovlen && size; i++, j = 0) {
unsigned char *d = msg->msg_iov[i].iov_base;
/* Special case test for skb ingress + ktls */
if (i == 0 && txmsg_ktls_skb) {
if (msg->msg_iov[i].iov_len < 4)
- return -EIO;
+ return -EDATAINTEGRITY;
if (memcmp(d, "PASS", 4) != 0) {
fprintf(stderr,
"detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
i, 0, d[0], d[1], d[2], d[3]);
- return -EIO;
+ return -EDATAINTEGRITY;
}
j = 4; /* advance index past PASS header */
}
for (; j < msg->msg_iov[i].iov_len && size; j++) {
+ if (push > 0 &&
+ check_cnt == verify_push_start + verify_push_len - push) {
+ int skipped;
+revisit_push:
+ skipped = push;
+ if (j + push >= msg->msg_iov[i].iov_len)
+ skipped = msg->msg_iov[i].iov_len - j;
+ push -= skipped;
+ size -= skipped;
+ j += skipped - 1;
+ check_cnt += skipped;
+ continue;
+ }
+
+ if (verify_pop_len > 0 && check_cnt == verify_pop_start) {
+ bytes_cnt += verify_pop_len;
+ check_cnt += verify_pop_len;
+ k += verify_pop_len;
+
+ if (bytes_cnt == chunk_sz) {
+ k = 0;
+ bytes_cnt = 0;
+ check_cnt = 0;
+ push = verify_push_len;
+ }
+
+ if (push > 0 &&
+ check_cnt == verify_push_start + verify_push_len - push)
+ goto revisit_push;
+ }
+
if (d[j] != k++) {
fprintf(stderr,
"detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
i, j, d[j], k - 1, d[j+1], k);
- return -EIO;
+ return -EDATAINTEGRITY;
}
bytes_cnt++;
+ check_cnt++;
if (bytes_cnt == chunk_sz) {
k = 0;
bytes_cnt = 0;
+ check_cnt = 0;
+ push = verify_push_len;
}
size--;
}
}
+ *k_p = k;
+ *bytes_cnt_p = bytes_cnt;
+ *check_cnt_p = check_cnt;
+ *push_p = push;
return 0;
}
@@ -598,10 +675,14 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
}
clock_gettime(CLOCK_MONOTONIC, &s->end);
} else {
+ float total_bytes, txmsg_pop_total, txmsg_push_total;
int slct, recvp = 0, recv, max_fd = fd;
- float total_bytes, txmsg_pop_total;
int fd_flags = O_NONBLOCK;
struct timeval timeout;
+ unsigned char k = 0;
+ int bytes_cnt = 0;
+ int check_cnt = 0;
+ int push = 0;
fd_set w;
fcntl(fd, fd_flags);
@@ -615,12 +696,22 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
* This is really only useful for testing edge cases in code
* paths.
*/
- total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
- if (txmsg_apply)
+ total_bytes = (float)iov_length * (float)cnt;
+ if (!opt->sendpage)
+ total_bytes *= (float)iov_count;
+ if (txmsg_apply) {
+ txmsg_push_total = txmsg_end_push * (total_bytes / txmsg_apply);
txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply);
- else
+ } else {
+ txmsg_push_total = txmsg_end_push * cnt;
txmsg_pop_total = txmsg_pop * cnt;
+ }
+ total_bytes += txmsg_push_total;
total_bytes -= txmsg_pop_total;
+ if (data) {
+ msg_verify_date_prep();
+ push = verify_push_len;
+ }
err = clock_gettime(CLOCK_MONOTONIC, &s->start);
if (err < 0)
perror("recv start time");
@@ -693,10 +784,11 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
if (data) {
int chunk_sz = opt->sendpage ?
- iov_length * cnt :
+ iov_length :
iov_length * iov_count;
- errno = msg_verify_data(&msg, recv, chunk_sz);
+ errno = msg_verify_data(&msg, recv, chunk_sz, &k, &bytes_cnt,
+ &check_cnt, &push);
if (errno) {
perror("data verify msg failed");
goto out_errno;
@@ -704,7 +796,11 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
if (recvp) {
errno = msg_verify_data(&msg_peek,
recvp,
- chunk_sz);
+ chunk_sz,
+ &k,
+ &bytes_cnt,
+ &check_cnt,
+ &push);
if (errno) {
perror("data verify msg_peek failed");
goto out_errno;
@@ -786,8 +882,6 @@ static int sendmsg_test(struct sockmap_options *opt)
rxpid = fork();
if (rxpid == 0) {
- if (txmsg_pop || txmsg_start_pop)
- iov_buf -= (txmsg_pop - txmsg_start_pop + 1);
if (opt->drop_expected || txmsg_ktls_skb_drop)
_exit(0);
@@ -812,7 +906,7 @@ static int sendmsg_test(struct sockmap_options *opt)
s.bytes_sent, sent_Bps, sent_Bps/giga,
s.bytes_recvd, recvd_Bps, recvd_Bps/giga,
peek_flag ? "(peek_msg)" : "");
- if (err && txmsg_cork)
+ if (err && err != -EDATAINTEGRITY && txmsg_cork)
err = 0;
exit(err ? 1 : 0);
} else if (rxpid == -1) {
@@ -1456,8 +1550,8 @@ static void test_send_many(struct sockmap_options *opt, int cgrp)
static void test_send_large(struct sockmap_options *opt, int cgrp)
{
- opt->iov_length = 256;
- opt->iov_count = 1024;
+ opt->iov_length = 8192;
+ opt->iov_count = 32;
opt->rate = 2;
test_exec(cgrp, opt);
}
@@ -1586,17 +1680,19 @@ static void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt)
static void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
{
/* Test basic start/end */
+ txmsg_pass = 1;
txmsg_start = 1;
txmsg_end = 2;
test_send(opt, cgrp);
/* Test >4k pull */
+ txmsg_pass = 1;
txmsg_start = 4096;
txmsg_end = 9182;
test_send_large(opt, cgrp);
/* Test pull + redirect */
- txmsg_redir = 0;
+ txmsg_redir = 1;
txmsg_start = 1;
txmsg_end = 2;
test_send(opt, cgrp);
@@ -1618,12 +1714,16 @@ static void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
{
+ bool data = opt->data_test;
+
/* Test basic pop */
+ txmsg_pass = 1;
txmsg_start_pop = 1;
txmsg_pop = 2;
test_send_many(opt, cgrp);
/* Test pop with >4k */
+ txmsg_pass = 1;
txmsg_start_pop = 4096;
txmsg_pop = 4096;
test_send_large(opt, cgrp);
@@ -1634,6 +1734,12 @@ static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
txmsg_pop = 2;
test_send_many(opt, cgrp);
+ /* TODO: Test for pop + cork should be different,
+ * - It makes the layout of the received data difficult
+ * - It makes it hard to calculate the total_bytes in the recvmsg
+ * Temporarily skip the data integrity test for this case now.
+ */
+ opt->data_test = false;
/* Test pop + cork */
txmsg_redir = 0;
txmsg_cork = 512;
@@ -1647,16 +1753,21 @@ static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
txmsg_start_pop = 1;
txmsg_pop = 2;
test_send_many(opt, cgrp);
+ opt->data_test = data;
}
static void test_txmsg_push(int cgrp, struct sockmap_options *opt)
{
+ bool data = opt->data_test;
+
/* Test basic push */
+ txmsg_pass = 1;
txmsg_start_push = 1;
txmsg_end_push = 1;
test_send(opt, cgrp);
/* Test push 4kB >4k */
+ txmsg_pass = 1;
txmsg_start_push = 4096;
txmsg_end_push = 4096;
test_send_large(opt, cgrp);
@@ -1667,21 +1778,66 @@ static void test_txmsg_push(int cgrp, struct sockmap_options *opt)
txmsg_end_push = 2;
test_send_many(opt, cgrp);
+ /* TODO: Test for push + cork should be different,
+ * - It makes the layout of the received data difficult
+ * - It makes it hard to calculate the total_bytes in the recvmsg
+ * Temporarily skip the data integrity test for this case now.
+ */
+ opt->data_test = false;
/* Test push + cork */
txmsg_redir = 0;
txmsg_cork = 512;
txmsg_start_push = 1;
txmsg_end_push = 2;
test_send_many(opt, cgrp);
+ opt->data_test = data;
}
static void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt)
{
+ /* Test push/pop range overlapping */
+ txmsg_pass = 1;
txmsg_start_push = 1;
txmsg_end_push = 10;
txmsg_start_pop = 5;
txmsg_pop = 4;
test_send_large(opt, cgrp);
+
+ txmsg_pass = 1;
+ txmsg_start_push = 1;
+ txmsg_end_push = 10;
+ txmsg_start_pop = 5;
+ txmsg_pop = 16;
+ test_send_large(opt, cgrp);
+
+ txmsg_pass = 1;
+ txmsg_start_push = 5;
+ txmsg_end_push = 4;
+ txmsg_start_pop = 1;
+ txmsg_pop = 10;
+ test_send_large(opt, cgrp);
+
+ txmsg_pass = 1;
+ txmsg_start_push = 5;
+ txmsg_end_push = 16;
+ txmsg_start_pop = 1;
+ txmsg_pop = 10;
+ test_send_large(opt, cgrp);
+
+ /* Test push/pop range non-overlapping */
+ txmsg_pass = 1;
+ txmsg_start_push = 1;
+ txmsg_end_push = 10;
+ txmsg_start_pop = 16;
+ txmsg_pop = 4;
+ test_send_large(opt, cgrp);
+
+ txmsg_pass = 1;
+ txmsg_start_push = 16;
+ txmsg_end_push = 10;
+ txmsg_start_pop = 5;
+ txmsg_pop = 4;
+ test_send_large(opt, cgrp);
}
static void test_txmsg_apply(int cgrp, struct sockmap_options *opt)
diff --git a/tools/testing/selftests/bpf/test_tcp_check_syncookie.sh b/tools/testing/selftests/bpf/test_tcp_check_syncookie.sh
deleted file mode 100755
index b42c24282c25..000000000000
--- a/tools/testing/selftests/bpf/test_tcp_check_syncookie.sh
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-# Copyright (c) 2018 Facebook
-# Copyright (c) 2019 Cloudflare
-
-set -eu
-readonly NS1="ns1-$(mktemp -u XXXXXX)"
-
-wait_for_ip()
-{
- local _i
- printf "Wait for IP %s to become available " "$1"
- for _i in $(seq ${MAX_PING_TRIES}); do
- printf "."
- if ns1_exec ping -c 1 -W 1 "$1" >/dev/null 2>&1; then
- echo " OK"
- return
- fi
- sleep 1
- done
- echo 1>&2 "ERROR: Timeout waiting for test IP to become available."
- exit 1
-}
-
-get_prog_id()
-{
- awk '/ id / {sub(/.* id /, "", $0); print($1)}'
-}
-
-ns1_exec()
-{
- ip netns exec ${NS1} "$@"
-}
-
-setup()
-{
- ip netns add ${NS1}
- ns1_exec ip link set lo up
-
- ns1_exec sysctl -w net.ipv4.tcp_syncookies=2
- ns1_exec sysctl -w net.ipv4.tcp_window_scaling=0
- ns1_exec sysctl -w net.ipv4.tcp_timestamps=0
- ns1_exec sysctl -w net.ipv4.tcp_sack=0
-
- wait_for_ip 127.0.0.1
- wait_for_ip ::1
-}
-
-cleanup()
-{
- ip netns del ns1 2>/dev/null || :
-}
-
-main()
-{
- trap cleanup EXIT 2 3 6 15
- setup
-
- printf "Testing clsact..."
- ns1_exec tc qdisc add dev "${TEST_IF}" clsact
- ns1_exec tc filter add dev "${TEST_IF}" ingress \
- bpf obj "${BPF_PROG_OBJ}" sec "${CLSACT_SECTION}" da
-
- BPF_PROG_ID=$(ns1_exec tc filter show dev "${TEST_IF}" ingress | \
- get_prog_id)
- ns1_exec "${PROG}" "${BPF_PROG_ID}"
- ns1_exec tc qdisc del dev "${TEST_IF}" clsact
-
- printf "Testing XDP..."
- ns1_exec ip link set "${TEST_IF}" xdp \
- object "${BPF_PROG_OBJ}" section "${XDP_SECTION}"
- BPF_PROG_ID=$(ns1_exec ip link show "${TEST_IF}" | get_prog_id)
- ns1_exec "${PROG}" "${BPF_PROG_ID}"
-}
-
-DIR=$(dirname $0)
-TEST_IF=lo
-MAX_PING_TRIES=5
-BPF_PROG_OBJ="${DIR}/test_tcp_check_syncookie_kern.bpf.o"
-CLSACT_SECTION="tc"
-XDP_SECTION="xdp"
-BPF_PROG_ID=0
-PROG="${DIR}/test_tcp_check_syncookie_user"
-
-main
diff --git a/tools/testing/selftests/bpf/test_tcp_check_syncookie_user.c b/tools/testing/selftests/bpf/test_tcp_check_syncookie_user.c
deleted file mode 100644
index 3844f9b8232a..000000000000
--- a/tools/testing/selftests/bpf/test_tcp_check_syncookie_user.c
+++ /dev/null
@@ -1,213 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018 Facebook
-// Copyright (c) 2019 Cloudflare
-
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bpf/bpf.h>
-#include <bpf/libbpf.h>
-
-#include "cgroup_helpers.h"
-#include "network_helpers.h"
-
-static int get_map_fd_by_prog_id(int prog_id, bool *xdp)
-{
- struct bpf_prog_info info = {};
- __u32 info_len = sizeof(info);
- __u32 map_ids[1];
- int prog_fd = -1;
- int map_fd = -1;
-
- prog_fd = bpf_prog_get_fd_by_id(prog_id);
- if (prog_fd < 0) {
- log_err("Failed to get fd by prog id %d", prog_id);
- goto err;
- }
-
- info.nr_map_ids = 1;
- info.map_ids = (__u64)(unsigned long)map_ids;
-
- if (bpf_prog_get_info_by_fd(prog_fd, &info, &info_len)) {
- log_err("Failed to get info by prog fd %d", prog_fd);
- goto err;
- }
-
- if (!info.nr_map_ids) {
- log_err("No maps found for prog fd %d", prog_fd);
- goto err;
- }
-
- *xdp = info.type == BPF_PROG_TYPE_XDP;
-
- map_fd = bpf_map_get_fd_by_id(map_ids[0]);
- if (map_fd < 0)
- log_err("Failed to get fd by map id %d", map_ids[0]);
-err:
- if (prog_fd >= 0)
- close(prog_fd);
- return map_fd;
-}
-
-static int run_test(int server_fd, int results_fd, bool xdp)
-{
- int client = -1, srv_client = -1;
- int ret = 0;
- __u32 key = 0;
- __u32 key_gen = 1;
- __u32 key_mss = 2;
- __u32 value = 0;
- __u32 value_gen = 0;
- __u32 value_mss = 0;
-
- if (bpf_map_update_elem(results_fd, &key, &value, 0) < 0) {
- log_err("Can't clear results");
- goto err;
- }
-
- if (bpf_map_update_elem(results_fd, &key_gen, &value_gen, 0) < 0) {
- log_err("Can't clear results");
- goto err;
- }
-
- if (bpf_map_update_elem(results_fd, &key_mss, &value_mss, 0) < 0) {
- log_err("Can't clear results");
- goto err;
- }
-
- client = connect_to_fd(server_fd, 0);
- if (client == -1)
- goto err;
-
- srv_client = accept(server_fd, NULL, 0);
- if (srv_client == -1) {
- log_err("Can't accept connection");
- goto err;
- }
-
- if (bpf_map_lookup_elem(results_fd, &key, &value) < 0) {
- log_err("Can't lookup result");
- goto err;
- }
-
- if (value == 0) {
- log_err("Didn't match syncookie: %u", value);
- goto err;
- }
-
- if (bpf_map_lookup_elem(results_fd, &key_gen, &value_gen) < 0) {
- log_err("Can't lookup result");
- goto err;
- }
-
- if (xdp && value_gen == 0) {
- // SYN packets do not get passed through generic XDP, skip the
- // rest of the test.
- printf("Skipping XDP cookie check\n");
- goto out;
- }
-
- if (bpf_map_lookup_elem(results_fd, &key_mss, &value_mss) < 0) {
- log_err("Can't lookup result");
- goto err;
- }
-
- if (value != value_gen) {
- log_err("BPF generated cookie does not match kernel one");
- goto err;
- }
-
- if (value_mss < 536 || value_mss > USHRT_MAX) {
- log_err("Unexpected MSS retrieved");
- goto err;
- }
-
- goto out;
-
-err:
- ret = 1;
-out:
- close(client);
- close(srv_client);
- return ret;
-}
-
-static int v6only_true(int fd, void *opts)
-{
- int mode = true;
-
- return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));
-}
-
-static int v6only_false(int fd, void *opts)
-{
- int mode = false;
-
- return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));
-}
-
-int main(int argc, char **argv)
-{
- struct network_helper_opts opts = { 0 };
- int server = -1;
- int server_v6 = -1;
- int server_dual = -1;
- int results = -1;
- int err = 0;
- bool xdp;
-
- if (argc < 2) {
- fprintf(stderr, "Usage: %s prog_id\n", argv[0]);
- exit(1);
- }
-
- /* Use libbpf 1.0 API mode */
- libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
-
- results = get_map_fd_by_prog_id(atoi(argv[1]), &xdp);
- if (results < 0) {
- log_err("Can't get map");
- goto err;
- }
-
- server = start_server_str(AF_INET, SOCK_STREAM, "127.0.0.1", 0, NULL);
- if (server == -1)
- goto err;
-
- opts.post_socket_cb = v6only_true;
- server_v6 = start_server_str(AF_INET6, SOCK_STREAM, "::1", 0, &opts);
- if (server_v6 == -1)
- goto err;
-
- opts.post_socket_cb = v6only_false;
- server_dual = start_server_str(AF_INET6, SOCK_STREAM, "::0", 0, &opts);
- if (server_dual == -1)
- goto err;
-
- if (run_test(server, results, xdp))
- goto err;
-
- if (run_test(server_v6, results, xdp))
- goto err;
-
- if (run_test(server_dual, results, xdp))
- goto err;
-
- printf("ok\n");
- goto out;
-err:
- err = 1;
-out:
- close(server);
- close(server_v6);
- close(server_dual);
- close(results);
- return err;
-}
diff --git a/tools/testing/selftests/bpf/veristat.cfg b/tools/testing/selftests/bpf/veristat.cfg
index 1a385061618d..e661ffdcaadf 100644
--- a/tools/testing/selftests/bpf/veristat.cfg
+++ b/tools/testing/selftests/bpf/veristat.cfg
@@ -15,3 +15,4 @@ test_usdt*
test_verif_scale*
test_xdp_noinline*
xdp_synproxy*
+verifier_search_pruning*
diff --git a/tools/testing/selftests/drivers/net/bonding/bond_options.sh b/tools/testing/selftests/drivers/net/bonding/bond_options.sh
index 41d0859feb7d..edc56e2cc606 100755
--- a/tools/testing/selftests/drivers/net/bonding/bond_options.sh
+++ b/tools/testing/selftests/drivers/net/bonding/bond_options.sh
@@ -11,6 +11,8 @@ ALL_TESTS="
lib_dir=$(dirname "$0")
source ${lib_dir}/bond_topo_3d1c.sh
+c_maddr="33:33:00:00:00:10"
+g_maddr="33:33:00:00:02:54"
skip_prio()
{
@@ -240,6 +242,54 @@ arp_validate_test()
done
}
+# Testing correct multicast groups are added to slaves for ns targets
+arp_validate_mcast()
+{
+ RET=0
+ local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
+ local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
+
+ for i in $(seq 0 2); do
+ maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
+
+ # arp_valid == 0 or active_slave should not join any maddrs
+ if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
+ echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
+ RET=1
+ check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
+ # arp_valid != 0 and backup_slave should join both maddrs
+ elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
+ ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
+ ! echo "$maddr_list" | grep -q "${m_maddr}"); then
+ RET=1
+ check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
+ fi
+ done
+
+ # Do failover
+ ip -n ${s_ns} link set ${active_slave} down
+ # wait for active link change
+ slowwait 2 active_slave_changed $active_slave
+ active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
+
+ for i in $(seq 0 2); do
+ maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
+
+ # arp_valid == 0 or active_slave should not join any maddrs
+ if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
+ echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
+ RET=1
+ check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
+ # arp_valid != 0 and backup_slave should join both maddrs
+ elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
+ ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
+ ! echo "$maddr_list" | grep -q "${m_maddr}"); then
+ RET=1
+ check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
+ fi
+ done
+}
+
arp_validate_arp()
{
local mode=$1
@@ -261,8 +311,10 @@ arp_validate_ns()
fi
for val in $(seq 0 6); do
- arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} arp_validate $val"
+ arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
+ arp_validate_mcast
+ log_test "arp_validate" "join mcast group"
done
}
diff --git a/tools/testing/selftests/drivers/net/hw/.gitignore b/tools/testing/selftests/drivers/net/hw/.gitignore
new file mode 100644
index 000000000000..e9fe6ede681a
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/.gitignore
@@ -0,0 +1 @@
+ncdevmem
diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile
index c9f2f48fc30f..1c6a77480923 100644
--- a/tools/testing/selftests/drivers/net/hw/Makefile
+++ b/tools/testing/selftests/drivers/net/hw/Makefile
@@ -3,6 +3,7 @@
TEST_PROGS = \
csum.py \
devlink_port_split.py \
+ devmem.py \
ethtool.sh \
ethtool_extended_state.sh \
ethtool_mm.sh \
@@ -26,4 +27,12 @@ TEST_INCLUDES := \
../../../net/forwarding/tc_common.sh \
#
+# YNL files, must be before "include ..lib.mk"
+YNL_GEN_FILES := ncdevmem
+TEST_GEN_FILES += $(YNL_GEN_FILES)
+
include ../../../lib.mk
+
+# YNL build
+YNL_GENS := ethtool netdev
+include ../../../net/ynl.mk
diff --git a/tools/testing/selftests/drivers/net/hw/devmem.py b/tools/testing/selftests/drivers/net/hw/devmem.py
new file mode 100755
index 000000000000..1223f0f5c10c
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/devmem.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+from lib.py import ksft_run, ksft_exit
+from lib.py import ksft_eq, KsftSkipEx
+from lib.py import NetDrvEpEnv
+from lib.py import bkg, cmd, rand_port, wait_port_listen
+from lib.py import ksft_disruptive
+
+
+def require_devmem(cfg):
+ if not hasattr(cfg, "_devmem_probed"):
+ port = rand_port()
+ probe_command = f"./ncdevmem -f {cfg.ifname}"
+ cfg._devmem_supported = cmd(probe_command, fail=False, shell=True).ret == 0
+ cfg._devmem_probed = True
+
+ if not cfg._devmem_supported:
+ raise KsftSkipEx("Test requires devmem support")
+
+
+@ksft_disruptive
+def check_rx(cfg) -> None:
+ cfg.require_v6()
+ require_devmem(cfg)
+
+ port = rand_port()
+ listen_cmd = f"./ncdevmem -l -f {cfg.ifname} -s {cfg.v6} -p {port}"
+
+ with bkg(listen_cmd) as socat:
+ wait_port_listen(port)
+ cmd(f"echo -e \"hello\\nworld\"| socat -u - TCP6:[{cfg.v6}]:{port}", host=cfg.remote, shell=True)
+
+ ksft_eq(socat.stdout.strip(), "hello\nworld")
+
+
+def main() -> None:
+ with NetDrvEpEnv(__file__) as cfg:
+ ksft_run([check_rx],
+ args=(cfg, ))
+ ksft_exit()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/testing/selftests/drivers/net/hw/ncdevmem.c b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
new file mode 100644
index 000000000000..8e502a1f8f9b
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/ncdevmem.c
@@ -0,0 +1,789 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tcpdevmem netcat. Works similarly to netcat but does device memory TCP
+ * instead of regular TCP. Uses udmabuf to mock a dmabuf provider.
+ *
+ * Usage:
+ *
+ * On server:
+ * ncdevmem -s <server IP> [-c <client IP>] -f eth1 -l -p 5201
+ *
+ * On client:
+ * echo -n "hello\nworld" | nc -s <server IP> 5201 -p 5201
+ *
+ * Test data validation:
+ *
+ * On server:
+ * ncdevmem -s <server IP> [-c <client IP>] -f eth1 -l -p 5201 -v 7
+ *
+ * On client:
+ * yes $(echo -e \\x01\\x02\\x03\\x04\\x05\\x06) | \
+ * tr \\n \\0 | \
+ * head -c 5G | \
+ * nc <server IP> 5201 -p 5201
+ *
+ *
+ * Note this is compatible with regular netcat. i.e. the sender or receiver can
+ * be replaced with regular netcat to test the RX or TX path in isolation.
+ */
+#define _GNU_SOURCE
+#define __EXPORTED_HEADERS__
+
+#include <linux/uio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#define __iovec_defined
+#include <fcntl.h>
+#include <malloc.h>
+#include <error.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+
+#include <linux/memfd.h>
+#include <linux/dma-buf.h>
+#include <linux/udmabuf.h>
+#include <libmnl/libmnl.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/netdev.h>
+#include <linux/ethtool_netlink.h>
+#include <time.h>
+#include <net/if.h>
+
+#include "netdev-user.h"
+#include "ethtool-user.h"
+#include <ynl.h>
+
+#define PAGE_SHIFT 12
+#define TEST_PREFIX "ncdevmem"
+#define NUM_PAGES 16000
+
+#ifndef MSG_SOCK_DEVMEM
+#define MSG_SOCK_DEVMEM 0x2000000
+#endif
+
+static char *server_ip;
+static char *client_ip;
+static char *port;
+static size_t do_validation;
+static int start_queue = -1;
+static int num_queues = -1;
+static char *ifname;
+static unsigned int ifindex;
+static unsigned int dmabuf_id;
+
+struct memory_buffer {
+ int fd;
+ size_t size;
+
+ int devfd;
+ int memfd;
+ char *buf_mem;
+};
+
+struct memory_provider {
+ struct memory_buffer *(*alloc)(size_t size);
+ void (*free)(struct memory_buffer *ctx);
+ void (*memcpy_from_device)(void *dst, struct memory_buffer *src,
+ size_t off, int n);
+};
+
+static struct memory_buffer *udmabuf_alloc(size_t size)
+{
+ struct udmabuf_create create;
+ struct memory_buffer *ctx;
+ int ret;
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx)
+ error(1, ENOMEM, "malloc failed");
+
+ ctx->size = size;
+
+ ctx->devfd = open("/dev/udmabuf", O_RDWR);
+ if (ctx->devfd < 0)
+ error(1, errno,
+ "%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
+ TEST_PREFIX);
+
+ ctx->memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
+ if (ctx->memfd < 0)
+ error(1, errno, "%s: [skip,no-memfd]\n", TEST_PREFIX);
+
+ ret = fcntl(ctx->memfd, F_ADD_SEALS, F_SEAL_SHRINK);
+ if (ret < 0)
+ error(1, errno, "%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
+
+ ret = ftruncate(ctx->memfd, size);
+ if (ret == -1)
+ error(1, errno, "%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
+
+ memset(&create, 0, sizeof(create));
+
+ create.memfd = ctx->memfd;
+ create.offset = 0;
+ create.size = size;
+ ctx->fd = ioctl(ctx->devfd, UDMABUF_CREATE, &create);
+ if (ctx->fd < 0)
+ error(1, errno, "%s: [FAIL, create udmabuf]\n", TEST_PREFIX);
+
+ ctx->buf_mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ ctx->fd, 0);
+ if (ctx->buf_mem == MAP_FAILED)
+ error(1, errno, "%s: [FAIL, map udmabuf]\n", TEST_PREFIX);
+
+ return ctx;
+}
+
+static void udmabuf_free(struct memory_buffer *ctx)
+{
+ munmap(ctx->buf_mem, ctx->size);
+ close(ctx->fd);
+ close(ctx->memfd);
+ close(ctx->devfd);
+ free(ctx);
+}
+
+static void udmabuf_memcpy_from_device(void *dst, struct memory_buffer *src,
+ size_t off, int n)
+{
+ struct dma_buf_sync sync = {};
+
+ sync.flags = DMA_BUF_SYNC_START;
+ ioctl(src->fd, DMA_BUF_IOCTL_SYNC, &sync);
+
+ memcpy(dst, src->buf_mem + off, n);
+
+ sync.flags = DMA_BUF_SYNC_END;
+ ioctl(src->fd, DMA_BUF_IOCTL_SYNC, &sync);
+}
+
+static struct memory_provider udmabuf_memory_provider = {
+ .alloc = udmabuf_alloc,
+ .free = udmabuf_free,
+ .memcpy_from_device = udmabuf_memcpy_from_device,
+};
+
+static struct memory_provider *provider = &udmabuf_memory_provider;
+
+static void print_nonzero_bytes(void *ptr, size_t size)
+{
+ unsigned char *p = ptr;
+ unsigned int i;
+
+ for (i = 0; i < size; i++)
+ putchar(p[i]);
+}
+
+void validate_buffer(void *line, size_t size)
+{
+ static unsigned char seed = 1;
+ unsigned char *ptr = line;
+ int errors = 0;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (ptr[i] != seed) {
+ fprintf(stderr,
+ "Failed validation: expected=%u, actual=%u, index=%lu\n",
+ seed, ptr[i], i);
+ errors++;
+ if (errors > 20)
+ error(1, 0, "validation failed.");
+ }
+ seed++;
+ if (seed == do_validation)
+ seed = 0;
+ }
+
+ fprintf(stdout, "Validated buffer\n");
+}
+
+static int rxq_num(int ifindex)
+{
+ struct ethtool_channels_get_req *req;
+ struct ethtool_channels_get_rsp *rsp;
+ struct ynl_error yerr;
+ struct ynl_sock *ys;
+ int num = -1;
+
+ ys = ynl_sock_create(&ynl_ethtool_family, &yerr);
+ if (!ys) {
+ fprintf(stderr, "YNL: %s\n", yerr.msg);
+ return -1;
+ }
+
+ req = ethtool_channels_get_req_alloc();
+ ethtool_channels_get_req_set_header_dev_index(req, ifindex);
+ rsp = ethtool_channels_get(ys, req);
+ if (rsp)
+ num = rsp->rx_count + rsp->combined_count;
+ ethtool_channels_get_req_free(req);
+ ethtool_channels_get_rsp_free(rsp);
+
+ ynl_sock_destroy(ys);
+
+ return num;
+}
+
+#define run_command(cmd, ...) \
+ ({ \
+ char command[256]; \
+ memset(command, 0, sizeof(command)); \
+ snprintf(command, sizeof(command), cmd, ##__VA_ARGS__); \
+ fprintf(stderr, "Running: %s\n", command); \
+ system(command); \
+ })
+
+static int reset_flow_steering(void)
+{
+ /* Depending on the NIC, toggling ntuple off and on might not
+ * be allowed. Additionally, attempting to delete existing filters
+ * will fail if no filters are present. Therefore, do not enforce
+ * the exit status.
+ */
+
+ run_command("sudo ethtool -K %s ntuple off >&2", ifname);
+ run_command("sudo ethtool -K %s ntuple on >&2", ifname);
+ run_command(
+ "sudo ethtool -n %s | grep 'Filter:' | awk '{print $2}' | xargs -n1 ethtool -N %s delete >&2",
+ ifname, ifname);
+ return 0;
+}
+
+static const char *tcp_data_split_str(int val)
+{
+ switch (val) {
+ case 0:
+ return "off";
+ case 1:
+ return "auto";
+ case 2:
+ return "on";
+ default:
+ return "?";
+ }
+}
+
+static int configure_headersplit(bool on)
+{
+ struct ethtool_rings_get_req *get_req;
+ struct ethtool_rings_get_rsp *get_rsp;
+ struct ethtool_rings_set_req *req;
+ struct ynl_error yerr;
+ struct ynl_sock *ys;
+ int ret;
+
+ ys = ynl_sock_create(&ynl_ethtool_family, &yerr);
+ if (!ys) {
+ fprintf(stderr, "YNL: %s\n", yerr.msg);
+ return -1;
+ }
+
+ req = ethtool_rings_set_req_alloc();
+ ethtool_rings_set_req_set_header_dev_index(req, ifindex);
+ /* 0 - off, 1 - auto, 2 - on */
+ ethtool_rings_set_req_set_tcp_data_split(req, on ? 2 : 0);
+ ret = ethtool_rings_set(ys, req);
+ if (ret < 0)
+ fprintf(stderr, "YNL failed: %s\n", ys->err.msg);
+ ethtool_rings_set_req_free(req);
+
+ if (ret == 0) {
+ get_req = ethtool_rings_get_req_alloc();
+ ethtool_rings_get_req_set_header_dev_index(get_req, ifindex);
+ get_rsp = ethtool_rings_get(ys, get_req);
+ ethtool_rings_get_req_free(get_req);
+ if (get_rsp)
+ fprintf(stderr, "TCP header split: %s\n",
+ tcp_data_split_str(get_rsp->tcp_data_split));
+ ethtool_rings_get_rsp_free(get_rsp);
+ }
+
+ ynl_sock_destroy(ys);
+
+ return ret;
+}
+
+static int configure_rss(void)
+{
+ return run_command("sudo ethtool -X %s equal %d >&2", ifname, start_queue);
+}
+
+static int configure_channels(unsigned int rx, unsigned int tx)
+{
+ return run_command("sudo ethtool -L %s rx %u tx %u", ifname, rx, tx);
+}
+
+static int configure_flow_steering(struct sockaddr_in6 *server_sin)
+{
+ const char *type = "tcp6";
+ const char *server_addr;
+ char buf[40];
+
+ inet_ntop(AF_INET6, &server_sin->sin6_addr, buf, sizeof(buf));
+ server_addr = buf;
+
+ if (IN6_IS_ADDR_V4MAPPED(&server_sin->sin6_addr)) {
+ type = "tcp4";
+ server_addr = strrchr(server_addr, ':') + 1;
+ }
+
+ return run_command("sudo ethtool -N %s flow-type %s %s %s dst-ip %s %s %s dst-port %s queue %d >&2",
+ ifname,
+ type,
+ client_ip ? "src-ip" : "",
+ client_ip ?: "",
+ server_addr,
+ client_ip ? "src-port" : "",
+ client_ip ? port : "",
+ port, start_queue);
+}
+
+static int bind_rx_queue(unsigned int ifindex, unsigned int dmabuf_fd,
+ struct netdev_queue_id *queues,
+ unsigned int n_queue_index, struct ynl_sock **ys)
+{
+ struct netdev_bind_rx_req *req = NULL;
+ struct netdev_bind_rx_rsp *rsp = NULL;
+ struct ynl_error yerr;
+
+ *ys = ynl_sock_create(&ynl_netdev_family, &yerr);
+ if (!*ys) {
+ fprintf(stderr, "YNL: %s\n", yerr.msg);
+ return -1;
+ }
+
+ req = netdev_bind_rx_req_alloc();
+ netdev_bind_rx_req_set_ifindex(req, ifindex);
+ netdev_bind_rx_req_set_fd(req, dmabuf_fd);
+ __netdev_bind_rx_req_set_queues(req, queues, n_queue_index);
+
+ rsp = netdev_bind_rx(*ys, req);
+ if (!rsp) {
+ perror("netdev_bind_rx");
+ goto err_close;
+ }
+
+ if (!rsp->_present.id) {
+ perror("id not present");
+ goto err_close;
+ }
+
+ fprintf(stderr, "got dmabuf id=%d\n", rsp->id);
+ dmabuf_id = rsp->id;
+
+ netdev_bind_rx_req_free(req);
+ netdev_bind_rx_rsp_free(rsp);
+
+ return 0;
+
+err_close:
+ fprintf(stderr, "YNL failed: %s\n", (*ys)->err.msg);
+ netdev_bind_rx_req_free(req);
+ ynl_sock_destroy(*ys);
+ return -1;
+}
+
+static void enable_reuseaddr(int fd)
+{
+ int opt = 1;
+ int ret;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
+ if (ret)
+ error(1, errno, "%s: [FAIL, SO_REUSEPORT]\n", TEST_PREFIX);
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ if (ret)
+ error(1, errno, "%s: [FAIL, SO_REUSEADDR]\n", TEST_PREFIX);
+}
+
+static int parse_address(const char *str, int port, struct sockaddr_in6 *sin6)
+{
+ int ret;
+
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+
+ ret = inet_pton(sin6->sin6_family, str, &sin6->sin6_addr);
+ if (ret != 1) {
+ /* fallback to plain IPv4 */
+ ret = inet_pton(AF_INET, str, &sin6->sin6_addr.s6_addr32[3]);
+ if (ret != 1)
+ return -1;
+
+ /* add ::ffff prefix */
+ sin6->sin6_addr.s6_addr32[0] = 0;
+ sin6->sin6_addr.s6_addr32[1] = 0;
+ sin6->sin6_addr.s6_addr16[4] = 0;
+ sin6->sin6_addr.s6_addr16[5] = 0xffff;
+ }
+
+ return 0;
+}
+
+int do_server(struct memory_buffer *mem)
+{
+ char ctrl_data[sizeof(int) * 20000];
+ struct netdev_queue_id *queues;
+ size_t non_page_aligned_frags = 0;
+ struct sockaddr_in6 client_addr;
+ struct sockaddr_in6 server_sin;
+ size_t page_aligned_frags = 0;
+ size_t total_received = 0;
+ socklen_t client_addr_len;
+ bool is_devmem = false;
+ char *tmp_mem = NULL;
+ struct ynl_sock *ys;
+ char iobuf[819200];
+ char buffer[256];
+ int socket_fd;
+ int client_fd;
+ size_t i = 0;
+ int ret;
+
+ ret = parse_address(server_ip, atoi(port), &server_sin);
+ if (ret < 0)
+ error(1, 0, "parse server address");
+
+ if (reset_flow_steering())
+ error(1, 0, "Failed to reset flow steering\n");
+
+ if (configure_headersplit(1))
+ error(1, 0, "Failed to enable TCP header split\n");
+
+ /* Configure RSS to divert all traffic from our devmem queues */
+ if (configure_rss())
+ error(1, 0, "Failed to configure rss\n");
+
+ /* Flow steer our devmem flows to start_queue */
+ if (configure_flow_steering(&server_sin))
+ error(1, 0, "Failed to configure flow steering\n");
+
+ sleep(1);
+
+ queues = malloc(sizeof(*queues) * num_queues);
+
+ for (i = 0; i < num_queues; i++) {
+ queues[i]._present.type = 1;
+ queues[i]._present.id = 1;
+ queues[i].type = NETDEV_QUEUE_TYPE_RX;
+ queues[i].id = start_queue + i;
+ }
+
+ if (bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
+ error(1, 0, "Failed to bind\n");
+
+ tmp_mem = malloc(mem->size);
+ if (!tmp_mem)
+ error(1, ENOMEM, "malloc failed");
+
+ socket_fd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (socket_fd < 0)
+ error(1, errno, "%s: [FAIL, create socket]\n", TEST_PREFIX);
+
+ enable_reuseaddr(socket_fd);
+
+ fprintf(stderr, "binding to address %s:%d\n", server_ip,
+ ntohs(server_sin.sin6_port));
+
+ ret = bind(socket_fd, &server_sin, sizeof(server_sin));
+ if (ret)
+ error(1, errno, "%s: [FAIL, bind]\n", TEST_PREFIX);
+
+ ret = listen(socket_fd, 1);
+ if (ret)
+ error(1, errno, "%s: [FAIL, listen]\n", TEST_PREFIX);
+
+ client_addr_len = sizeof(client_addr);
+
+ inet_ntop(AF_INET6, &server_sin.sin6_addr, buffer,
+ sizeof(buffer));
+ fprintf(stderr, "Waiting or connection on %s:%d\n", buffer,
+ ntohs(server_sin.sin6_port));
+ client_fd = accept(socket_fd, &client_addr, &client_addr_len);
+
+ inet_ntop(AF_INET6, &client_addr.sin6_addr, buffer,
+ sizeof(buffer));
+ fprintf(stderr, "Got connection from %s:%d\n", buffer,
+ ntohs(client_addr.sin6_port));
+
+ while (1) {
+ struct iovec iov = { .iov_base = iobuf,
+ .iov_len = sizeof(iobuf) };
+ struct dmabuf_cmsg *dmabuf_cmsg = NULL;
+ struct cmsghdr *cm = NULL;
+ struct msghdr msg = { 0 };
+ struct dmabuf_token token;
+ ssize_t ret;
+
+ is_devmem = false;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = ctrl_data;
+ msg.msg_controllen = sizeof(ctrl_data);
+ ret = recvmsg(client_fd, &msg, MSG_SOCK_DEVMEM);
+ fprintf(stderr, "recvmsg ret=%ld\n", ret);
+ if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ continue;
+ if (ret < 0) {
+ perror("recvmsg");
+ continue;
+ }
+ if (ret == 0) {
+ fprintf(stderr, "client exited\n");
+ goto cleanup;
+ }
+
+ i++;
+ for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+ if (cm->cmsg_level != SOL_SOCKET ||
+ (cm->cmsg_type != SCM_DEVMEM_DMABUF &&
+ cm->cmsg_type != SCM_DEVMEM_LINEAR)) {
+ fprintf(stderr, "skipping non-devmem cmsg\n");
+ continue;
+ }
+
+ dmabuf_cmsg = (struct dmabuf_cmsg *)CMSG_DATA(cm);
+ is_devmem = true;
+
+ if (cm->cmsg_type == SCM_DEVMEM_LINEAR) {
+ /* TODO: process data copied from skb's linear
+ * buffer.
+ */
+ fprintf(stderr,
+ "SCM_DEVMEM_LINEAR. dmabuf_cmsg->frag_size=%u\n",
+ dmabuf_cmsg->frag_size);
+
+ continue;
+ }
+
+ token.token_start = dmabuf_cmsg->frag_token;
+ token.token_count = 1;
+
+ total_received += dmabuf_cmsg->frag_size;
+ fprintf(stderr,
+ "received frag_page=%llu, in_page_offset=%llu, frag_offset=%llu, frag_size=%u, token=%u, total_received=%lu, dmabuf_id=%u\n",
+ dmabuf_cmsg->frag_offset >> PAGE_SHIFT,
+ dmabuf_cmsg->frag_offset % getpagesize(),
+ dmabuf_cmsg->frag_offset,
+ dmabuf_cmsg->frag_size, dmabuf_cmsg->frag_token,
+ total_received, dmabuf_cmsg->dmabuf_id);
+
+ if (dmabuf_cmsg->dmabuf_id != dmabuf_id)
+ error(1, 0,
+ "received on wrong dmabuf_id: flow steering error\n");
+
+ if (dmabuf_cmsg->frag_size % getpagesize())
+ non_page_aligned_frags++;
+ else
+ page_aligned_frags++;
+
+ provider->memcpy_from_device(tmp_mem, mem,
+ dmabuf_cmsg->frag_offset,
+ dmabuf_cmsg->frag_size);
+
+ if (do_validation)
+ validate_buffer(tmp_mem,
+ dmabuf_cmsg->frag_size);
+ else
+ print_nonzero_bytes(tmp_mem,
+ dmabuf_cmsg->frag_size);
+
+ ret = setsockopt(client_fd, SOL_SOCKET,
+ SO_DEVMEM_DONTNEED, &token,
+ sizeof(token));
+ if (ret != 1)
+ error(1, 0,
+ "SO_DEVMEM_DONTNEED not enough tokens");
+ }
+ if (!is_devmem)
+ error(1, 0, "flow steering error\n");
+
+ fprintf(stderr, "total_received=%lu\n", total_received);
+ }
+
+ fprintf(stderr, "%s: ok\n", TEST_PREFIX);
+
+ fprintf(stderr, "page_aligned_frags=%lu, non_page_aligned_frags=%lu\n",
+ page_aligned_frags, non_page_aligned_frags);
+
+ fprintf(stderr, "page_aligned_frags=%lu, non_page_aligned_frags=%lu\n",
+ page_aligned_frags, non_page_aligned_frags);
+
+cleanup:
+
+ free(tmp_mem);
+ close(client_fd);
+ close(socket_fd);
+ ynl_sock_destroy(ys);
+
+ return 0;
+}
+
+void run_devmem_tests(void)
+{
+ struct netdev_queue_id *queues;
+ struct memory_buffer *mem;
+ struct ynl_sock *ys;
+ size_t i = 0;
+
+ mem = provider->alloc(getpagesize() * NUM_PAGES);
+
+ /* Configure RSS to divert all traffic from our devmem queues */
+ if (configure_rss())
+ error(1, 0, "rss error\n");
+
+ queues = calloc(num_queues, sizeof(*queues));
+
+ if (configure_headersplit(1))
+ error(1, 0, "Failed to configure header split\n");
+
+ if (!bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
+ error(1, 0, "Binding empty queues array should have failed\n");
+
+ for (i = 0; i < num_queues; i++) {
+ queues[i]._present.type = 1;
+ queues[i]._present.id = 1;
+ queues[i].type = NETDEV_QUEUE_TYPE_RX;
+ queues[i].id = start_queue + i;
+ }
+
+ if (configure_headersplit(0))
+ error(1, 0, "Failed to configure header split\n");
+
+ if (!bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
+ error(1, 0, "Configure dmabuf with header split off should have failed\n");
+
+ if (configure_headersplit(1))
+ error(1, 0, "Failed to configure header split\n");
+
+ for (i = 0; i < num_queues; i++) {
+ queues[i]._present.type = 1;
+ queues[i]._present.id = 1;
+ queues[i].type = NETDEV_QUEUE_TYPE_RX;
+ queues[i].id = start_queue + i;
+ }
+
+ if (bind_rx_queue(ifindex, mem->fd, queues, num_queues, &ys))
+ error(1, 0, "Failed to bind\n");
+
+ /* Deactivating a bound queue should not be legal */
+ if (!configure_channels(num_queues, num_queues - 1))
+ error(1, 0, "Deactivating a bound queue should be illegal.\n");
+
+ /* Closing the netlink socket does an implicit unbind */
+ ynl_sock_destroy(ys);
+
+ provider->free(mem);
+}
+
+int main(int argc, char *argv[])
+{
+ struct memory_buffer *mem;
+ int is_server = 0, opt;
+ int ret;
+
+ while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:")) != -1) {
+ switch (opt) {
+ case 'l':
+ is_server = 1;
+ break;
+ case 's':
+ server_ip = optarg;
+ break;
+ case 'c':
+ client_ip = optarg;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'v':
+ do_validation = atoll(optarg);
+ break;
+ case 'q':
+ num_queues = atoi(optarg);
+ break;
+ case 't':
+ start_queue = atoi(optarg);
+ break;
+ case 'f':
+ ifname = optarg;
+ break;
+ case '?':
+ fprintf(stderr, "unknown option: %c\n", optopt);
+ break;
+ }
+ }
+
+ if (!ifname)
+ error(1, 0, "Missing -f argument\n");
+
+ ifindex = if_nametoindex(ifname);
+
+ if (!server_ip && !client_ip) {
+ if (start_queue < 0 && num_queues < 0) {
+ num_queues = rxq_num(ifindex);
+ if (num_queues < 0)
+ error(1, 0, "couldn't detect number of queues\n");
+ if (num_queues < 2)
+ error(1, 0,
+ "number of device queues is too low\n");
+ /* make sure can bind to multiple queues */
+ start_queue = num_queues / 2;
+ num_queues /= 2;
+ }
+
+ if (start_queue < 0 || num_queues < 0)
+ error(1, 0, "Both -t and -q are required\n");
+
+ run_devmem_tests();
+ return 0;
+ }
+
+ if (start_queue < 0 && num_queues < 0) {
+ num_queues = rxq_num(ifindex);
+ if (num_queues < 2)
+ error(1, 0, "number of device queues is too low\n");
+
+ num_queues = 1;
+ start_queue = rxq_num(ifindex) - num_queues;
+
+ if (start_queue < 0)
+ error(1, 0, "couldn't detect number of queues\n");
+
+ fprintf(stderr, "using queues %d..%d\n", start_queue, start_queue + num_queues);
+ }
+
+ for (; optind < argc; optind++)
+ fprintf(stderr, "extra arguments: %s\n", argv[optind]);
+
+ if (start_queue < 0)
+ error(1, 0, "Missing -t argument\n");
+
+ if (num_queues < 0)
+ error(1, 0, "Missing -q argument\n");
+
+ if (!server_ip)
+ error(1, 0, "Missing -s argument\n");
+
+ if (!port)
+ error(1, 0, "Missing -p argument\n");
+
+ mem = provider->alloc(getpagesize() * NUM_PAGES);
+ ret = is_server ? do_server(mem) : 1;
+ provider->free(mem);
+
+ return ret;
+}
diff --git a/tools/testing/selftests/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
index 29995586993c..0b49ce7ae678 100755
--- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py
+++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
@@ -215,7 +215,7 @@ def test_rss_queue_reconfigure(cfg, main_ctx=True):
defer(ethtool, f"-X {cfg.ifname} default")
else:
other_key = 'noise'
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {ctx_id}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
@@ -238,6 +238,32 @@ def test_rss_queue_reconfigure(cfg, main_ctx=True):
else:
raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
+ if not main_ctx:
+ ethtool(f"-L {cfg.ifname} combined 4")
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 1"
+ try:
+ # this targets queue 4, which doesn't exist
+ ntuple2 = ethtool_create(cfg, "-N", flow)
+ except CmdExitFailure:
+ pass
+ else:
+ raise Exception(f"Driver didn't prevent us from targeting a nonexistent queue (context {ctx_id})")
+ # change the table to target queues 0 and 2
+ ethtool(f"-X {cfg.ifname} {ctx_ref} weight 1 0 1 0")
+ # ntuple rule therefore targets queues 1 and 3
+ ntuple2 = ethtool_create(cfg, "-N", flow)
+ # should replace existing filter
+ ksft_eq(ntuple, ntuple2)
+ _send_traffic_check(cfg, port, ctx_ref, { 'target': (1, 3),
+ 'noise' : (0, 2) })
+ # Setting queue count to 3 should fail, queue 3 is used
+ try:
+ ethtool(f"-L {cfg.ifname} combined 3")
+ except CmdExitFailure:
+ pass
+ else:
+ raise Exception(f"Driver didn't prevent us from deactivating a used queue (context {ctx_id})")
+
def test_rss_resize(cfg):
"""Test resizing of the RSS table.
@@ -429,7 +455,7 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
ksft_eq(max(data['rss-indirection-table']), 2 + i * 2 + 1, "Unexpected context cfg: " + str(data))
ports.append(rand_port())
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {ports[i]} context {ctx_id}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
@@ -516,7 +542,7 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
ctx.append(defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete"))
ports.append(rand_port())
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {ports[i]} context {ctx_id}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ntuple.append(defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}"))
@@ -569,7 +595,7 @@ def test_rss_context_overlap(cfg, other_ctx=0):
port = rand_port()
if other_ctx:
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {other_ctx}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {other_ctx}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ntuple = defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
@@ -587,7 +613,7 @@ def test_rss_context_overlap(cfg, other_ctx=0):
# Now create a rule for context 1 and make sure traffic goes to a subset
if other_ctx:
ntuple.exec()
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {ctx_id}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
@@ -620,7 +646,7 @@ def test_delete_rss_context_busy(cfg):
# utilize context from ntuple filter
port = rand_port()
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {ctx_id}"
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
@@ -633,6 +659,45 @@ def test_delete_rss_context_busy(cfg):
pass
+def test_rss_ntuple_addition(cfg):
+ """
+ Test that the queue offset (ring_cookie) of an ntuple rule is added
+ to the queue number read from the indirection table.
+ """
+
+ require_ntuple(cfg)
+
+ queue_cnt = len(_get_rx_cnts(cfg))
+ if queue_cnt < 4:
+ try:
+ ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
+ ethtool(f"-L {cfg.ifname} combined 4")
+ defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
+ except:
+ raise KsftSkipEx("Not enough queues for the test")
+
+ # Use queue 0 for normal traffic
+ ethtool(f"-X {cfg.ifname} equal 1")
+ defer(ethtool, f"-X {cfg.ifname} default")
+
+ # create additional rss context
+ ctx_id = ethtool_create(cfg, "-X", "context new equal 2")
+ defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
+
+ # utilize context from ntuple filter
+ port = rand_port()
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port} context {ctx_id} action 2"
+ try:
+ ntuple_id = ethtool_create(cfg, "-N", flow)
+ except CmdExitFailure:
+ raise KsftSkipEx("Ntuple filter with RSS and nonzero action not supported")
+ defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
+
+ _send_traffic_check(cfg, port, f"context {ctx_id}", { 'target': (2, 3),
+ 'empty' : (1,),
+ 'noise' : (0,) })
+
+
def main() -> None:
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
cfg.ethnl = EthtoolFamily()
@@ -644,7 +709,7 @@ def main() -> None:
test_rss_context_dump, test_rss_context_queue_reconfigure,
test_rss_context_overlap, test_rss_context_overlap2,
test_rss_context_out_of_order, test_rss_context4_create_with_cfg,
- test_delete_rss_context_busy],
+ test_delete_rss_context_busy, test_rss_ntuple_addition],
args=(cfg, ))
ksft_exit()
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap.sh
index 89b55e946eed..36055279ba92 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap.sh
@@ -116,7 +116,7 @@ dev_del_test()
log_test "Device delete"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
}
trap cleanup EXIT
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_drops.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_drops.sh
index 160891dcb4bc..db5806d189bb 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_drops.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_drops.sh
@@ -595,7 +595,7 @@ irif_disabled_test()
log_test "Ingress RIF disabled"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
ip link set dev $rp1 nomaster
__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
ip link del dev br0 type bridge
@@ -645,7 +645,7 @@ erif_disabled_test()
log_test "Egress RIF disabled"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
__addr_add_del $rp1 add 192.0.2.2/24 2001:db8:1::2/64
ip link del dev br0 type bridge
devlink_trap_action_set $trap_name "drop"
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh
index 190c1b6b5365..5d6d88b600f0 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_l3_exceptions.sh
@@ -202,7 +202,7 @@ mtu_value_is_too_small_test()
mtu_restore $rp2
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
}
@@ -235,7 +235,7 @@ __ttl_value_is_too_small_test()
log_test "TTL value is too small: TTL=$ttl_val"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $h1 ingress protocol ip pref 1 handle 101 flower
}
@@ -299,7 +299,7 @@ __mc_reverse_path_forwarding_test()
log_test "Multicast reverse path forwarding: $desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $rp2 egress protocol $proto pref 1 handle 101 flower
}
@@ -347,7 +347,7 @@ __reject_route_test()
log_test "Reject route: $desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
ip route del unreachable $unreachable
tc filter del dev $h1 ingress protocol $proto pref 1 handle 101 flower
}
@@ -542,7 +542,7 @@ ipv4_lpm_miss_test()
log_test "LPM miss: IPv4"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
vrf_without_routes_destroy
}
@@ -569,7 +569,7 @@ ipv6_lpm_miss_test()
log_test "LPM miss: IPv6"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
vrf_without_routes_destroy
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip.sh
index e9a82cae8c9a..4ac1dae92d0f 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip.sh
@@ -176,7 +176,7 @@ ecn_decap_test()
log_test "$desc: Inner ECN is not ECT and outer is $ecn_desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ip pref 1 handle 101 flower
}
@@ -207,7 +207,7 @@ no_matching_tunnel_test()
log_test "$desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ip pref 1 handle 101 flower
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip6.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip6.sh
index 878125041fc3..fce885184404 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip6.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_ipip6.sh
@@ -176,7 +176,7 @@ ecn_decap_test()
log_test "$desc: Inner ECN is not ECT and outer is $ecn_desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ipv6 pref 1 handle 101 flower
}
@@ -207,7 +207,7 @@ no_matching_tunnel_test()
log_test "$desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ipv6 pref 1 handle 101 flower
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan.sh
index 5f6eb965cfd1..7aca8e5922cf 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan.sh
@@ -183,7 +183,7 @@ ecn_decap_test()
log_test "$desc: Inner ECN is not ECT and outer is $ecn_desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ip pref 1 handle 101 flower
}
@@ -253,7 +253,7 @@ corrupted_packet_test()
log_test "$desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ip pref 1 handle 101 flower
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan_ipv6.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan_ipv6.sh
index f6c16cbb6cf7..4599c331240b 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan_ipv6.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_tunnel_vxlan_ipv6.sh
@@ -188,7 +188,7 @@ ecn_decap_test()
log_test "$desc: Inner ECN is not ECT and outer is $ecn_desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ipv6 pref 1 handle 101 flower
}
@@ -262,7 +262,7 @@ corrupted_packet_test()
log_test "$desc"
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $swp1 egress protocol ipv6 pref 1 handle 101 flower
}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
index 83a0210e7544..bc7ea2df49fb 100755
--- a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
+++ b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh
@@ -218,7 +218,7 @@ psample_capture_start()
psample_capture_stop()
{
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
}
__tc_sample_rate_test()
@@ -499,7 +499,7 @@ tc_sample_md_out_tc_occ_test()
backlog=$(tc -j -p -s qdisc show dev $rp2 | jq '.[0]["backlog"]')
# Kill mausezahn.
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
psample_capture_stop
diff --git a/tools/testing/selftests/drivers/net/netcons_basic.sh b/tools/testing/selftests/drivers/net/netcons_basic.sh
index 06021b2059b7..b175f4d966e5 100755
--- a/tools/testing/selftests/drivers/net/netcons_basic.sh
+++ b/tools/testing/selftests/drivers/net/netcons_basic.sh
@@ -20,22 +20,26 @@ SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
# Simple script to test dynamic targets in netconsole
SRCIF="" # to be populated later
-SRCIP=192.168.1.1
+SRCIP=192.0.2.1
DSTIF="" # to be populated later
-DSTIP=192.168.1.2
+DSTIP=192.0.2.2
PORT="6666"
MSG="netconsole selftest"
+USERDATA_KEY="key"
+USERDATA_VALUE="value"
TARGET=$(mktemp -u netcons_XXXXX)
DEFAULT_PRINTK_VALUES=$(cat /proc/sys/kernel/printk)
NETCONS_CONFIGFS="/sys/kernel/config/netconsole"
NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
+KEY_PATH="${NETCONS_PATH}/userdata/${USERDATA_KEY}"
# NAMESPACE will be populated by setup_ns with a random value
NAMESPACE=""
# IDs for netdevsim
NSIM_DEV_1_ID=$((256 + RANDOM % 256))
NSIM_DEV_2_ID=$((512 + RANDOM % 256))
+NSIM_DEV_SYS_NEW="/sys/bus/netdevsim/new_device"
# Used to create and delete namespaces
source "${SCRIPTDIR}"/../../net/lib.sh
@@ -43,7 +47,6 @@ source "${SCRIPTDIR}"/../../net/net_helper.sh
# Create netdevsim interfaces
create_ifaces() {
- local NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device
echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
@@ -122,6 +125,8 @@ function cleanup() {
# delete netconsole dynamic reconfiguration
echo 0 > "${NETCONS_PATH}"/enabled
+ # Remove key
+ rmdir "${KEY_PATH}"
# Remove the configfs entry
rmdir "${NETCONS_PATH}"
@@ -136,6 +141,18 @@ function cleanup() {
echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
}
+function set_user_data() {
+ if [[ ! -d "${NETCONS_PATH}""/userdata" ]]
+ then
+ echo "Userdata path not available in ${NETCONS_PATH}/userdata"
+ exit "${ksft_skip}"
+ fi
+
+ mkdir -p "${KEY_PATH}"
+ VALUE_PATH="${KEY_PATH}""/value"
+ echo "${USERDATA_VALUE}" > "${VALUE_PATH}"
+}
+
function listen_port_and_save_to() {
local OUTPUT=${1}
# Just wait for 2 seconds
@@ -146,6 +163,10 @@ function listen_port_and_save_to() {
function validate_result() {
local TMPFILENAME="$1"
+ # TMPFILENAME will contain something like:
+ # 6.11.1-0_fbk0_rc13_509_g30d75cea12f7,13,1822,115075213798,-;netconsole selftest: netcons_gtJHM
+ # key=value
+
# Check if the file exists
if [ ! -f "$TMPFILENAME" ]; then
echo "FAIL: File was not generated." >&2
@@ -158,6 +179,12 @@ function validate_result() {
exit "${ksft_fail}"
fi
+ if ! grep -q "${USERDATA_KEY}=${USERDATA_VALUE}" "${TMPFILENAME}"; then
+ echo "FAIL: ${USERDATA_KEY}=${USERDATA_VALUE} not found in ${TMPFILENAME}" >&2
+ cat "${TMPFILENAME}" >&2
+ exit "${ksft_fail}"
+ fi
+
# Delete the file once it is validated, otherwise keep it
# for debugging purposes
rm "${TMPFILENAME}"
@@ -185,6 +212,11 @@ function check_for_dependencies() {
exit "${ksft_skip}"
fi
+ if [ ! -f "${NSIM_DEV_SYS_NEW}" ]; then
+ echo "SKIP: file ${NSIM_DEV_SYS_NEW} does not exist. Check if CONFIG_NETDEVSIM is enabled" >&2
+ exit "${ksft_skip}"
+ fi
+
if [ ! -d "${NETCONS_CONFIGFS}" ]; then
echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2
exit "${ksft_skip}"
@@ -220,6 +252,8 @@ trap cleanup EXIT
set_network
# Create a dynamic target for netconsole
create_dynamic_target
+# Set userdata "key" with the "value" value
+set_user_data
# Listed for netconsole port inside the namespace and destination interface
listen_port_and_save_to "${OUTPUT_FILE}" &
# Wait for socat to start and listen to the port.
diff --git a/tools/testing/selftests/drivers/net/netdevsim/Makefile b/tools/testing/selftests/drivers/net/netdevsim/Makefile
index 5bace0b7fb57..07b7c46d3311 100644
--- a/tools/testing/selftests/drivers/net/netdevsim/Makefile
+++ b/tools/testing/selftests/drivers/net/netdevsim/Makefile
@@ -4,11 +4,14 @@ TEST_PROGS = devlink.sh \
devlink_in_netns.sh \
devlink_trap.sh \
ethtool-coalesce.sh \
+ ethtool-features.sh \
ethtool-fec.sh \
ethtool-pause.sh \
ethtool-ring.sh \
fib.sh \
+ fib_notifications.sh \
hw_stats_l3.sh \
+ macsec-offload.sh \
nexthop.sh \
peer.sh \
psample.sh \
diff --git a/tools/testing/selftests/drivers/net/netdevsim/config b/tools/testing/selftests/drivers/net/netdevsim/config
index adf45a3a78b4..5117c78ddf0a 100644
--- a/tools/testing/selftests/drivers/net/netdevsim/config
+++ b/tools/testing/selftests/drivers/net/netdevsim/config
@@ -1,6 +1,7 @@
CONFIG_DUMMY=y
CONFIG_GENEVE=m
CONFIG_IPV6=y
+CONFIG_MACSEC=m
CONFIG_NETDEVSIM=m
CONFIG_NET_SCH_MQPRIO=y
CONFIG_NET_SCH_MULTIQ=y
diff --git a/tools/testing/selftests/drivers/net/netdevsim/ethtool-features.sh b/tools/testing/selftests/drivers/net/netdevsim/ethtool-features.sh
new file mode 100644
index 000000000000..bc210dc6ad2d
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/netdevsim/ethtool-features.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source ethtool-common.sh
+
+NSIM_NETDEV=$(make_netdev)
+
+set -o pipefail
+
+FEATS="
+ tx-checksum-ip-generic
+ tx-scatter-gather
+ tx-tcp-segmentation
+ generic-segmentation-offload
+ generic-receive-offload"
+
+for feat in $FEATS ; do
+ s=$(ethtool --json -k $NSIM_NETDEV | jq ".[].\"$feat\".active" 2>/dev/null)
+ check $? "$s" true
+
+ s=$(ethtool --json -k $NSIM_NETDEV | jq ".[].\"$feat\".fixed" 2>/dev/null)
+ check $? "$s" false
+done
+
+if [ $num_errors -eq 0 ]; then
+ echo "PASSED all $((num_passes)) checks"
+ exit 0
+else
+ echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
+ exit 1
+fi
diff --git a/tools/testing/selftests/drivers/net/netdevsim/fib_notifications.sh b/tools/testing/selftests/drivers/net/netdevsim/fib_notifications.sh
index 8d91191a098c..9896580c3d85 100755
--- a/tools/testing/selftests/drivers/net/netdevsim/fib_notifications.sh
+++ b/tools/testing/selftests/drivers/net/netdevsim/fib_notifications.sh
@@ -94,7 +94,7 @@ route_addition_check()
sleep 1
$IP route add $route dev dummy1
sleep 1
- kill %% && wait %% &> /dev/null
+ kill_process %%
route_notify_check $outfile $expected_num_notifications $offload_failed
rm -f $outfile
@@ -148,7 +148,7 @@ route_deletion_check()
sleep 1
$IP route del $route dev dummy1
sleep 1
- kill %% && wait %% &> /dev/null
+ kill_process %%
route_notify_check $outfile $expected_num_notifications
rm -f $outfile
@@ -191,7 +191,7 @@ route_replacement_check()
sleep 1
$IP route replace $route dev dummy2
sleep 1
- kill %% && wait %% &> /dev/null
+ kill_process %%
route_notify_check $outfile $expected_num_notifications
rm -f $outfile
diff --git a/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh b/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
new file mode 100755
index 000000000000..98033e6667d2
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/netdevsim/macsec-offload.sh
@@ -0,0 +1,117 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-only
+
+source ethtool-common.sh
+
+NSIM_NETDEV=$(make_netdev)
+MACSEC_NETDEV=macsec_nsim
+
+set -o pipefail
+
+if ! ethtool -k $NSIM_NETDEV | grep -q 'macsec-hw-offload: on'; then
+ echo "SKIP: netdevsim doesn't support MACsec offload"
+ exit 4
+fi
+
+if ! ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac 2>/dev/null; then
+ echo "SKIP: couldn't create macsec device"
+ exit 4
+fi
+ip link del $MACSEC_NETDEV
+
+#
+# test macsec offload API
+#
+
+ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}" type macsec port 4 offload mac
+check $?
+
+ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}2" type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
+check $?
+
+ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}3" type macsec sci abbacdde01020304 offload mac
+check $?
+
+ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}4" type macsec port 8 offload mac 2> /dev/null
+check $? '' '' 1
+
+ip macsec add "${MACSEC_NETDEV}" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
+check $?
+
+ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef"
+check $?
+
+ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
+ key 00 0123456789abcdef0123456789abcdef
+check $?
+
+ip macsec add "${MACSEC_NETDEV}" rx port 1235 address "1c:ed:de:ad:be:ef" 2> /dev/null
+check $? '' '' 1
+
+# can't disable macsec offload when SAs are configured
+ip link set "${MACSEC_NETDEV}" type macsec offload off 2> /dev/null
+check $? '' '' 1
+
+ip macsec offload "${MACSEC_NETDEV}" off 2> /dev/null
+check $? '' '' 1
+
+# toggle macsec offload via rtnetlink
+ip link set "${MACSEC_NETDEV}2" type macsec offload off
+check $?
+
+ip link set "${MACSEC_NETDEV}2" type macsec offload mac
+check $?
+
+# toggle macsec offload via genetlink
+ip macsec offload "${MACSEC_NETDEV}2" off
+check $?
+
+ip macsec offload "${MACSEC_NETDEV}2" mac
+check $?
+
+for dev in ${MACSEC_NETDEV}{,2,3} ; do
+ ip link del $dev
+ check $?
+done
+
+
+#
+# test ethtool features when toggling offload
+#
+
+ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac
+TMP_FEATS_ON_1="$(ethtool -k $MACSEC_NETDEV)"
+
+ip link set $MACSEC_NETDEV type macsec offload off
+TMP_FEATS_OFF_1="$(ethtool -k $MACSEC_NETDEV)"
+
+ip link set $MACSEC_NETDEV type macsec offload mac
+TMP_FEATS_ON_2="$(ethtool -k $MACSEC_NETDEV)"
+
+[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_2" ]
+check $?
+
+ip link del $MACSEC_NETDEV
+
+ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec
+check $?
+
+TMP_FEATS_OFF_2="$(ethtool -k $MACSEC_NETDEV)"
+[ "$TMP_FEATS_OFF_1" = "$TMP_FEATS_OFF_2" ]
+check $?
+
+ip link set $MACSEC_NETDEV type macsec offload mac
+check $?
+
+TMP_FEATS_ON_3="$(ethtool -k $MACSEC_NETDEV)"
+[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_3" ]
+check $?
+
+
+if [ $num_errors -eq 0 ]; then
+ echo "PASSED all $((num_passes)) checks"
+ exit 0
+else
+ echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
+ exit 1
+fi
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/mount_options.tc b/tools/testing/selftests/ftrace/test.d/00basic/mount_options.tc
new file mode 100644
index 000000000000..35e8d47d6072
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/mount_options.tc
@@ -0,0 +1,101 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Test tracefs GID mount option
+# requires: "[gid=<gid>]":README
+
+fail() {
+ local msg="$1"
+
+ echo "FAILED: $msg"
+ exit_fail
+}
+
+find_alternate_gid() {
+ local original_gid="$1"
+ tac /etc/group | grep -v ":$original_gid:" | head -1 | cut -d: -f3
+}
+
+mount_tracefs_with_options() {
+ local mount_point="$1"
+ local options="$2"
+
+ mount -t tracefs -o "$options" nodev "$mount_point"
+
+ setup
+}
+
+unmount_tracefs() {
+ local mount_point="$1"
+
+ # Need to make sure the mount isn't busy so that we can umount it
+ (cd $mount_point; finish_ftrace;)
+
+ cleanup
+}
+
+create_instance() {
+ local mount_point="$1"
+ local instance="$mount_point/instances/$(mktemp -u test-XXXXXX)"
+
+ mkdir "$instance"
+ echo "$instance"
+}
+
+remove_instance() {
+ local instance="$1"
+
+ rmdir "$instance"
+}
+
+check_gid() {
+ local mount_point="$1"
+ local expected_gid="$2"
+
+ echo "Checking permission group ..."
+
+ cd "$mount_point"
+
+ for file in "." "events" "events/sched" "events/sched/sched_switch" "events/sched/sched_switch/enable"; do
+ local gid=`stat -c "%g" $file`
+ if [ "$gid" -ne "$expected_gid" ]; then
+ cd - # Return to the previous working directory (tracefs root)
+ fail "$(realpath $file): Expected group $expected_gid; Got group $gid"
+ fi
+ done
+
+ cd - # Return to the previous working directory (tracefs root)
+}
+
+test_gid_mount_option() {
+ local mount_point=$(get_mount_point)
+ local mount_options=$(get_mnt_options "$mount_point")
+ local original_group=$(stat -c "%g" .)
+ local other_group=$(find_alternate_gid "$original_group")
+
+ # Set up mount options with new GID for testing
+ local new_options=`echo "$mount_options" | sed -e "s/gid=[0-9]*/gid=$other_group/"`
+ if [ "$new_options" = "$mount_options" ]; then
+ new_options="$mount_options,gid=$other_group"
+ mount_options="$mount_options,gid=$original_group"
+ fi
+
+ # Unmount existing tracefs instance and mount with new GID
+ unmount_tracefs "$mount_point"
+ mount_tracefs_with_options "$mount_point" "$new_options"
+
+ check_gid "$mount_point" "$other_group"
+
+ # Check that files created after the mount inherit the GID
+ local instance=$(create_instance "$mount_point")
+ check_gid "$instance" "$other_group"
+ remove_instance "$instance"
+
+ # Unmount and remount with the original GID
+ unmount_tracefs "$mount_point"
+ mount_tracefs_with_options "$mount_point" "$mount_options"
+ check_gid "$mount_point" "$original_group"
+}
+
+test_gid_mount_option
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc b/tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc
index 094419e190c2..e71cc3ad0bdf 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/test_ownership.tc
@@ -1,24 +1,14 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Test file and directory ownership changes for eventfs
+# requires: "[gid=<gid>]":README
original_group=`stat -c "%g" .`
original_owner=`stat -c "%u" .`
-mount_point=`stat -c '%m' .`
+local mount_point=$(get_mount_point)
-# If stat -c '%m' does not work (e.g. busybox) or failed, try to use the
-# current working directory (which should be a tracefs) as the mount point.
-if [ ! -d "$mount_point" ]; then
- if mount | grep -qw $PWD ; then
- mount_point=$PWD
- else
- # If PWD doesn't work, that is an environmental problem.
- exit_unresolved
- fi
-fi
-
-mount_options=`mount | grep "$mount_point" | sed -e 's/.*(\(.*\)).*/\1/'`
+mount_options=$(get_mnt_options "$mount_point")
# find another owner and group that is not the original
other_group=`tac /etc/group | grep -v ":$original_group:" | head -1 | cut -d: -f3`
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 779f3e62ec90..84d6a9c7ad67 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -193,3 +193,28 @@ ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
# " Command: " and "^\n" => 13
test $(expr 13 + $pos) -eq $N
}
+
+# Helper to get the tracefs mount point
+get_mount_point() {
+ local mount_point=`stat -c '%m' .`
+
+ # If stat -c '%m' does not work (e.g. busybox) or failed, try to use the
+ # current working directory (which should be a tracefs) as the mount point.
+ if [ ! -d "$mount_point" ]; then
+ if mount | grep -qw "$PWD"; then
+ mount_point=$PWD
+ else
+ # If PWD doesn't work, that is an environmental problem.
+ exit_unresolved
+ fi
+ fi
+ echo "$mount_point"
+}
+
+# Helper function to retrieve mount options for a given mount point
+get_mnt_options() {
+ local mnt_point="$1"
+ local opts=$(mount | grep -m1 "$mnt_point" | sed -e 's/.*(\(.*\)).*/\1/')
+
+ echo "$opts"
+} \ No newline at end of file
diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh
index e7008f614ad7..6a3b8503264e 100755
--- a/tools/testing/selftests/intel_pstate/run.sh
+++ b/tools/testing/selftests/intel_pstate/run.sh
@@ -44,6 +44,11 @@ if [ $UID != 0 ] && [ $EVALUATE_ONLY == 0 ]; then
exit $ksft_skip
fi
+if ! command -v cpupower &> /dev/null; then
+ echo $msg cpupower could not be found, please install it >&2
+ exit $ksft_skip
+fi
+
max_cpus=$(($(nproc)-1))
function run_test () {
@@ -87,9 +92,9 @@ mkt_freq=${_mkt_freq}0
# Get the ranges from cpupower
_min_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $1 } ')
-min_freq=$(($_min_freq / 1000))
+min_freq=$((_min_freq / 1000))
_max_freq=$(cpupower frequency-info -l | tail -1 | awk ' { print $2 } ')
-max_freq=$(($_max_freq / 1000))
+max_freq=$((_max_freq / 1000))
[ $EVALUATE_ONLY -eq 0 ] && for freq in `seq $max_freq -100 $min_freq`
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 156fbfae940f..48645a2e29da 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -241,16 +241,18 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
-Wno-gnu-variable-sized-type-not-at-end -MD -MP -DCONFIG_64BIT \
-fno-builtin-memcmp -fno-builtin-memcpy \
-fno-builtin-memset -fno-builtin-strnlen \
- -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \
- -I$(LINUX_TOOL_ARCH_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude \
- -I$(<D) -Iinclude/$(ARCH_DIR) -I ../rseq -I.. $(EXTRA_CFLAGS) \
- $(KHDR_INCLUDES)
+ -fno-stack-protector -fno-PIE -fno-strict-aliasing \
+ -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_TOOL_ARCH_INCLUDE) \
+ -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -Iinclude/$(ARCH_DIR) \
+ -I ../rseq -I.. $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
ifeq ($(ARCH),s390)
CFLAGS += -march=z10
endif
ifeq ($(ARCH),x86)
+ifeq ($(shell echo "void foo(void) { }" | $(CC) -march=x86-64-v2 -x c - -c -o /dev/null 2>/dev/null; echo "$$?"),0)
CFLAGS += -march=x86-64-v2
endif
+endif
ifeq ($(ARCH),arm64)
tools_dir := $(top_srcdir)/tools
arm64_tools_dir := $(tools_dir)/arch/arm64/tools/
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index ba0c8e996035..ce687f8d248f 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -134,7 +134,7 @@ static void test_create_guest_memfd_invalid(struct kvm_vm *vm)
size);
}
- for (flag = 0; flag; flag <<= 1) {
+ for (flag = BIT(0); flag; flag <<= 1) {
fd = __vm_create_guest_memfd(vm, page_size, flag);
TEST_ASSERT(fd == -1 && errno == EINVAL,
"guest_memfd() with flag '0x%lx' should fail with EINVAL",
diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c
index 089b8925b6b2..d7ac122820bf 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c
@@ -200,7 +200,7 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx)
if (vmx->eptp_gpa) {
uint64_t ept_paddr;
struct eptPageTablePointer eptp = {
- .memory_type = VMX_BASIC_MEM_TYPE_WB,
+ .memory_type = X86_MEMTYPE_WB,
.page_walk_length = 3, /* + 1 */
.ad_enabled = ept_vpid_cap_supported(VMX_EPT_VPID_CAP_AD_BITS),
.address = vmx->eptp_gpa >> PAGE_SHIFT_4K,
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index 989ffe0d047f..e3711beff7f3 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -417,7 +417,7 @@ static bool _guest_should_exit(void)
*/
static noinline void host_perform_sync(struct sync_area *sync)
{
- alarm(2);
+ alarm(10);
atomic_store_explicit(&sync->sync_flag, true, memory_order_release);
while (atomic_load_explicit(&sync->sync_flag, memory_order_acquire))
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index 02e1204971b0..acec529baaca 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -36,6 +36,8 @@ MAKEFLAGS += --no-builtin-rules
CFLAGS = -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
LDLIBS = -lrt -lpthread -lm
+TEST_GEN_MODS_DIR := page_frag
+
TEST_GEN_FILES = cow
TEST_GEN_FILES += compaction_test
TEST_GEN_FILES += gup_longterm
@@ -126,6 +128,7 @@ TEST_FILES += test_hmm.sh
TEST_FILES += va_high_addr_switch.sh
TEST_FILES += charge_reserved_hugetlb.sh
TEST_FILES += hugetlb_reparenting_test.sh
+TEST_FILES += test_page_frag.sh
# required by charge_reserved_hugetlb.sh
TEST_FILES += write_hugetlb_memory.sh
diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c
index f9ac20c657ec..432d5af15e66 100644
--- a/tools/testing/selftests/mm/hugetlb_dio.c
+++ b/tools/testing/selftests/mm/hugetlb_dio.c
@@ -94,8 +94,20 @@ void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off)
int main(void)
{
size_t pagesize = 0;
+ int fd;
ksft_print_header();
+
+ /* Open the file to DIO */
+ fd = open("/tmp", O_TMPFILE | O_RDWR | O_DIRECT, 0664);
+ if (fd < 0)
+ ksft_exit_skip("Unable to allocate file: %s\n", strerror(errno));
+ close(fd);
+
+ /* Check if huge pages are free */
+ if (!get_free_hugepages())
+ ksft_exit_skip("No free hugepage, exiting\n");
+
ksft_set_plan(4);
/* Get base page size */
diff --git a/tools/testing/selftests/mm/page_frag/Makefile b/tools/testing/selftests/mm/page_frag/Makefile
new file mode 100644
index 000000000000..58dda74d50a3
--- /dev/null
+++ b/tools/testing/selftests/mm/page_frag/Makefile
@@ -0,0 +1,18 @@
+PAGE_FRAG_TEST_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
+KDIR ?= $(abspath $(PAGE_FRAG_TEST_DIR)/../../../../..)
+
+ifeq ($(V),1)
+Q =
+else
+Q = @
+endif
+
+MODULES = page_frag_test.ko
+
+obj-m += page_frag_test.o
+
+all:
+ +$(Q)make -C $(KDIR) M=$(PAGE_FRAG_TEST_DIR) modules
+
+clean:
+ +$(Q)make -C $(KDIR) M=$(PAGE_FRAG_TEST_DIR) clean
diff --git a/tools/testing/selftests/mm/page_frag/page_frag_test.c b/tools/testing/selftests/mm/page_frag/page_frag_test.c
new file mode 100644
index 000000000000..e806c1866e36
--- /dev/null
+++ b/tools/testing/selftests/mm/page_frag/page_frag_test.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Test module for page_frag cache
+ *
+ * Copyright (C) 2024 Yunsheng Lin <linyunsheng@huawei.com>
+ */
+
+#include <linux/module.h>
+#include <linux/cpumask.h>
+#include <linux/completion.h>
+#include <linux/ptr_ring.h>
+#include <linux/kthread.h>
+#include <linux/page_frag_cache.h>
+
+#define TEST_FAILED_PREFIX "page_frag_test failed: "
+
+static struct ptr_ring ptr_ring;
+static int nr_objs = 512;
+static atomic_t nthreads;
+static struct completion wait;
+static struct page_frag_cache test_nc;
+static int test_popped;
+static int test_pushed;
+static bool force_exit;
+
+static int nr_test = 2000000;
+module_param(nr_test, int, 0);
+MODULE_PARM_DESC(nr_test, "number of iterations to test");
+
+static bool test_align;
+module_param(test_align, bool, 0);
+MODULE_PARM_DESC(test_align, "use align API for testing");
+
+static int test_alloc_len = 2048;
+module_param(test_alloc_len, int, 0);
+MODULE_PARM_DESC(test_alloc_len, "alloc len for testing");
+
+static int test_push_cpu;
+module_param(test_push_cpu, int, 0);
+MODULE_PARM_DESC(test_push_cpu, "test cpu for pushing fragment");
+
+static int test_pop_cpu;
+module_param(test_pop_cpu, int, 0);
+MODULE_PARM_DESC(test_pop_cpu, "test cpu for popping fragment");
+
+static int page_frag_pop_thread(void *arg)
+{
+ struct ptr_ring *ring = arg;
+
+ pr_info("page_frag pop test thread begins on cpu %d\n",
+ smp_processor_id());
+
+ while (test_popped < nr_test) {
+ void *obj = __ptr_ring_consume(ring);
+
+ if (obj) {
+ test_popped++;
+ page_frag_free(obj);
+ } else {
+ if (force_exit)
+ break;
+
+ cond_resched();
+ }
+ }
+
+ if (atomic_dec_and_test(&nthreads))
+ complete(&wait);
+
+ pr_info("page_frag pop test thread exits on cpu %d\n",
+ smp_processor_id());
+
+ return 0;
+}
+
+static int page_frag_push_thread(void *arg)
+{
+ struct ptr_ring *ring = arg;
+
+ pr_info("page_frag push test thread begins on cpu %d\n",
+ smp_processor_id());
+
+ while (test_pushed < nr_test && !force_exit) {
+ void *va;
+ int ret;
+
+ if (test_align) {
+ va = page_frag_alloc_align(&test_nc, test_alloc_len,
+ GFP_KERNEL, SMP_CACHE_BYTES);
+
+ if ((unsigned long)va & (SMP_CACHE_BYTES - 1)) {
+ force_exit = true;
+ WARN_ONCE(true, TEST_FAILED_PREFIX "unaligned va returned\n");
+ }
+ } else {
+ va = page_frag_alloc(&test_nc, test_alloc_len, GFP_KERNEL);
+ }
+
+ if (!va)
+ continue;
+
+ ret = __ptr_ring_produce(ring, va);
+ if (ret) {
+ page_frag_free(va);
+ cond_resched();
+ } else {
+ test_pushed++;
+ }
+ }
+
+ pr_info("page_frag push test thread exits on cpu %d\n",
+ smp_processor_id());
+
+ if (atomic_dec_and_test(&nthreads))
+ complete(&wait);
+
+ return 0;
+}
+
+static int __init page_frag_test_init(void)
+{
+ struct task_struct *tsk_push, *tsk_pop;
+ int last_pushed = 0, last_popped = 0;
+ ktime_t start;
+ u64 duration;
+ int ret;
+
+ page_frag_cache_init(&test_nc);
+ atomic_set(&nthreads, 2);
+ init_completion(&wait);
+
+ if (test_alloc_len > PAGE_SIZE || test_alloc_len <= 0 ||
+ !cpu_active(test_push_cpu) || !cpu_active(test_pop_cpu))
+ return -EINVAL;
+
+ ret = ptr_ring_init(&ptr_ring, nr_objs, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ tsk_push = kthread_create_on_cpu(page_frag_push_thread, &ptr_ring,
+ test_push_cpu, "page_frag_push");
+ if (IS_ERR(tsk_push))
+ return PTR_ERR(tsk_push);
+
+ tsk_pop = kthread_create_on_cpu(page_frag_pop_thread, &ptr_ring,
+ test_pop_cpu, "page_frag_pop");
+ if (IS_ERR(tsk_pop)) {
+ kthread_stop(tsk_push);
+ return PTR_ERR(tsk_pop);
+ }
+
+ start = ktime_get();
+ wake_up_process(tsk_push);
+ wake_up_process(tsk_pop);
+
+ pr_info("waiting for test to complete\n");
+
+ while (!wait_for_completion_timeout(&wait, msecs_to_jiffies(10000))) {
+ /* exit if there is no progress for push or pop size */
+ if (last_pushed == test_pushed || last_popped == test_popped) {
+ WARN_ONCE(true, TEST_FAILED_PREFIX "no progress\n");
+ force_exit = true;
+ continue;
+ }
+
+ last_pushed = test_pushed;
+ last_popped = test_popped;
+ pr_info("page_frag_test progress: pushed = %d, popped = %d\n",
+ test_pushed, test_popped);
+ }
+
+ if (force_exit) {
+ pr_err(TEST_FAILED_PREFIX "exit with error\n");
+ goto out;
+ }
+
+ duration = (u64)ktime_us_delta(ktime_get(), start);
+ pr_info("%d of iterations for %s testing took: %lluus\n", nr_test,
+ test_align ? "aligned" : "non-aligned", duration);
+
+out:
+ ptr_ring_cleanup(&ptr_ring, NULL);
+ page_frag_cache_drain(&test_nc);
+
+ return -EAGAIN;
+}
+
+static void __exit page_frag_test_exit(void)
+{
+}
+
+module_init(page_frag_test_init);
+module_exit(page_frag_test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yunsheng Lin <linyunsheng@huawei.com>");
+MODULE_DESCRIPTION("Test module for page_frag");
diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh
index c5797ad1d37b..2c5394584af4 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -75,6 +75,8 @@ separated by spaces:
read-only VMAs
- mdwe
test prctl(PR_SET_MDWE, ...)
+- page_frag
+ test handling of page fragment allocation and freeing
example: ./run_vmtests.sh -t "hmm mmap ksm"
EOF
@@ -456,6 +458,12 @@ CATEGORY="mkdirty" run_test ./mkdirty
CATEGORY="mdwe" run_test ./mdwe_test
+CATEGORY="page_frag" run_test ./test_page_frag.sh smoke
+
+CATEGORY="page_frag" run_test ./test_page_frag.sh aligned
+
+CATEGORY="page_frag" run_test ./test_page_frag.sh nonaligned
+
echo "SUMMARY: PASS=${count_pass} SKIP=${count_skip} FAIL=${count_fail}" | tap_prefix
echo "1..${count_total}" | tap_output
diff --git a/tools/testing/selftests/mm/test_page_frag.sh b/tools/testing/selftests/mm/test_page_frag.sh
new file mode 100755
index 000000000000..f55b105084cf
--- /dev/null
+++ b/tools/testing/selftests/mm/test_page_frag.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2024 Yunsheng Lin <linyunsheng@huawei.com>
+# Copyright (C) 2018 Uladzislau Rezki (Sony) <urezki@gmail.com>
+#
+# This is a test script for the kernel test driver to test the
+# correctness and performance of page_frag's implementation.
+# Therefore it is just a kernel module loader. You can specify
+# and pass different parameters in order to:
+# a) analyse performance of page fragment allocations;
+# b) stressing and stability check of page_frag subsystem.
+
+DRIVER="./page_frag/page_frag_test.ko"
+CPU_LIST=$(grep -m 2 processor /proc/cpuinfo | cut -d ' ' -f 2)
+TEST_CPU_0=$(echo $CPU_LIST | awk '{print $1}')
+
+if [ $(echo $CPU_LIST | wc -w) -gt 1 ]; then
+ TEST_CPU_1=$(echo $CPU_LIST | awk '{print $2}')
+ NR_TEST=100000000
+else
+ TEST_CPU_1=$TEST_CPU_0
+ NR_TEST=1000000
+fi
+
+# 1 if fails
+exitcode=1
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+
+check_test_failed_prefix() {
+ if dmesg | grep -q 'page_frag_test failed:';then
+ echo "page_frag_test failed, please check dmesg"
+ exit $exitcode
+ fi
+}
+
+#
+# Static templates for testing of page_frag APIs.
+# Also it is possible to pass any supported parameters manually.
+#
+SMOKE_PARAM="test_push_cpu=$TEST_CPU_0 test_pop_cpu=$TEST_CPU_1"
+NONALIGNED_PARAM="$SMOKE_PARAM test_alloc_len=75 nr_test=$NR_TEST"
+ALIGNED_PARAM="$NONALIGNED_PARAM test_align=1"
+
+check_test_requirements()
+{
+ uid=$(id -u)
+ if [ $uid -ne 0 ]; then
+ echo "$0: Must be run as root"
+ exit $ksft_skip
+ fi
+
+ if ! which insmod > /dev/null 2>&1; then
+ echo "$0: You need insmod installed"
+ exit $ksft_skip
+ fi
+
+ if [ ! -f $DRIVER ]; then
+ echo "$0: You need to compile page_frag_test module"
+ exit $ksft_skip
+ fi
+}
+
+run_nonaligned_check()
+{
+ echo "Run performance tests to evaluate how fast nonaligned alloc API is."
+
+ insmod $DRIVER $NONALIGNED_PARAM > /dev/null 2>&1
+}
+
+run_aligned_check()
+{
+ echo "Run performance tests to evaluate how fast aligned alloc API is."
+
+ insmod $DRIVER $ALIGNED_PARAM > /dev/null 2>&1
+}
+
+run_smoke_check()
+{
+ echo "Run smoke test."
+
+ insmod $DRIVER $SMOKE_PARAM > /dev/null 2>&1
+}
+
+usage()
+{
+ echo -n "Usage: $0 [ aligned ] | [ nonaligned ] | | [ smoke ] | "
+ echo "manual parameters"
+ echo
+ echo "Valid tests and parameters:"
+ echo
+ modinfo $DRIVER
+ echo
+ echo "Example usage:"
+ echo
+ echo "# Shows help message"
+ echo "$0"
+ echo
+ echo "# Smoke testing"
+ echo "$0 smoke"
+ echo
+ echo "# Performance testing for nonaligned alloc API"
+ echo "$0 nonaligned"
+ echo
+ echo "# Performance testing for aligned alloc API"
+ echo "$0 aligned"
+ echo
+ exit 0
+}
+
+function validate_passed_args()
+{
+ VALID_ARGS=`modinfo $DRIVER | awk '/parm:/ {print $2}' | sed 's/:.*//'`
+
+ #
+ # Something has been passed, check it.
+ #
+ for passed_arg in $@; do
+ key=${passed_arg//=*/}
+ valid=0
+
+ for valid_arg in $VALID_ARGS; do
+ if [[ $key = $valid_arg ]]; then
+ valid=1
+ break
+ fi
+ done
+
+ if [[ $valid -ne 1 ]]; then
+ echo "Error: key is not correct: ${key}"
+ exit $exitcode
+ fi
+ done
+}
+
+function run_manual_check()
+{
+ #
+ # Validate passed parameters. If there is wrong one,
+ # the script exists and does not execute further.
+ #
+ validate_passed_args $@
+
+ echo "Run the test with following parameters: $@"
+ insmod $DRIVER $@ > /dev/null 2>&1
+}
+
+function run_test()
+{
+ if [ $# -eq 0 ]; then
+ usage
+ else
+ if [[ "$1" = "smoke" ]]; then
+ run_smoke_check
+ elif [[ "$1" = "nonaligned" ]]; then
+ run_nonaligned_check
+ elif [[ "$1" = "aligned" ]]; then
+ run_aligned_check
+ else
+ run_manual_check $@
+ fi
+ fi
+
+ check_test_failed_prefix
+
+ echo "Done."
+ echo "Check the kernel ring buffer to see the summary."
+}
+
+check_test_requirements
+run_test $@
+
+exit 0
diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c
index 852e7281026e..717539eddf98 100644
--- a/tools/testing/selftests/mm/uffd-common.c
+++ b/tools/testing/selftests/mm/uffd-common.c
@@ -18,7 +18,7 @@ bool test_uffdio_wp = true;
unsigned long long *count_verify;
uffd_test_ops_t *uffd_test_ops;
uffd_test_case_ops_t *uffd_test_case_ops;
-pthread_barrier_t ready_for_fork;
+atomic_bool ready_for_fork;
static int uffd_mem_fd_create(off_t mem_size, bool hugetlb)
{
@@ -519,8 +519,7 @@ void *uffd_poll_thread(void *arg)
pollfd[1].fd = pipefd[cpu*2];
pollfd[1].events = POLLIN;
- /* Ready for parent thread to fork */
- pthread_barrier_wait(&ready_for_fork);
+ ready_for_fork = true;
for (;;) {
ret = poll(pollfd, 2, -1);
diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h
index 3e6228d8e0dc..a70ae10b5f62 100644
--- a/tools/testing/selftests/mm/uffd-common.h
+++ b/tools/testing/selftests/mm/uffd-common.h
@@ -33,6 +33,7 @@
#include <inttypes.h>
#include <stdint.h>
#include <sys/random.h>
+#include <stdatomic.h>
#include "../kselftest.h"
#include "vm_util.h"
@@ -104,7 +105,7 @@ extern bool map_shared;
extern bool test_uffdio_wp;
extern unsigned long long *count_verify;
extern volatile bool test_uffdio_copy_eexist;
-extern pthread_barrier_t ready_for_fork;
+extern atomic_bool ready_for_fork;
extern uffd_test_ops_t anon_uffd_test_ops;
extern uffd_test_ops_t shmem_uffd_test_ops;
diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c
index c8a3b1c7edff..a2e71b1636e7 100644
--- a/tools/testing/selftests/mm/uffd-unit-tests.c
+++ b/tools/testing/selftests/mm/uffd-unit-tests.c
@@ -241,8 +241,7 @@ static void *fork_event_consumer(void *data)
fork_event_args *args = data;
struct uffd_msg msg = { 0 };
- /* Ready for parent thread to fork */
- pthread_barrier_wait(&ready_for_fork);
+ ready_for_fork = true;
/* Read until a full msg received */
while (uffd_read_msg(args->parent_uffd, &msg));
@@ -311,12 +310,11 @@ static int pagemap_test_fork(int uffd, bool with_event, bool test_pin)
/* Prepare a thread to resolve EVENT_FORK */
if (with_event) {
- pthread_barrier_init(&ready_for_fork, NULL, 2);
+ ready_for_fork = false;
if (pthread_create(&thread, NULL, fork_event_consumer, &args))
err("pthread_create()");
- /* Wait for child thread to start before forking */
- pthread_barrier_wait(&ready_for_fork);
- pthread_barrier_destroy(&ready_for_fork);
+ while (!ready_for_fork)
+ ; /* Wait for the poll_thread to start executing before forking */
}
child = fork();
@@ -781,7 +779,7 @@ static void uffd_sigbus_test_common(bool wp)
char c;
struct uffd_args args = { 0 };
- pthread_barrier_init(&ready_for_fork, NULL, 2);
+ ready_for_fork = false;
fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK);
@@ -798,9 +796,8 @@ static void uffd_sigbus_test_common(bool wp)
if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args))
err("uffd_poll_thread create");
- /* Wait for child thread to start before forking */
- pthread_barrier_wait(&ready_for_fork);
- pthread_barrier_destroy(&ready_for_fork);
+ while (!ready_for_fork)
+ ; /* Wait for the poll_thread to start executing before forking */
pid = fork();
if (pid < 0)
@@ -841,7 +838,7 @@ static void uffd_events_test_common(bool wp)
char c;
struct uffd_args args = { 0 };
- pthread_barrier_init(&ready_for_fork, NULL, 2);
+ ready_for_fork = false;
fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK);
if (uffd_register(uffd, area_dst, nr_pages * page_size,
@@ -852,9 +849,8 @@ static void uffd_events_test_common(bool wp)
if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args))
err("uffd_poll_thread create");
- /* Wait for child thread to start before forking */
- pthread_barrier_wait(&ready_for_fork);
- pthread_barrier_destroy(&ready_for_fork);
+ while (!ready_for_fork)
+ ; /* Wait for the poll_thread to start executing before forking */
pid = fork();
if (pid < 0)
diff --git a/tools/testing/selftests/mount_setattr/mount_setattr_test.c b/tools/testing/selftests/mount_setattr/mount_setattr_test.c
index c6a8c732b802..68801e1a9ec2 100644
--- a/tools/testing/selftests/mount_setattr/mount_setattr_test.c
+++ b/tools/testing/selftests/mount_setattr/mount_setattr_test.c
@@ -1414,6 +1414,13 @@ TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/b", 0, 0, 0), 0);
ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
+ ASSERT_EQ(mount("testing", "/mnt/A", "ramfs", MS_NOATIME | MS_NODEV,
+ "size=100000,mode=700"), 0);
+
+ ASSERT_EQ(mkdir("/mnt/A/AA", 0777), 0);
+
+ ASSERT_EQ(mount("/tmp", "/mnt/A/AA", NULL, MS_BIND | MS_REC, NULL), 0);
+
open_tree_fd = sys_open_tree(-EBADF, "/mnt/A",
AT_RECURSIVE |
AT_EMPTY_PATH |
@@ -1433,6 +1440,8 @@ TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
ASSERT_EQ(expected_uid_gid(-EBADF, "/tmp/B/BB/b", 0, 0, 0), 0);
ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/b", 0, 0, 0), 0);
ASSERT_EQ(expected_uid_gid(open_tree_fd, "B/BB/b", 0, 0, 0), 0);
+
+ (void)umount2("/mnt/A", MNT_DETACH);
}
TEST_F(mount_setattr, mount_attr_nosymfollow)
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 217d8b7a7365..28a715a8ef2b 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -2,6 +2,7 @@
bind_bhash
bind_timewait
bind_wildcard
+busy_poller
cmsg_sender
diag_uid
epoll_busy_poll
@@ -18,7 +19,7 @@ ipv6_flowlabel_mgr
log.txt
msg_oob
msg_zerocopy
-ncdevmem
+netlink-dumps
nettest
psock_fanout
psock_snd
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 26a4883a65c9..3d487b03c4a0 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -78,6 +78,7 @@ TEST_PROGS += test_vxlan_vnifiltering.sh
TEST_GEN_FILES += io_uring_zerocopy_tx
TEST_PROGS += io_uring_zerocopy_tx.sh
TEST_GEN_FILES += bind_bhash
+TEST_GEN_PROGS += netlink-dumps
TEST_GEN_PROGS += sk_bind_sendto_listen
TEST_GEN_PROGS += sk_connect_zero_addr
TEST_GEN_PROGS += sk_so_peek_off
@@ -92,13 +93,15 @@ TEST_PROGS += test_vxlan_mdb.sh
TEST_PROGS += test_bridge_neigh_suppress.sh
TEST_PROGS += test_vxlan_nolocalbypass.sh
TEST_PROGS += test_bridge_backup_port.sh
-TEST_PROGS += fdb_flush.sh
+TEST_PROGS += fdb_flush.sh fdb_notify.sh
TEST_PROGS += fq_band_pktlimit.sh
TEST_PROGS += vlan_hw_filter.sh
TEST_PROGS += bpf_offload.py
+TEST_PROGS += ipv6_route_update_soft_lockup.sh
+TEST_PROGS += busy_poll_test.sh
# YNL files, must be before "include ..lib.mk"
-YNL_GEN_FILES := ncdevmem
+YNL_GEN_FILES := busy_poller
TEST_GEN_FILES += $(YNL_GEN_FILES)
TEST_FILES := settings
diff --git a/tools/testing/selftests/net/busy_poll_test.sh b/tools/testing/selftests/net/busy_poll_test.sh
new file mode 100755
index 000000000000..7db292ec4884
--- /dev/null
+++ b/tools/testing/selftests/net/busy_poll_test.sh
@@ -0,0 +1,165 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+source net_helper.sh
+
+NSIM_SV_ID=$((256 + RANDOM % 256))
+NSIM_SV_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_SV_ID
+NSIM_CL_ID=$((512 + RANDOM % 256))
+NSIM_CL_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_CL_ID
+
+NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device
+NSIM_DEV_SYS_DEL=/sys/bus/netdevsim/del_device
+NSIM_DEV_SYS_LINK=/sys/bus/netdevsim/link_device
+NSIM_DEV_SYS_UNLINK=/sys/bus/netdevsim/unlink_device
+
+SERVER_IP=192.168.1.1
+CLIENT_IP=192.168.1.2
+SERVER_PORT=48675
+
+# busy poll config
+MAX_EVENTS=8
+BUSY_POLL_USECS=0
+BUSY_POLL_BUDGET=16
+PREFER_BUSY_POLL=1
+
+# IRQ deferral config
+NAPI_DEFER_HARD_IRQS=100
+GRO_FLUSH_TIMEOUT=50000
+SUSPEND_TIMEOUT=20000000
+
+setup_ns()
+{
+ set -e
+ ip netns add nssv
+ ip netns add nscl
+
+ NSIM_SV_NAME=$(find $NSIM_SV_SYS/net -maxdepth 1 -type d ! \
+ -path $NSIM_SV_SYS/net -exec basename {} \;)
+ NSIM_CL_NAME=$(find $NSIM_CL_SYS/net -maxdepth 1 -type d ! \
+ -path $NSIM_CL_SYS/net -exec basename {} \;)
+
+ # ensure the server has 1 queue
+ ethtool -L $NSIM_SV_NAME combined 1 2>/dev/null
+
+ ip link set $NSIM_SV_NAME netns nssv
+ ip link set $NSIM_CL_NAME netns nscl
+
+ ip netns exec nssv ip addr add "${SERVER_IP}/24" dev $NSIM_SV_NAME
+ ip netns exec nscl ip addr add "${CLIENT_IP}/24" dev $NSIM_CL_NAME
+
+ ip netns exec nssv ip link set dev $NSIM_SV_NAME up
+ ip netns exec nscl ip link set dev $NSIM_CL_NAME up
+
+ set +e
+}
+
+cleanup_ns()
+{
+ ip netns del nscl
+ ip netns del nssv
+}
+
+test_busypoll()
+{
+ suspend_value=${1:-0}
+ tmp_file=$(mktemp)
+ out_file=$(mktemp)
+
+ # fill a test file with random data
+ dd if=/dev/urandom of=${tmp_file} bs=1M count=1 2> /dev/null
+
+ timeout -k 1s 30s ip netns exec nssv ./busy_poller \
+ -p${SERVER_PORT} \
+ -b${SERVER_IP} \
+ -m${MAX_EVENTS} \
+ -u${BUSY_POLL_USECS} \
+ -P${PREFER_BUSY_POLL} \
+ -g${BUSY_POLL_BUDGET} \
+ -i${NSIM_SV_IFIDX} \
+ -s${suspend_value} \
+ -o${out_file}&
+
+ wait_local_port_listen nssv ${SERVER_PORT} tcp
+
+ ip netns exec nscl socat -u $tmp_file TCP:${SERVER_IP}:${SERVER_PORT}
+
+ wait
+
+ tmp_file_md5sum=$(md5sum $tmp_file | cut -f1 -d' ')
+ out_file_md5sum=$(md5sum $out_file | cut -f1 -d' ')
+
+ if [ "$tmp_file_md5sum" = "$out_file_md5sum" ]; then
+ res=0
+ else
+ echo "md5sum mismatch"
+ echo "input file md5sum: ${tmp_file_md5sum}";
+ echo "output file md5sum: ${out_file_md5sum}";
+ res=1
+ fi
+
+ rm $out_file $tmp_file
+
+ return $res
+}
+
+test_busypoll_with_suspend()
+{
+ test_busypoll ${SUSPEND_TIMEOUT}
+
+ return $?
+}
+
+###
+### Code start
+###
+
+modprobe netdevsim
+
+# linking
+
+echo $NSIM_SV_ID > $NSIM_DEV_SYS_NEW
+echo $NSIM_CL_ID > $NSIM_DEV_SYS_NEW
+udevadm settle
+
+setup_ns
+
+NSIM_SV_FD=$((256 + RANDOM % 256))
+exec {NSIM_SV_FD}</var/run/netns/nssv
+NSIM_SV_IFIDX=$(ip netns exec nssv cat /sys/class/net/$NSIM_SV_NAME/ifindex)
+
+NSIM_CL_FD=$((256 + RANDOM % 256))
+exec {NSIM_CL_FD}</var/run/netns/nscl
+NSIM_CL_IFIDX=$(ip netns exec nscl cat /sys/class/net/$NSIM_CL_NAME/ifindex)
+
+echo "$NSIM_SV_FD:$NSIM_SV_IFIDX $NSIM_CL_FD:$NSIM_CL_IFIDX" > \
+ $NSIM_DEV_SYS_LINK
+
+if [ $? -ne 0 ]; then
+ echo "linking netdevsim1 with netdevsim2 should succeed"
+ cleanup_ns
+ exit 1
+fi
+
+test_busypoll
+if [ $? -ne 0 ]; then
+ echo "test_busypoll failed"
+ cleanup_ns
+ exit 1
+fi
+
+test_busypoll_with_suspend
+if [ $? -ne 0 ]; then
+ echo "test_busypoll_with_suspend failed"
+ cleanup_ns
+ exit 1
+fi
+
+echo "$NSIM_SV_FD:$NSIM_SV_IFIDX" > $NSIM_DEV_SYS_UNLINK
+
+echo $NSIM_CL_ID > $NSIM_DEV_SYS_DEL
+
+cleanup_ns
+
+modprobe -r netdevsim
+
+exit 0
diff --git a/tools/testing/selftests/net/busy_poller.c b/tools/testing/selftests/net/busy_poller.c
new file mode 100644
index 000000000000..99b0e8c17fca
--- /dev/null
+++ b/tools/testing/selftests/net/busy_poller.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ynl.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <linux/genetlink.h>
+#include <linux/netlink.h>
+
+#include "netdev-user.h"
+
+/* The below ifdef blob is required because:
+ *
+ * - sys/epoll.h does not (yet) have the ioctl definitions included. So,
+ * systems with older glibcs will not have them available. However,
+ * sys/epoll.h does include the type definition for epoll_data, which is
+ * needed by the user program (e.g. epoll_event.data.fd)
+ *
+ * - linux/eventpoll.h does not define the epoll_data type, it is simply an
+ * opaque __u64. It does, however, include the ioctl definition.
+ *
+ * Including both headers is impossible (types would be redefined), so I've
+ * opted instead to take sys/epoll.h, and include the blob below.
+ *
+ * Someday, when glibc is globally up to date, the blob below can be removed.
+ */
+#if !defined(EPOLL_IOC_TYPE)
+struct epoll_params {
+ uint32_t busy_poll_usecs;
+ uint16_t busy_poll_budget;
+ uint8_t prefer_busy_poll;
+
+ /* pad the struct to a multiple of 64bits */
+ uint8_t __pad;
+};
+
+#define EPOLL_IOC_TYPE 0x8A
+#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
+#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
+#endif
+
+static uint32_t cfg_port = 8000;
+static struct in_addr cfg_bind_addr = { .s_addr = INADDR_ANY };
+static char *cfg_outfile;
+static int cfg_max_events = 8;
+static int cfg_ifindex;
+
+/* busy poll params */
+static uint32_t cfg_busy_poll_usecs;
+static uint32_t cfg_busy_poll_budget;
+static uint32_t cfg_prefer_busy_poll;
+
+/* IRQ params */
+static uint32_t cfg_defer_hard_irqs;
+static uint64_t cfg_gro_flush_timeout;
+static uint64_t cfg_irq_suspend_timeout;
+
+static void usage(const char *filepath)
+{
+ error(1, 0,
+ "Usage: %s -p<port> -b<addr> -m<max_events> -u<busy_poll_usecs> -P<prefer_busy_poll> -g<busy_poll_budget> -o<outfile> -d<defer_hard_irqs> -r<gro_flush_timeout> -s<irq_suspend_timeout> -i<ifindex>",
+ filepath);
+}
+
+static void parse_opts(int argc, char **argv)
+{
+ int ret;
+ int c;
+
+ if (argc <= 1)
+ usage(argv[0]);
+
+ while ((c = getopt(argc, argv, "p:m:b:u:P:g:o:d:r:s:i:")) != -1) {
+ switch (c) {
+ case 'u':
+ cfg_busy_poll_usecs = strtoul(optarg, NULL, 0);
+ if (cfg_busy_poll_usecs == ULONG_MAX ||
+ cfg_busy_poll_usecs > UINT32_MAX)
+ error(1, ERANGE, "busy_poll_usecs too large");
+ break;
+ case 'P':
+ cfg_prefer_busy_poll = strtoul(optarg, NULL, 0);
+ if (cfg_prefer_busy_poll == ULONG_MAX ||
+ cfg_prefer_busy_poll > 1)
+ error(1, ERANGE,
+ "prefer busy poll should be 0 or 1");
+ break;
+ case 'g':
+ cfg_busy_poll_budget = strtoul(optarg, NULL, 0);
+ if (cfg_busy_poll_budget == ULONG_MAX ||
+ cfg_busy_poll_budget > UINT16_MAX)
+ error(1, ERANGE,
+ "busy poll budget must be [0, UINT16_MAX]");
+ break;
+ case 'p':
+ cfg_port = strtoul(optarg, NULL, 0);
+ if (cfg_port > UINT16_MAX)
+ error(1, ERANGE, "port must be <= 65535");
+ break;
+ case 'b':
+ ret = inet_aton(optarg, &cfg_bind_addr);
+ if (ret == 0)
+ error(1, errno,
+ "bind address %s invalid", optarg);
+ break;
+ case 'o':
+ cfg_outfile = strdup(optarg);
+ if (!cfg_outfile)
+ error(1, 0, "outfile invalid");
+ break;
+ case 'm':
+ cfg_max_events = strtol(optarg, NULL, 0);
+
+ if (cfg_max_events == LONG_MIN ||
+ cfg_max_events == LONG_MAX ||
+ cfg_max_events <= 0)
+ error(1, ERANGE,
+ "max events must be > 0 and < LONG_MAX");
+ break;
+ case 'd':
+ cfg_defer_hard_irqs = strtoul(optarg, NULL, 0);
+
+ if (cfg_defer_hard_irqs == ULONG_MAX ||
+ cfg_defer_hard_irqs > INT32_MAX)
+ error(1, ERANGE,
+ "defer_hard_irqs must be <= INT32_MAX");
+ break;
+ case 'r':
+ cfg_gro_flush_timeout = strtoull(optarg, NULL, 0);
+
+ if (cfg_gro_flush_timeout == ULLONG_MAX)
+ error(1, ERANGE,
+ "gro_flush_timeout must be < ULLONG_MAX");
+ break;
+ case 's':
+ cfg_irq_suspend_timeout = strtoull(optarg, NULL, 0);
+
+ if (cfg_irq_suspend_timeout == ULLONG_MAX)
+ error(1, ERANGE,
+ "irq_suspend_timeout must be < ULLONG_MAX");
+ break;
+ case 'i':
+ cfg_ifindex = strtoul(optarg, NULL, 0);
+ if (cfg_ifindex == ULONG_MAX)
+ error(1, ERANGE,
+ "ifindex must be < ULONG_MAX");
+ break;
+ }
+ }
+
+ if (!cfg_ifindex)
+ usage(argv[0]);
+
+ if (optind != argc)
+ usage(argv[0]);
+}
+
+static void epoll_ctl_add(int epfd, int fd, uint32_t events)
+{
+ struct epoll_event ev;
+
+ ev.events = events;
+ ev.data.fd = fd;
+ if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
+ error(1, errno, "epoll_ctl add fd: %d", fd);
+}
+
+static void setnonblock(int sockfd)
+{
+ int flags;
+
+ flags = fcntl(sockfd, F_GETFL, 0);
+
+ if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
+ error(1, errno, "unable to set socket to nonblocking mode");
+}
+
+static void write_chunk(int fd, char *buf, ssize_t buflen)
+{
+ ssize_t remaining = buflen;
+ char *buf_offset = buf;
+ ssize_t writelen = 0;
+ ssize_t write_result;
+
+ while (writelen < buflen) {
+ write_result = write(fd, buf_offset, remaining);
+ if (write_result == -1)
+ error(1, errno, "unable to write data to outfile");
+
+ writelen += write_result;
+ remaining -= write_result;
+ buf_offset += write_result;
+ }
+}
+
+static void setup_queue(void)
+{
+ struct netdev_napi_get_list *napi_list = NULL;
+ struct netdev_napi_get_req_dump *req = NULL;
+ struct netdev_napi_set_req *set_req = NULL;
+ struct ynl_sock *ys;
+ struct ynl_error yerr;
+ uint32_t napi_id;
+
+ ys = ynl_sock_create(&ynl_netdev_family, &yerr);
+ if (!ys)
+ error(1, 0, "YNL: %s", yerr.msg);
+
+ req = netdev_napi_get_req_dump_alloc();
+ netdev_napi_get_req_dump_set_ifindex(req, cfg_ifindex);
+ napi_list = netdev_napi_get_dump(ys, req);
+
+ /* assume there is 1 NAPI configured and take the first */
+ if (napi_list->obj._present.id)
+ napi_id = napi_list->obj.id;
+ else
+ error(1, 0, "napi ID not present?");
+
+ set_req = netdev_napi_set_req_alloc();
+ netdev_napi_set_req_set_id(set_req, napi_id);
+ netdev_napi_set_req_set_defer_hard_irqs(set_req, cfg_defer_hard_irqs);
+ netdev_napi_set_req_set_gro_flush_timeout(set_req,
+ cfg_gro_flush_timeout);
+ netdev_napi_set_req_set_irq_suspend_timeout(set_req,
+ cfg_irq_suspend_timeout);
+
+ if (netdev_napi_set(ys, set_req))
+ error(1, 0, "can't set NAPI params: %s\n", yerr.msg);
+
+ netdev_napi_get_list_free(napi_list);
+ netdev_napi_get_req_dump_free(req);
+ netdev_napi_set_req_free(set_req);
+ ynl_sock_destroy(ys);
+}
+
+static void run_poller(void)
+{
+ struct epoll_event events[cfg_max_events];
+ struct epoll_params epoll_params = {0};
+ struct sockaddr_in server_addr;
+ int i, epfd, nfds;
+ ssize_t readlen;
+ int outfile_fd;
+ char buf[1024];
+ int sockfd;
+ int conn;
+ int val;
+
+ outfile_fd = open(cfg_outfile, O_WRONLY | O_CREAT, 0644);
+ if (outfile_fd == -1)
+ error(1, errno, "unable to open outfile: %s", cfg_outfile);
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd == -1)
+ error(1, errno, "unable to create listen socket");
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(cfg_port);
+ server_addr.sin_addr = cfg_bind_addr;
+
+ /* these values are range checked during parse_opts, so casting is safe
+ * here
+ */
+ epoll_params.busy_poll_usecs = cfg_busy_poll_usecs;
+ epoll_params.busy_poll_budget = (uint16_t)cfg_busy_poll_budget;
+ epoll_params.prefer_busy_poll = (uint8_t)cfg_prefer_busy_poll;
+ epoll_params.__pad = 0;
+
+ val = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
+ error(1, errno, "poller setsockopt reuseaddr");
+
+ setnonblock(sockfd);
+
+ if (bind(sockfd, (struct sockaddr *)&server_addr,
+ sizeof(struct sockaddr_in)))
+ error(0, errno, "poller bind to port: %d\n", cfg_port);
+
+ if (listen(sockfd, 1))
+ error(1, errno, "poller listen");
+
+ epfd = epoll_create1(0);
+ if (ioctl(epfd, EPIOCSPARAMS, &epoll_params) == -1)
+ error(1, errno, "unable to set busy poll params");
+
+ epoll_ctl_add(epfd, sockfd, EPOLLIN | EPOLLOUT | EPOLLET);
+
+ for (;;) {
+ nfds = epoll_wait(epfd, events, cfg_max_events, -1);
+ for (i = 0; i < nfds; i++) {
+ if (events[i].data.fd == sockfd) {
+ conn = accept(sockfd, NULL, NULL);
+ if (conn == -1)
+ error(1, errno,
+ "accepting incoming connection failed");
+
+ setnonblock(conn);
+ epoll_ctl_add(epfd, conn,
+ EPOLLIN | EPOLLET | EPOLLRDHUP |
+ EPOLLHUP);
+ } else if (events[i].events & EPOLLIN) {
+ for (;;) {
+ readlen = read(events[i].data.fd, buf,
+ sizeof(buf));
+ if (readlen > 0)
+ write_chunk(outfile_fd, buf,
+ readlen);
+ else
+ break;
+ }
+ } else {
+ /* spurious event ? */
+ }
+ if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {
+ epoll_ctl(epfd, EPOLL_CTL_DEL,
+ events[i].data.fd, NULL);
+ close(events[i].data.fd);
+ close(outfile_fd);
+ return;
+ }
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ parse_opts(argc, argv);
+ setup_queue();
+ run_poller();
+ return 0;
+}
diff --git a/tools/testing/selftests/net/drop_monitor_tests.sh b/tools/testing/selftests/net/drop_monitor_tests.sh
index 7c4818c971fc..507d0a82f5f0 100755
--- a/tools/testing/selftests/net/drop_monitor_tests.sh
+++ b/tools/testing/selftests/net/drop_monitor_tests.sh
@@ -77,7 +77,7 @@ sw_drops_test()
rm ${dir}/packets.pcap
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
timeout 5 dwdump -o sw -w ${dir}/packets.pcap
(( $(tshark -r ${dir}/packets.pcap \
-Y 'ip.dst == 192.0.2.10' 2> /dev/null | wc -l) == 0))
diff --git a/tools/testing/selftests/net/fdb_notify.sh b/tools/testing/selftests/net/fdb_notify.sh
new file mode 100755
index 000000000000..c03151e7791c
--- /dev/null
+++ b/tools/testing/selftests/net/fdb_notify.sh
@@ -0,0 +1,96 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source lib.sh
+
+ALL_TESTS="
+ test_dup_bridge
+ test_dup_vxlan_self
+ test_dup_vxlan_master
+ test_dup_macvlan_self
+ test_dup_macvlan_master
+"
+
+do_test_dup()
+{
+ local op=$1; shift
+ local what=$1; shift
+ local tmpf
+
+ RET=0
+
+ tmpf=$(mktemp)
+ defer rm "$tmpf"
+
+ defer_scope_push
+ bridge monitor fdb &> "$tmpf" &
+ defer kill_process $!
+
+ sleep 0.5
+ bridge fdb "$op" 00:11:22:33:44:55 vlan 1 "$@"
+ sleep 0.5
+ defer_scope_pop
+
+ local count=$(grep -c -e 00:11:22:33:44:55 $tmpf)
+ ((count == 1))
+ check_err $? "Got $count notifications, expected 1"
+
+ log_test "$what $op: Duplicate notifications"
+}
+
+test_dup_bridge()
+{
+ ip_link_add br up type bridge vlan_filtering 1
+ do_test_dup add "bridge" dev br self
+ do_test_dup del "bridge" dev br self
+}
+
+test_dup_vxlan_self()
+{
+ ip_link_add br up type bridge vlan_filtering 1
+ ip_link_add vx up type vxlan id 2000 dstport 4789
+ ip_link_master vx br
+
+ do_test_dup add "vxlan" dev vx self dst 192.0.2.1
+ do_test_dup del "vxlan" dev vx self dst 192.0.2.1
+}
+
+test_dup_vxlan_master()
+{
+ ip_link_add br up type bridge vlan_filtering 1
+ ip_link_add vx up type vxlan id 2000 dstport 4789
+ ip_link_master vx br
+
+ do_test_dup add "vxlan master" dev vx master
+ do_test_dup del "vxlan master" dev vx master
+}
+
+test_dup_macvlan_self()
+{
+ ip_link_add dd up type dummy
+ ip_link_add mv up link dd type macvlan mode passthru
+
+ do_test_dup add "macvlan self" dev mv self
+ do_test_dup del "macvlan self" dev mv self
+}
+
+test_dup_macvlan_master()
+{
+ ip_link_add br up type bridge vlan_filtering 1
+ ip_link_add dd up type dummy
+ ip_link_add mv up link dd type macvlan mode passthru
+ ip_link_master mv br
+
+ do_test_dup add "macvlan master" dev mv self
+ do_test_dup del "macvlan master" dev mv self
+}
+
+cleanup()
+{
+ defer_scopes_cleanup
+}
+
+trap cleanup EXIT
+tests_run
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh
index 5f3c28fc8624..3ea6f886a210 100755
--- a/tools/testing/selftests/net/fib_tests.sh
+++ b/tools/testing/selftests/net/fib_tests.sh
@@ -689,7 +689,7 @@ fib6_notify_test()
log_test $ret 0 "ipv6 route add notify"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
#rm errors.txt
@@ -736,7 +736,7 @@ fib_notify_test()
log_test $ret 0 "ipv4 route add notify"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
rm errors.txt
@@ -2328,7 +2328,7 @@ ipv4_mangle_test()
$IP route del table 123 172.16.101.0/24 dev veth1
$IP rule del pref 100
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
rm $tmp_file
route_cleanup
@@ -2386,7 +2386,7 @@ ipv6_mangle_test()
$IP -6 route del table 123 2001:db8:101::/64 dev veth1
$IP -6 rule del pref 100
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
rm $tmp_file
route_cleanup
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
index 224346426ef2..7d885cff8d79 100644
--- a/tools/testing/selftests/net/forwarding/Makefile
+++ b/tools/testing/selftests/net/forwarding/Makefile
@@ -126,6 +126,7 @@ TEST_FILES := devlink_lib.sh \
tc_common.sh
TEST_INCLUDES := \
- ../lib.sh
+ ../lib.sh \
+ $(wildcard ../lib/sh/*.sh)
include ../../lib.mk
diff --git a/tools/testing/selftests/net/forwarding/devlink_lib.sh b/tools/testing/selftests/net/forwarding/devlink_lib.sh
index 62a05bca1e82..18afa89ebbcc 100644
--- a/tools/testing/selftests/net/forwarding/devlink_lib.sh
+++ b/tools/testing/selftests/net/forwarding/devlink_lib.sh
@@ -501,7 +501,7 @@ devlink_trap_drop_cleanup()
local pref=$1; shift
local handle=$1; shift
- kill $mz_pid && wait $mz_pid &> /dev/null
+ kill_process $mz_pid
tc filter del dev $dev egress protocol $proto pref $pref handle $handle flower
}
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_flat.sh b/tools/testing/selftests/net/forwarding/ip6gre_flat.sh
index 96c97064f2d3..becc7c3fc809 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_flat.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_flat.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_flat
gre_mtu_change
+ gre_flat_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change
}
+gre_flat_remote_change()
+{
+ flat_remote_change
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 (new remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 (new remote)"
+
+ flat_remote_restore
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 (old remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_flat_key.sh b/tools/testing/selftests/net/forwarding/ip6gre_flat_key.sh
index ff9fb0db9bd1..e5335116a2fd 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_flat_key.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_flat_key.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_flat
gre_mtu_change
+ gre_flat_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change
}
+gre_flat_remote_change()
+{
+ flat_remote_change
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 with key (new remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 with key (new remote)"
+
+ flat_remote_restore
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 with key (old remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 with key (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_flat_keys.sh b/tools/testing/selftests/net/forwarding/ip6gre_flat_keys.sh
index 12c138785242..7e0cbfdefab0 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_flat_keys.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_flat_keys.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_flat
gre_mtu_change
+ gre_flat_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change gre
}
+gre_flat_remote_change()
+{
+ flat_remote_change
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 with ikey/okey (new remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 with ikey/okey (new remote)"
+
+ flat_remote_restore
+
+ test_traffic_ip4ip6 "GRE flat IPv4-in-IPv6 with ikey/okey (old remote)"
+ test_traffic_ip6ip6 "GRE flat IPv6-in-IPv6 with ikey/okey (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_hier.sh b/tools/testing/selftests/net/forwarding/ip6gre_hier.sh
index 83b55c30a5c3..e0844495f3d1 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_hier.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_hier.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_hier
gre_mtu_change
+ gre_hier_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change gre
}
+gre_hier_remote_change()
+{
+ hier_remote_change
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 (new remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 (new remote)"
+
+ hier_remote_restore
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 (old remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_hier_key.sh b/tools/testing/selftests/net/forwarding/ip6gre_hier_key.sh
index 256607916d92..741bc9c928eb 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_hier_key.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_hier_key.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_hier
gre_mtu_change
+ gre_hier_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change gre
}
+gre_hier_remote_change()
+{
+ hier_remote_change
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 with key (new remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 with key (new remote)"
+
+ hier_remote_restore
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 with key (old remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 with key (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_hier_keys.sh b/tools/testing/selftests/net/forwarding/ip6gre_hier_keys.sh
index ad1bcd6334a8..ad9eab4b1367 100755
--- a/tools/testing/selftests/net/forwarding/ip6gre_hier_keys.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_hier_keys.sh
@@ -8,6 +8,7 @@
ALL_TESTS="
gre_hier
gre_mtu_change
+ gre_hier_remote_change
"
NUM_NETIFS=6
@@ -44,6 +45,19 @@ gre_mtu_change()
test_mtu_change gre
}
+gre_hier_remote_change()
+{
+ hier_remote_change
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 with ikey/okey (new remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 with ikey/okey (new remote)"
+
+ hier_remote_restore
+
+ test_traffic_ip4ip6 "GRE hierarchical IPv4-in-IPv6 with ikey/okey (old remote)"
+ test_traffic_ip6ip6 "GRE hierarchical IPv6-in-IPv6 with ikey/okey (old remote)"
+}
+
cleanup()
{
pre_cleanup
diff --git a/tools/testing/selftests/net/forwarding/ip6gre_lib.sh b/tools/testing/selftests/net/forwarding/ip6gre_lib.sh
index 24f4ab328bd2..2d91281dc5b7 100644
--- a/tools/testing/selftests/net/forwarding/ip6gre_lib.sh
+++ b/tools/testing/selftests/net/forwarding/ip6gre_lib.sh
@@ -436,3 +436,83 @@ test_mtu_change()
check_err $?
log_test "ping GRE IPv6, packet size 1800 after MTU change"
}
+
+topo_flat_remote_change()
+{
+ local old1=$1; shift
+ local new1=$1; shift
+ local old2=$1; shift
+ local new2=$1; shift
+
+ ip link set dev g1a type ip6gre local $new1 remote $new2
+ __addr_add_del g1a add "$new1/128"
+ __addr_add_del g1a del "$old1/128"
+ ip -6 route add $new2/128 via 2001:db8:10::2
+ ip -6 route del $old2/128
+
+ ip link set dev g2a type ip6gre local $new2 remote $new1
+ __addr_add_del g2a add "$new2/128"
+ __addr_add_del g2a del "$old2/128"
+ ip -6 route add vrf v$ol2 $new1/128 via 2001:db8:10::1
+ ip -6 route del vrf v$ol2 $old1/128
+}
+
+flat_remote_change()
+{
+ local old1=2001:db8:3::1
+ local new1=2001:db8:3::10
+ local old2=2001:db8:3::2
+ local new2=2001:db8:3::20
+
+ topo_flat_remote_change $old1 $new1 $old2 $new2
+}
+
+flat_remote_restore()
+{
+ local old1=2001:db8:3::10
+ local new1=2001:db8:3::1
+ local old2=2001:db8:3::20
+ local new2=2001:db8:3::2
+
+ topo_flat_remote_change $old1 $new1 $old2 $new2
+}
+
+topo_hier_remote_change()
+{
+ local old1=$1; shift
+ local new1=$1; shift
+ local old2=$1; shift
+ local new2=$1; shift
+
+ __addr_add_del dummy1 del "$old1/64"
+ __addr_add_del dummy1 add "$new1/64"
+ ip link set dev g1a type ip6gre local $new1 remote $new2
+ ip -6 route add vrf v$ul1 $new2/128 via 2001:db8:10::2
+ ip -6 route del vrf v$ul1 $old2/128
+
+ __addr_add_del dummy2 del "$old2/64"
+ __addr_add_del dummy2 add "$new2/64"
+ ip link set dev g2a type ip6gre local $new2 remote $new1
+ ip -6 route add vrf v$ul2 $new1/128 via 2001:db8:10::1
+ ip -6 route del vrf v$ul2 $old1/128
+}
+
+hier_remote_change()
+{
+ local old1=2001:db8:3::1
+ local new1=2001:db8:3::10
+ local old2=2001:db8:3::2
+ local new2=2001:db8:3::20
+
+ topo_hier_remote_change $old1 $new1 $old2 $new2
+}
+
+hier_remote_restore()
+{
+ local old1=2001:db8:3::10
+ local new1=2001:db8:3::1
+ local old2=2001:db8:3::20
+ local new2=2001:db8:3::2
+
+ topo_hier_remote_change $old1 $new1 $old2 $new2
+}
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index 89c25f72b10c..7337f398f9cc 100644
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -48,7 +48,6 @@ declare -A NETIFS=(
: "${WAIT_TIME:=5}"
# Whether to pause on, respectively, after a failure and before cleanup.
-: "${PAUSE_ON_FAIL:=no}"
: "${PAUSE_ON_CLEANUP:=no}"
# Whether to create virtual interfaces, and what netdevice type they should be.
@@ -446,191 +445,6 @@ done
##############################################################################
# Helpers
-# Exit status to return at the end. Set in case one of the tests fails.
-EXIT_STATUS=0
-# Per-test return value. Clear at the beginning of each test.
-RET=0
-
-ret_set_ksft_status()
-{
- local ksft_status=$1; shift
- local msg=$1; shift
-
- RET=$(ksft_status_merge $RET $ksft_status)
- if (( $? )); then
- retmsg=$msg
- fi
-}
-
-# Whether FAILs should be interpreted as XFAILs. Internal.
-FAIL_TO_XFAIL=
-
-check_err()
-{
- local err=$1
- local msg=$2
-
- if ((err)); then
- if [[ $FAIL_TO_XFAIL = yes ]]; then
- ret_set_ksft_status $ksft_xfail "$msg"
- else
- ret_set_ksft_status $ksft_fail "$msg"
- fi
- fi
-}
-
-check_fail()
-{
- local err=$1
- local msg=$2
-
- check_err $((!err)) "$msg"
-}
-
-check_err_fail()
-{
- local should_fail=$1; shift
- local err=$1; shift
- local what=$1; shift
-
- if ((should_fail)); then
- check_fail $err "$what succeeded, but should have failed"
- else
- check_err $err "$what failed"
- fi
-}
-
-xfail()
-{
- FAIL_TO_XFAIL=yes "$@"
-}
-
-xfail_on_slow()
-{
- if [[ $KSFT_MACHINE_SLOW = yes ]]; then
- FAIL_TO_XFAIL=yes "$@"
- else
- "$@"
- fi
-}
-
-omit_on_slow()
-{
- if [[ $KSFT_MACHINE_SLOW != yes ]]; then
- "$@"
- fi
-}
-
-xfail_on_veth()
-{
- local dev=$1; shift
- local kind
-
- kind=$(ip -j -d link show dev $dev |
- jq -r '.[].linkinfo.info_kind')
- if [[ $kind = veth ]]; then
- FAIL_TO_XFAIL=yes "$@"
- else
- "$@"
- fi
-}
-
-log_test_result()
-{
- local test_name=$1; shift
- local opt_str=$1; shift
- local result=$1; shift
- local retmsg=$1; shift
-
- printf "TEST: %-60s [%s]\n" "$test_name $opt_str" "$result"
- if [[ $retmsg ]]; then
- printf "\t%s\n" "$retmsg"
- fi
-}
-
-pause_on_fail()
-{
- if [[ $PAUSE_ON_FAIL == yes ]]; then
- echo "Hit enter to continue, 'q' to quit"
- read a
- [[ $a == q ]] && exit 1
- fi
-}
-
-handle_test_result_pass()
-{
- local test_name=$1; shift
- local opt_str=$1; shift
-
- log_test_result "$test_name" "$opt_str" " OK "
-}
-
-handle_test_result_fail()
-{
- local test_name=$1; shift
- local opt_str=$1; shift
-
- log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
- pause_on_fail
-}
-
-handle_test_result_xfail()
-{
- local test_name=$1; shift
- local opt_str=$1; shift
-
- log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
- pause_on_fail
-}
-
-handle_test_result_skip()
-{
- local test_name=$1; shift
- local opt_str=$1; shift
-
- log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
-}
-
-log_test()
-{
- local test_name=$1
- local opt_str=$2
-
- if [[ $# -eq 2 ]]; then
- opt_str="($opt_str)"
- fi
-
- if ((RET == ksft_pass)); then
- handle_test_result_pass "$test_name" "$opt_str"
- elif ((RET == ksft_xfail)); then
- handle_test_result_xfail "$test_name" "$opt_str"
- elif ((RET == ksft_skip)); then
- handle_test_result_skip "$test_name" "$opt_str"
- else
- handle_test_result_fail "$test_name" "$opt_str"
- fi
-
- EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
- return $RET
-}
-
-log_test_skip()
-{
- RET=$ksft_skip retmsg= log_test "$@"
-}
-
-log_test_xfail()
-{
- RET=$ksft_xfail retmsg= log_test "$@"
-}
-
-log_info()
-{
- local msg=$1
-
- echo "INFO: $msg"
-}
-
not()
{
"$@"
@@ -1398,16 +1212,6 @@ matchall_sink_create()
action drop
}
-tests_run()
-{
- local current_test
-
- for current_test in ${TESTS:-$ALL_TESTS}; do
- in_defer_scope \
- $current_test
- done
-}
-
cleanup()
{
pre_cleanup
@@ -1770,8 +1574,7 @@ stop_traffic()
{
local pid=${1-%%}; shift
- # Suppress noise from killing mausezahn.
- { kill $pid && wait $pid; } 2>/dev/null
+ kill_process "$pid"
}
declare -A cappid
diff --git a/tools/testing/selftests/net/forwarding/tc_police.sh b/tools/testing/selftests/net/forwarding/tc_police.sh
index 5103f64a71d6..509fdedfcfa1 100755
--- a/tools/testing/selftests/net/forwarding/tc_police.sh
+++ b/tools/testing/selftests/net/forwarding/tc_police.sh
@@ -148,7 +148,7 @@ police_common_test()
log_test "$test_name"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
}
@@ -198,7 +198,7 @@ police_shared_common_test()
log_test "$test_name"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
}
police_shared_test()
@@ -278,7 +278,7 @@ police_mirror_common_test()
log_test "$test_name"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
tc filter del dev $pol_if $dir protocol ip pref 1 handle 101 flower
tc filter del dev $h3 ingress protocol ip pref 1 handle 101 flower
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
@@ -320,7 +320,7 @@ police_pps_common_test()
log_test "$test_name"
- { kill %% && wait %%; } 2>/dev/null
+ kill_process %%
tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
}
diff --git a/tools/testing/selftests/net/hsr/config b/tools/testing/selftests/net/hsr/config
index 241542441c51..555a868743f0 100644
--- a/tools/testing/selftests/net/hsr/config
+++ b/tools/testing/selftests/net/hsr/config
@@ -3,3 +3,4 @@ CONFIG_NET_SCH_NETEM=m
CONFIG_HSR=y
CONFIG_VETH=y
CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=m
diff --git a/tools/testing/selftests/net/hsr/hsr_common.sh b/tools/testing/selftests/net/hsr/hsr_common.sh
index 8e97b1f2e7e5..1dc882ac1c74 100644
--- a/tools/testing/selftests/net/hsr/hsr_common.sh
+++ b/tools/testing/selftests/net/hsr/hsr_common.sh
@@ -15,7 +15,7 @@ do_ping()
{
local netns="$1"
local connect_addr="$2"
- local ping_args="-q -c 2"
+ local ping_args="-q -c 2 -i 0.1"
if is_v6 "${connect_addr}"; then
$ipv6 || return 0
@@ -36,7 +36,7 @@ do_ping_long()
{
local netns="$1"
local connect_addr="$2"
- local ping_args="-q -c 10"
+ local ping_args="-q -c 10 -i 0.1"
if is_v6 "${connect_addr}"; then
$ipv6 || return 0
diff --git a/tools/testing/selftests/net/hsr/hsr_ping.sh b/tools/testing/selftests/net/hsr/hsr_ping.sh
index f5d207fc770a..5a65f4f836be 100755
--- a/tools/testing/selftests/net/hsr/hsr_ping.sh
+++ b/tools/testing/selftests/net/hsr/hsr_ping.sh
@@ -175,6 +175,100 @@ setup_hsr_interfaces()
ip -net "$ns3" link set hsr3 up
}
+setup_vlan_interfaces() {
+ ip -net "$ns1" link add link hsr1 name hsr1.2 type vlan id 2
+ ip -net "$ns1" link add link hsr1 name hsr1.3 type vlan id 3
+ ip -net "$ns1" link add link hsr1 name hsr1.4 type vlan id 4
+ ip -net "$ns1" link add link hsr1 name hsr1.5 type vlan id 5
+
+ ip -net "$ns2" link add link hsr2 name hsr2.2 type vlan id 2
+ ip -net "$ns2" link add link hsr2 name hsr2.3 type vlan id 3
+ ip -net "$ns2" link add link hsr2 name hsr2.4 type vlan id 4
+ ip -net "$ns2" link add link hsr2 name hsr2.5 type vlan id 5
+
+ ip -net "$ns3" link add link hsr3 name hsr3.2 type vlan id 2
+ ip -net "$ns3" link add link hsr3 name hsr3.3 type vlan id 3
+ ip -net "$ns3" link add link hsr3 name hsr3.4 type vlan id 4
+ ip -net "$ns3" link add link hsr3 name hsr3.5 type vlan id 5
+
+ ip -net "$ns1" addr add 100.64.2.1/24 dev hsr1.2
+ ip -net "$ns1" addr add 100.64.3.1/24 dev hsr1.3
+ ip -net "$ns1" addr add 100.64.4.1/24 dev hsr1.4
+ ip -net "$ns1" addr add 100.64.5.1/24 dev hsr1.5
+
+ ip -net "$ns2" addr add 100.64.2.2/24 dev hsr2.2
+ ip -net "$ns2" addr add 100.64.3.2/24 dev hsr2.3
+ ip -net "$ns2" addr add 100.64.4.2/24 dev hsr2.4
+ ip -net "$ns2" addr add 100.64.5.2/24 dev hsr2.5
+
+ ip -net "$ns3" addr add 100.64.2.3/24 dev hsr3.2
+ ip -net "$ns3" addr add 100.64.3.3/24 dev hsr3.3
+ ip -net "$ns3" addr add 100.64.4.3/24 dev hsr3.4
+ ip -net "$ns3" addr add 100.64.5.3/24 dev hsr3.5
+
+ ip -net "$ns1" link set dev hsr1.2 up
+ ip -net "$ns1" link set dev hsr1.3 up
+ ip -net "$ns1" link set dev hsr1.4 up
+ ip -net "$ns1" link set dev hsr1.5 up
+
+ ip -net "$ns2" link set dev hsr2.2 up
+ ip -net "$ns2" link set dev hsr2.3 up
+ ip -net "$ns2" link set dev hsr2.4 up
+ ip -net "$ns2" link set dev hsr2.5 up
+
+ ip -net "$ns3" link set dev hsr3.2 up
+ ip -net "$ns3" link set dev hsr3.3 up
+ ip -net "$ns3" link set dev hsr3.4 up
+ ip -net "$ns3" link set dev hsr3.5 up
+
+}
+
+hsr_vlan_ping() {
+ do_ping "$ns1" 100.64.2.2
+ do_ping "$ns1" 100.64.3.2
+ do_ping "$ns1" 100.64.4.2
+ do_ping "$ns1" 100.64.5.2
+
+ do_ping "$ns1" 100.64.2.3
+ do_ping "$ns1" 100.64.3.3
+ do_ping "$ns1" 100.64.4.3
+ do_ping "$ns1" 100.64.5.3
+
+ do_ping "$ns2" 100.64.2.1
+ do_ping "$ns2" 100.64.3.1
+ do_ping "$ns2" 100.64.4.1
+ do_ping "$ns2" 100.64.5.1
+
+ do_ping "$ns2" 100.64.2.3
+ do_ping "$ns2" 100.64.3.3
+ do_ping "$ns2" 100.64.4.3
+ do_ping "$ns2" 100.64.5.3
+
+ do_ping "$ns3" 100.64.2.1
+ do_ping "$ns3" 100.64.3.1
+ do_ping "$ns3" 100.64.4.1
+ do_ping "$ns3" 100.64.5.1
+
+ do_ping "$ns3" 100.64.2.2
+ do_ping "$ns3" 100.64.3.2
+ do_ping "$ns3" 100.64.4.2
+ do_ping "$ns3" 100.64.5.2
+}
+
+run_vlan_tests() {
+ vlan_challenged_hsr1=$(ip net exec "$ns1" ethtool -k hsr1 | grep "vlan-challenged" | awk '{print $2}')
+ vlan_challenged_hsr2=$(ip net exec "$ns2" ethtool -k hsr2 | grep "vlan-challenged" | awk '{print $2}')
+ vlan_challenged_hsr3=$(ip net exec "$ns3" ethtool -k hsr3 | grep "vlan-challenged" | awk '{print $2}')
+
+ if [[ "$vlan_challenged_hsr1" = "off" || "$vlan_challenged_hsr2" = "off" || "$vlan_challenged_hsr3" = "off" ]]; then
+ echo "INFO: Running VLAN tests"
+ setup_vlan_interfaces
+ hsr_vlan_ping
+ else
+ echo "INFO: Not Running VLAN tests as the device does not support VLAN"
+ fi
+}
+
check_prerequisites
setup_ns ns1 ns2 ns3
@@ -183,9 +277,13 @@ trap cleanup_all_ns EXIT
setup_hsr_interfaces 0
do_complete_ping_test
+run_vlan_tests
+
setup_ns ns1 ns2 ns3
setup_hsr_interfaces 1
do_complete_ping_test
+run_vlan_tests
+
exit $ret
diff --git a/tools/testing/selftests/net/hsr/settings b/tools/testing/selftests/net/hsr/settings
new file mode 100644
index 000000000000..0fbc037f2aa8
--- /dev/null
+++ b/tools/testing/selftests/net/hsr/settings
@@ -0,0 +1 @@
+timeout=50
diff --git a/tools/testing/selftests/net/ipv6_route_update_soft_lockup.sh b/tools/testing/selftests/net/ipv6_route_update_soft_lockup.sh
new file mode 100755
index 000000000000..a6b2b1f9c641
--- /dev/null
+++ b/tools/testing/selftests/net/ipv6_route_update_soft_lockup.sh
@@ -0,0 +1,262 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Testing for potential kernel soft lockup during IPv6 routing table
+# refresh under heavy outgoing IPv6 traffic. If a kernel soft lockup
+# occurs, a kernel panic will be triggered to prevent associated issues.
+#
+#
+# Test Environment Layout
+#
+# ┌----------------┐ ┌----------------┐
+# | SOURCE_NS | | SINK_NS |
+# | NAMESPACE | | NAMESPACE |
+# |(iperf3 clients)| |(iperf3 servers)|
+# | | | |
+# | | | |
+# | ┌-----------| nexthops |---------┐ |
+# | |veth_source|<--------------------------------------->|veth_sink|<┐ |
+# | └-----------|2001:0DB8:1::0:1/96 2001:0DB8:1::1:1/96 |---------┘ | |
+# | | ^ 2001:0DB8:1::1:2/96 | | |
+# | | . . | fwd | |
+# | ┌---------┐ | . . | | |
+# | | IPv6 | | . . | V |
+# | | routing | | . 2001:0DB8:1::1:80/96| ┌-----┐ |
+# | | table | | . | | lo | |
+# | | nexthop | | . └--------┴-----┴-┘
+# | | update | | ............................> 2001:0DB8:2::1:1/128
+# | └-------- ┘ |
+# └----------------┘
+#
+# The test script sets up two network namespaces, source_ns and sink_ns,
+# connected via a veth link. Within source_ns, it continuously updates the
+# IPv6 routing table by flushing and inserting IPV6_NEXTHOP_ADDR_COUNT nexthop
+# IPs destined for SINK_LOOPBACK_IP_ADDR in sink_ns. This refresh occurs at a
+# rate of 1/ROUTING_TABLE_REFRESH_PERIOD per second for TEST_DURATION seconds.
+#
+# Simultaneously, multiple iperf3 clients within source_ns generate heavy
+# outgoing IPv6 traffic. Each client is assigned a unique port number starting
+# at 5000 and incrementing sequentially. Each client targets a unique iperf3
+# server running in sink_ns, connected to the SINK_LOOPBACK_IFACE interface
+# using the same port number.
+#
+# The number of iperf3 servers and clients is set to half of the total
+# available cores on each machine.
+#
+# NOTE: We have tested this script on machines with various CPU specifications,
+# ranging from lower to higher performance as listed below. The test script
+# effectively triggered a kernel soft lockup on machines running an unpatched
+# kernel in under a minute:
+#
+# - 1x Intel Xeon E-2278G 8-Core Processor @ 3.40GHz
+# - 1x Intel Xeon E-2378G Processor 8-Core @ 2.80GHz
+# - 1x AMD EPYC 7401P 24-Core Processor @ 2.00GHz
+# - 1x AMD EPYC 7402P 24-Core Processor @ 2.80GHz
+# - 2x Intel Xeon Gold 5120 14-Core Processor @ 2.20GHz
+# - 1x Ampere Altra Q80-30 80-Core Processor @ 3.00GHz
+# - 2x Intel Xeon Gold 5120 14-Core Processor @ 2.20GHz
+# - 2x Intel Xeon Silver 4214 24-Core Processor @ 2.20GHz
+# - 1x AMD EPYC 7502P 32-Core @ 2.50GHz
+# - 1x Intel Xeon Gold 6314U 32-Core Processor @ 2.30GHz
+# - 2x Intel Xeon Gold 6338 32-Core Processor @ 2.00GHz
+#
+# On less performant machines, you may need to increase the TEST_DURATION
+# parameter to enhance the likelihood of encountering a race condition leading
+# to a kernel soft lockup and avoid a false negative result.
+#
+# NOTE: The test may not produce the expected result in virtualized
+# environments (e.g., qemu) due to differences in timing and CPU handling,
+# which can affect the conditions needed to trigger a soft lockup.
+
+source lib.sh
+source net_helper.sh
+
+TEST_DURATION=300
+ROUTING_TABLE_REFRESH_PERIOD=0.01
+
+IPERF3_BITRATE="300m"
+
+
+IPV6_NEXTHOP_ADDR_COUNT="128"
+IPV6_NEXTHOP_ADDR_MASK="96"
+IPV6_NEXTHOP_PREFIX="2001:0DB8:1"
+
+
+SOURCE_TEST_IFACE="veth_source"
+SOURCE_TEST_IP_ADDR="2001:0DB8:1::0:1/96"
+
+SINK_TEST_IFACE="veth_sink"
+# ${SINK_TEST_IFACE} is populated with the following range of IPv6 addresses:
+# 2001:0DB8:1::1:1 to 2001:0DB8:1::1:${IPV6_NEXTHOP_ADDR_COUNT}
+SINK_LOOPBACK_IFACE="lo"
+SINK_LOOPBACK_IP_MASK="128"
+SINK_LOOPBACK_IP_ADDR="2001:0DB8:2::1:1"
+
+nexthop_ip_list=""
+termination_signal=""
+kernel_softlokup_panic_prev_val=""
+
+terminate_ns_processes_by_pattern() {
+ local ns=$1
+ local pattern=$2
+
+ for pid in $(ip netns pids ${ns}); do
+ [ -e /proc/$pid/cmdline ] && grep -qe "${pattern}" /proc/$pid/cmdline && kill -9 $pid
+ done
+}
+
+cleanup() {
+ echo "info: cleaning up namespaces and terminating all processes within them..."
+
+
+ # Terminate iperf3 instances running in the source_ns. To avoid race
+ # conditions, first iterate over the PIDs and terminate those
+ # associated with the bash shells running the
+ # `while true; do iperf3 -c ...; done` loops. In a second iteration,
+ # terminate the individual `iperf3 -c ...` instances.
+ terminate_ns_processes_by_pattern ${source_ns} while
+ terminate_ns_processes_by_pattern ${source_ns} iperf3
+
+ # Repeat the same process for sink_ns
+ terminate_ns_processes_by_pattern ${sink_ns} while
+ terminate_ns_processes_by_pattern ${sink_ns} iperf3
+
+ # Check if any iperf3 instances are still running. This could happen
+ # if a core has entered an infinite loop and the timeout for detecting
+ # the soft lockup has not expired, but either the test interval has
+ # already elapsed or the test was terminated manually (e.g., with ^C)
+ for pid in $(ip netns pids ${source_ns}); do
+ if [ -e /proc/$pid/cmdline ] && grep -qe 'iperf3' /proc/$pid/cmdline; then
+ echo "FAIL: unable to terminate some iperf3 instances. Soft lockup is underway. A kernel panic is on the way!"
+ exit ${ksft_fail}
+ fi
+ done
+
+ if [ "$termination_signal" == "SIGINT" ]; then
+ echo "SKIP: Termination due to ^C (SIGINT)"
+ elif [ "$termination_signal" == "SIGALRM" ]; then
+ echo "PASS: No kernel soft lockup occurred during this ${TEST_DURATION} second test"
+ fi
+
+ cleanup_ns ${source_ns} ${sink_ns}
+
+ sysctl -qw kernel.softlockup_panic=${kernel_softlokup_panic_prev_val}
+}
+
+setup_prepare() {
+ setup_ns source_ns sink_ns
+
+ ip -n ${source_ns} link add name ${SOURCE_TEST_IFACE} type veth peer name ${SINK_TEST_IFACE} netns ${sink_ns}
+
+ # Setting up the Source namespace
+ ip -n ${source_ns} addr add ${SOURCE_TEST_IP_ADDR} dev ${SOURCE_TEST_IFACE}
+ ip -n ${source_ns} link set dev ${SOURCE_TEST_IFACE} qlen 10000
+ ip -n ${source_ns} link set dev ${SOURCE_TEST_IFACE} up
+ ip netns exec ${source_ns} sysctl -qw net.ipv6.fib_multipath_hash_policy=1
+
+ # Setting up the Sink namespace
+ ip -n ${sink_ns} addr add ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK} dev ${SINK_LOOPBACK_IFACE}
+ ip -n ${sink_ns} link set dev ${SINK_LOOPBACK_IFACE} up
+ ip netns exec ${sink_ns} sysctl -qw net.ipv6.conf.${SINK_LOOPBACK_IFACE}.forwarding=1
+
+ ip -n ${sink_ns} link set ${SINK_TEST_IFACE} up
+ ip netns exec ${sink_ns} sysctl -qw net.ipv6.conf.${SINK_TEST_IFACE}.forwarding=1
+
+
+ # Populate nexthop IPv6 addresses on the test interface in the sink_ns
+ echo "info: populating ${IPV6_NEXTHOP_ADDR_COUNT} IPv6 addresses on the ${SINK_TEST_IFACE} interface ..."
+ for IP in $(seq 1 ${IPV6_NEXTHOP_ADDR_COUNT}); do
+ ip -n ${sink_ns} addr add ${IPV6_NEXTHOP_PREFIX}::$(printf "1:%x" "${IP}")/${IPV6_NEXTHOP_ADDR_MASK} dev ${SINK_TEST_IFACE};
+ done
+
+ # Preparing list of nexthops
+ for IP in $(seq 1 ${IPV6_NEXTHOP_ADDR_COUNT}); do
+ nexthop_ip_list=$nexthop_ip_list" nexthop via ${IPV6_NEXTHOP_PREFIX}::$(printf "1:%x" $IP) dev ${SOURCE_TEST_IFACE} weight 1"
+ done
+}
+
+
+test_soft_lockup_during_routing_table_refresh() {
+ # Start num_of_iperf_servers iperf3 servers in the sink_ns namespace,
+ # each listening on ports starting at 5001 and incrementing
+ # sequentially. Since iperf3 instances may terminate unexpectedly, a
+ # while loop is used to automatically restart them in such cases.
+ echo "info: starting ${num_of_iperf_servers} iperf3 servers in the sink_ns namespace ..."
+ for i in $(seq 1 ${num_of_iperf_servers}); do
+ cmd="iperf3 --bind ${SINK_LOOPBACK_IP_ADDR} -s -p $(printf '5%03d' ${i}) --rcv-timeout 200 &>/dev/null"
+ ip netns exec ${sink_ns} bash -c "while true; do ${cmd}; done &" &>/dev/null
+ done
+
+ # Wait for the iperf3 servers to be ready
+ for i in $(seq ${num_of_iperf_servers}); do
+ port=$(printf '5%03d' ${i});
+ wait_local_port_listen ${sink_ns} ${port} tcp
+ done
+
+ # Continuously refresh the routing table in the background within
+ # the source_ns namespace
+ ip netns exec ${source_ns} bash -c "
+ while \$(ip netns list | grep -q ${source_ns}); do
+ ip -6 route add ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK} ${nexthop_ip_list};
+ sleep ${ROUTING_TABLE_REFRESH_PERIOD};
+ ip -6 route delete ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK};
+ done &"
+
+ # Start num_of_iperf_servers iperf3 clients in the source_ns namespace,
+ # each sending TCP traffic on sequential ports starting at 5001.
+ # Since iperf3 instances may terminate unexpectedly (e.g., if the route
+ # to the server is deleted in the background during a route refresh), a
+ # while loop is used to automatically restart them in such cases.
+ echo "info: starting ${num_of_iperf_servers} iperf3 clients in the source_ns namespace ..."
+ for i in $(seq 1 ${num_of_iperf_servers}); do
+ cmd="iperf3 -c ${SINK_LOOPBACK_IP_ADDR} -p $(printf '5%03d' ${i}) --length 64 --bitrate ${IPERF3_BITRATE} -t 0 --connect-timeout 150 &>/dev/null"
+ ip netns exec ${source_ns} bash -c "while true; do ${cmd}; done &" &>/dev/null
+ done
+
+ echo "info: IPv6 routing table is being updated at the rate of $(echo "1/${ROUTING_TABLE_REFRESH_PERIOD}" | bc)/s for ${TEST_DURATION} seconds ..."
+ echo "info: A kernel soft lockup, if detected, results in a kernel panic!"
+
+ wait
+}
+
+# Make sure 'iperf3' is installed, skip the test otherwise
+if [ ! -x "$(command -v "iperf3")" ]; then
+ echo "SKIP: 'iperf3' is not installed. Skipping the test."
+ exit ${ksft_skip}
+fi
+
+# Determine the number of cores on the machine
+num_of_iperf_servers=$(( $(nproc)/2 ))
+
+# Check if we are running on a multi-core machine, skip the test otherwise
+if [ "${num_of_iperf_servers}" -eq 0 ]; then
+ echo "SKIP: This test is not valid on a single core machine!"
+ exit ${ksft_skip}
+fi
+
+# Since the kernel soft lockup we're testing causes at least one core to enter
+# an infinite loop, destabilizing the host and likely affecting subsequent
+# tests, we trigger a kernel panic instead of reporting a failure and
+# continuing
+kernel_softlokup_panic_prev_val=$(sysctl -n kernel.softlockup_panic)
+sysctl -qw kernel.softlockup_panic=1
+
+handle_sigint() {
+ termination_signal="SIGINT"
+ cleanup
+ exit ${ksft_skip}
+}
+
+handle_sigalrm() {
+ termination_signal="SIGALRM"
+ cleanup
+ exit ${ksft_pass}
+}
+
+trap handle_sigint SIGINT
+trap handle_sigalrm SIGALRM
+
+(sleep ${TEST_DURATION} && kill -s SIGALRM $$)&
+
+setup_prepare
+test_soft_lockup_during_routing_table_refresh
diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh
index c8991cc6bf28..8994fec1c38f 100644
--- a/tools/testing/selftests/net/lib.sh
+++ b/tools/testing/selftests/net/lib.sh
@@ -9,6 +9,9 @@ source "$net_dir/lib/sh/defer.sh"
: "${WAIT_TIMEOUT:=20}"
+# Whether to pause on after a failure.
+: "${PAUSE_ON_FAIL:=no}"
+
BUSYWAIT_TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms
# Kselftest framework constants.
@@ -20,6 +23,11 @@ ksft_skip=4
# namespace list created by setup_ns
NS_LIST=()
+# Exit status to return at the end. Set in case one of the tests fails.
+EXIT_STATUS=0
+# Per-test return value. Clear at the beginning of each test.
+RET=0
+
##############################################################################
# Helpers
@@ -236,3 +244,218 @@ tc_rule_handle_stats_get()
| jq ".[] | select(.options.handle == $handle) | \
.options.actions[0].stats$selector"
}
+
+ret_set_ksft_status()
+{
+ local ksft_status=$1; shift
+ local msg=$1; shift
+
+ RET=$(ksft_status_merge $RET $ksft_status)
+ if (( $? )); then
+ retmsg=$msg
+ fi
+}
+
+log_test_result()
+{
+ local test_name=$1; shift
+ local opt_str=$1; shift
+ local result=$1; shift
+ local retmsg=$1; shift
+
+ printf "TEST: %-60s [%s]\n" "$test_name $opt_str" "$result"
+ if [[ $retmsg ]]; then
+ printf "\t%s\n" "$retmsg"
+ fi
+}
+
+pause_on_fail()
+{
+ if [[ $PAUSE_ON_FAIL == yes ]]; then
+ echo "Hit enter to continue, 'q' to quit"
+ read a
+ [[ $a == q ]] && exit 1
+ fi
+}
+
+handle_test_result_pass()
+{
+ local test_name=$1; shift
+ local opt_str=$1; shift
+
+ log_test_result "$test_name" "$opt_str" " OK "
+}
+
+handle_test_result_fail()
+{
+ local test_name=$1; shift
+ local opt_str=$1; shift
+
+ log_test_result "$test_name" "$opt_str" FAIL "$retmsg"
+ pause_on_fail
+}
+
+handle_test_result_xfail()
+{
+ local test_name=$1; shift
+ local opt_str=$1; shift
+
+ log_test_result "$test_name" "$opt_str" XFAIL "$retmsg"
+ pause_on_fail
+}
+
+handle_test_result_skip()
+{
+ local test_name=$1; shift
+ local opt_str=$1; shift
+
+ log_test_result "$test_name" "$opt_str" SKIP "$retmsg"
+}
+
+log_test()
+{
+ local test_name=$1
+ local opt_str=$2
+
+ if [[ $# -eq 2 ]]; then
+ opt_str="($opt_str)"
+ fi
+
+ if ((RET == ksft_pass)); then
+ handle_test_result_pass "$test_name" "$opt_str"
+ elif ((RET == ksft_xfail)); then
+ handle_test_result_xfail "$test_name" "$opt_str"
+ elif ((RET == ksft_skip)); then
+ handle_test_result_skip "$test_name" "$opt_str"
+ else
+ handle_test_result_fail "$test_name" "$opt_str"
+ fi
+
+ EXIT_STATUS=$(ksft_exit_status_merge $EXIT_STATUS $RET)
+ return $RET
+}
+
+log_test_skip()
+{
+ RET=$ksft_skip retmsg= log_test "$@"
+}
+
+log_test_xfail()
+{
+ RET=$ksft_xfail retmsg= log_test "$@"
+}
+
+log_info()
+{
+ local msg=$1
+
+ echo "INFO: $msg"
+}
+
+tests_run()
+{
+ local current_test
+
+ for current_test in ${TESTS:-$ALL_TESTS}; do
+ in_defer_scope \
+ $current_test
+ done
+}
+
+# Whether FAILs should be interpreted as XFAILs. Internal.
+FAIL_TO_XFAIL=
+
+check_err()
+{
+ local err=$1
+ local msg=$2
+
+ if ((err)); then
+ if [[ $FAIL_TO_XFAIL = yes ]]; then
+ ret_set_ksft_status $ksft_xfail "$msg"
+ else
+ ret_set_ksft_status $ksft_fail "$msg"
+ fi
+ fi
+}
+
+check_fail()
+{
+ local err=$1
+ local msg=$2
+
+ check_err $((!err)) "$msg"
+}
+
+check_err_fail()
+{
+ local should_fail=$1; shift
+ local err=$1; shift
+ local what=$1; shift
+
+ if ((should_fail)); then
+ check_fail $err "$what succeeded, but should have failed"
+ else
+ check_err $err "$what failed"
+ fi
+}
+
+xfail()
+{
+ FAIL_TO_XFAIL=yes "$@"
+}
+
+xfail_on_slow()
+{
+ if [[ $KSFT_MACHINE_SLOW = yes ]]; then
+ FAIL_TO_XFAIL=yes "$@"
+ else
+ "$@"
+ fi
+}
+
+omit_on_slow()
+{
+ if [[ $KSFT_MACHINE_SLOW != yes ]]; then
+ "$@"
+ fi
+}
+
+xfail_on_veth()
+{
+ local dev=$1; shift
+ local kind
+
+ kind=$(ip -j -d link show dev $dev |
+ jq -r '.[].linkinfo.info_kind')
+ if [[ $kind = veth ]]; then
+ FAIL_TO_XFAIL=yes "$@"
+ else
+ "$@"
+ fi
+}
+
+kill_process()
+{
+ local pid=$1; shift
+
+ # Suppress noise from killing the process.
+ { kill $pid && wait $pid; } 2>/dev/null
+}
+
+ip_link_add()
+{
+ local name=$1; shift
+
+ ip link add name "$name" "$@"
+ defer ip link del dev "$name"
+}
+
+ip_link_master()
+{
+ local member=$1; shift
+ local master=$1; shift
+
+ ip link set dev "$member" master "$master"
+ defer ip link set dev "$member" nomaster
+}
diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile
index 5d796622e730..8e3fc05a5397 100644
--- a/tools/testing/selftests/net/mptcp/Makefile
+++ b/tools/testing/selftests/net/mptcp/Makefile
@@ -11,7 +11,7 @@ TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
TEST_FILES := mptcp_lib.sh settings
-TEST_INCLUDES := ../lib.sh ../net_helper.sh
+TEST_INCLUDES := ../lib.sh $(wildcard ../lib/sh/*.sh) ../net_helper.sh
EXTRA_CLEAN := *.pcap
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
index 57325d57e4c6..b48b4e56826a 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
@@ -259,6 +259,15 @@ check_mptcp_disabled()
mptcp_lib_ns_init disabled_ns
print_larger_title "New MPTCP socket can be blocked via sysctl"
+
+ # mainly to cover more code
+ if ! ip netns exec ${disabled_ns} sysctl net.mptcp >/dev/null; then
+ mptcp_lib_pr_fail "not able to list net.mptcp sysctl knobs"
+ mptcp_lib_result_fail "not able to list net.mptcp sysctl knobs"
+ ret=${KSFT_FAIL}
+ return 1
+ fi
+
# net.mptcp.enabled should be enabled by default
if [ "$(ip netns exec ${disabled_ns} sysctl net.mptcp.enabled | awk '{ print $3 }')" -ne 1 ]; then
mptcp_lib_pr_fail "net.mptcp.enabled sysctl is not 1 by default"
diff --git a/tools/testing/selftests/net/ncdevmem.c b/tools/testing/selftests/net/ncdevmem.c
deleted file mode 100644
index 64d6805381c5..000000000000
--- a/tools/testing/selftests/net/ncdevmem.c
+++ /dev/null
@@ -1,570 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define _GNU_SOURCE
-#define __EXPORTED_HEADERS__
-
-#include <linux/uio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#define __iovec_defined
-#include <fcntl.h>
-#include <malloc.h>
-#include <error.h>
-
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <sys/syscall.h>
-
-#include <linux/memfd.h>
-#include <linux/dma-buf.h>
-#include <linux/udmabuf.h>
-#include <libmnl/libmnl.h>
-#include <linux/types.h>
-#include <linux/netlink.h>
-#include <linux/genetlink.h>
-#include <linux/netdev.h>
-#include <time.h>
-#include <net/if.h>
-
-#include "netdev-user.h"
-#include <ynl.h>
-
-#define PAGE_SHIFT 12
-#define TEST_PREFIX "ncdevmem"
-#define NUM_PAGES 16000
-
-#ifndef MSG_SOCK_DEVMEM
-#define MSG_SOCK_DEVMEM 0x2000000
-#endif
-
-/*
- * tcpdevmem netcat. Works similarly to netcat but does device memory TCP
- * instead of regular TCP. Uses udmabuf to mock a dmabuf provider.
- *
- * Usage:
- *
- * On server:
- * ncdevmem -s <server IP> -c <client IP> -f eth1 -l -p 5201 -v 7
- *
- * On client:
- * yes $(echo -e \\x01\\x02\\x03\\x04\\x05\\x06) | \
- * tr \\n \\0 | \
- * head -c 5G | \
- * nc <server IP> 5201 -p 5201
- *
- * Note this is compatible with regular netcat. i.e. the sender or receiver can
- * be replaced with regular netcat to test the RX or TX path in isolation.
- */
-
-static char *server_ip = "192.168.1.4";
-static char *client_ip = "192.168.1.2";
-static char *port = "5201";
-static size_t do_validation;
-static int start_queue = 8;
-static int num_queues = 8;
-static char *ifname = "eth1";
-static unsigned int ifindex;
-static unsigned int dmabuf_id;
-
-void print_bytes(void *ptr, size_t size)
-{
- unsigned char *p = ptr;
- int i;
-
- for (i = 0; i < size; i++)
- printf("%02hhX ", p[i]);
- printf("\n");
-}
-
-void print_nonzero_bytes(void *ptr, size_t size)
-{
- unsigned char *p = ptr;
- unsigned int i;
-
- for (i = 0; i < size; i++)
- putchar(p[i]);
- printf("\n");
-}
-
-void validate_buffer(void *line, size_t size)
-{
- static unsigned char seed = 1;
- unsigned char *ptr = line;
- int errors = 0;
- size_t i;
-
- for (i = 0; i < size; i++) {
- if (ptr[i] != seed) {
- fprintf(stderr,
- "Failed validation: expected=%u, actual=%u, index=%lu\n",
- seed, ptr[i], i);
- errors++;
- if (errors > 20)
- error(1, 0, "validation failed.");
- }
- seed++;
- if (seed == do_validation)
- seed = 0;
- }
-
- fprintf(stdout, "Validated buffer\n");
-}
-
-#define run_command(cmd, ...) \
- ({ \
- char command[256]; \
- memset(command, 0, sizeof(command)); \
- snprintf(command, sizeof(command), cmd, ##__VA_ARGS__); \
- printf("Running: %s\n", command); \
- system(command); \
- })
-
-static int reset_flow_steering(void)
-{
- int ret = 0;
-
- ret = run_command("sudo ethtool -K %s ntuple off", ifname);
- if (ret)
- return ret;
-
- return run_command("sudo ethtool -K %s ntuple on", ifname);
-}
-
-static int configure_headersplit(bool on)
-{
- return run_command("sudo ethtool -G %s tcp-data-split %s", ifname,
- on ? "on" : "off");
-}
-
-static int configure_rss(void)
-{
- return run_command("sudo ethtool -X %s equal %d", ifname, start_queue);
-}
-
-static int configure_channels(unsigned int rx, unsigned int tx)
-{
- return run_command("sudo ethtool -L %s rx %u tx %u", ifname, rx, tx);
-}
-
-static int configure_flow_steering(void)
-{
- return run_command("sudo ethtool -N %s flow-type tcp4 src-ip %s dst-ip %s src-port %s dst-port %s queue %d",
- ifname, client_ip, server_ip, port, port, start_queue);
-}
-
-static int bind_rx_queue(unsigned int ifindex, unsigned int dmabuf_fd,
- struct netdev_queue_id *queues,
- unsigned int n_queue_index, struct ynl_sock **ys)
-{
- struct netdev_bind_rx_req *req = NULL;
- struct netdev_bind_rx_rsp *rsp = NULL;
- struct ynl_error yerr;
-
- *ys = ynl_sock_create(&ynl_netdev_family, &yerr);
- if (!*ys) {
- fprintf(stderr, "YNL: %s\n", yerr.msg);
- return -1;
- }
-
- req = netdev_bind_rx_req_alloc();
- netdev_bind_rx_req_set_ifindex(req, ifindex);
- netdev_bind_rx_req_set_fd(req, dmabuf_fd);
- __netdev_bind_rx_req_set_queues(req, queues, n_queue_index);
-
- rsp = netdev_bind_rx(*ys, req);
- if (!rsp) {
- perror("netdev_bind_rx");
- goto err_close;
- }
-
- if (!rsp->_present.id) {
- perror("id not present");
- goto err_close;
- }
-
- printf("got dmabuf id=%d\n", rsp->id);
- dmabuf_id = rsp->id;
-
- netdev_bind_rx_req_free(req);
- netdev_bind_rx_rsp_free(rsp);
-
- return 0;
-
-err_close:
- fprintf(stderr, "YNL failed: %s\n", (*ys)->err.msg);
- netdev_bind_rx_req_free(req);
- ynl_sock_destroy(*ys);
- return -1;
-}
-
-static void create_udmabuf(int *devfd, int *memfd, int *buf, size_t dmabuf_size)
-{
- struct udmabuf_create create;
- int ret;
-
- *devfd = open("/dev/udmabuf", O_RDWR);
- if (*devfd < 0) {
- error(70, 0,
- "%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
- TEST_PREFIX);
- }
-
- *memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
- if (*memfd < 0)
- error(70, 0, "%s: [skip,no-memfd]\n", TEST_PREFIX);
-
- /* Required for udmabuf */
- ret = fcntl(*memfd, F_ADD_SEALS, F_SEAL_SHRINK);
- if (ret < 0)
- error(73, 0, "%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
-
- ret = ftruncate(*memfd, dmabuf_size);
- if (ret == -1)
- error(74, 0, "%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
-
- memset(&create, 0, sizeof(create));
-
- create.memfd = *memfd;
- create.offset = 0;
- create.size = dmabuf_size;
- *buf = ioctl(*devfd, UDMABUF_CREATE, &create);
- if (*buf < 0)
- error(75, 0, "%s: [FAIL, create udmabuf]\n", TEST_PREFIX);
-}
-
-int do_server(void)
-{
- char ctrl_data[sizeof(int) * 20000];
- struct netdev_queue_id *queues;
- size_t non_page_aligned_frags = 0;
- struct sockaddr_in client_addr;
- struct sockaddr_in server_sin;
- size_t page_aligned_frags = 0;
- int devfd, memfd, buf, ret;
- size_t total_received = 0;
- socklen_t client_addr_len;
- bool is_devmem = false;
- char *buf_mem = NULL;
- struct ynl_sock *ys;
- size_t dmabuf_size;
- char iobuf[819200];
- char buffer[256];
- int socket_fd;
- int client_fd;
- size_t i = 0;
- int opt = 1;
-
- dmabuf_size = getpagesize() * NUM_PAGES;
-
- create_udmabuf(&devfd, &memfd, &buf, dmabuf_size);
-
- if (reset_flow_steering())
- error(1, 0, "Failed to reset flow steering\n");
-
- /* Configure RSS to divert all traffic from our devmem queues */
- if (configure_rss())
- error(1, 0, "Failed to configure rss\n");
-
- /* Flow steer our devmem flows to start_queue */
- if (configure_flow_steering())
- error(1, 0, "Failed to configure flow steering\n");
-
- sleep(1);
-
- queues = malloc(sizeof(*queues) * num_queues);
-
- for (i = 0; i < num_queues; i++) {
- queues[i]._present.type = 1;
- queues[i]._present.id = 1;
- queues[i].type = NETDEV_QUEUE_TYPE_RX;
- queues[i].id = start_queue + i;
- }
-
- if (bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
- error(1, 0, "Failed to bind\n");
-
- buf_mem = mmap(NULL, dmabuf_size, PROT_READ | PROT_WRITE, MAP_SHARED,
- buf, 0);
- if (buf_mem == MAP_FAILED)
- error(1, 0, "mmap()");
-
- server_sin.sin_family = AF_INET;
- server_sin.sin_port = htons(atoi(port));
-
- ret = inet_pton(server_sin.sin_family, server_ip, &server_sin.sin_addr);
- if (socket < 0)
- error(79, 0, "%s: [FAIL, create socket]\n", TEST_PREFIX);
-
- socket_fd = socket(server_sin.sin_family, SOCK_STREAM, 0);
- if (socket < 0)
- error(errno, errno, "%s: [FAIL, create socket]\n", TEST_PREFIX);
-
- ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &opt,
- sizeof(opt));
- if (ret)
- error(errno, errno, "%s: [FAIL, set sock opt]\n", TEST_PREFIX);
-
- ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt,
- sizeof(opt));
- if (ret)
- error(errno, errno, "%s: [FAIL, set sock opt]\n", TEST_PREFIX);
-
- printf("binding to address %s:%d\n", server_ip,
- ntohs(server_sin.sin_port));
-
- ret = bind(socket_fd, &server_sin, sizeof(server_sin));
- if (ret)
- error(errno, errno, "%s: [FAIL, bind]\n", TEST_PREFIX);
-
- ret = listen(socket_fd, 1);
- if (ret)
- error(errno, errno, "%s: [FAIL, listen]\n", TEST_PREFIX);
-
- client_addr_len = sizeof(client_addr);
-
- inet_ntop(server_sin.sin_family, &server_sin.sin_addr, buffer,
- sizeof(buffer));
- printf("Waiting or connection on %s:%d\n", buffer,
- ntohs(server_sin.sin_port));
- client_fd = accept(socket_fd, &client_addr, &client_addr_len);
-
- inet_ntop(client_addr.sin_family, &client_addr.sin_addr, buffer,
- sizeof(buffer));
- printf("Got connection from %s:%d\n", buffer,
- ntohs(client_addr.sin_port));
-
- while (1) {
- struct iovec iov = { .iov_base = iobuf,
- .iov_len = sizeof(iobuf) };
- struct dmabuf_cmsg *dmabuf_cmsg = NULL;
- struct dma_buf_sync sync = { 0 };
- struct cmsghdr *cm = NULL;
- struct msghdr msg = { 0 };
- struct dmabuf_token token;
- ssize_t ret;
-
- is_devmem = false;
- printf("\n\n");
-
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = ctrl_data;
- msg.msg_controllen = sizeof(ctrl_data);
- ret = recvmsg(client_fd, &msg, MSG_SOCK_DEVMEM);
- printf("recvmsg ret=%ld\n", ret);
- if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
- continue;
- if (ret < 0) {
- perror("recvmsg");
- continue;
- }
- if (ret == 0) {
- printf("client exited\n");
- goto cleanup;
- }
-
- i++;
- for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
- if (cm->cmsg_level != SOL_SOCKET ||
- (cm->cmsg_type != SCM_DEVMEM_DMABUF &&
- cm->cmsg_type != SCM_DEVMEM_LINEAR)) {
- fprintf(stdout, "skipping non-devmem cmsg\n");
- continue;
- }
-
- dmabuf_cmsg = (struct dmabuf_cmsg *)CMSG_DATA(cm);
- is_devmem = true;
-
- if (cm->cmsg_type == SCM_DEVMEM_LINEAR) {
- /* TODO: process data copied from skb's linear
- * buffer.
- */
- fprintf(stdout,
- "SCM_DEVMEM_LINEAR. dmabuf_cmsg->frag_size=%u\n",
- dmabuf_cmsg->frag_size);
-
- continue;
- }
-
- token.token_start = dmabuf_cmsg->frag_token;
- token.token_count = 1;
-
- total_received += dmabuf_cmsg->frag_size;
- printf("received frag_page=%llu, in_page_offset=%llu, frag_offset=%llu, frag_size=%u, token=%u, total_received=%lu, dmabuf_id=%u\n",
- dmabuf_cmsg->frag_offset >> PAGE_SHIFT,
- dmabuf_cmsg->frag_offset % getpagesize(),
- dmabuf_cmsg->frag_offset, dmabuf_cmsg->frag_size,
- dmabuf_cmsg->frag_token, total_received,
- dmabuf_cmsg->dmabuf_id);
-
- if (dmabuf_cmsg->dmabuf_id != dmabuf_id)
- error(1, 0,
- "received on wrong dmabuf_id: flow steering error\n");
-
- if (dmabuf_cmsg->frag_size % getpagesize())
- non_page_aligned_frags++;
- else
- page_aligned_frags++;
-
- sync.flags = DMA_BUF_SYNC_READ | DMA_BUF_SYNC_START;
- ioctl(buf, DMA_BUF_IOCTL_SYNC, &sync);
-
- if (do_validation)
- validate_buffer(
- ((unsigned char *)buf_mem) +
- dmabuf_cmsg->frag_offset,
- dmabuf_cmsg->frag_size);
- else
- print_nonzero_bytes(
- ((unsigned char *)buf_mem) +
- dmabuf_cmsg->frag_offset,
- dmabuf_cmsg->frag_size);
-
- sync.flags = DMA_BUF_SYNC_READ | DMA_BUF_SYNC_END;
- ioctl(buf, DMA_BUF_IOCTL_SYNC, &sync);
-
- ret = setsockopt(client_fd, SOL_SOCKET,
- SO_DEVMEM_DONTNEED, &token,
- sizeof(token));
- if (ret != 1)
- error(1, 0,
- "SO_DEVMEM_DONTNEED not enough tokens");
- }
- if (!is_devmem)
- error(1, 0, "flow steering error\n");
-
- printf("total_received=%lu\n", total_received);
- }
-
- fprintf(stdout, "%s: ok\n", TEST_PREFIX);
-
- fprintf(stdout, "page_aligned_frags=%lu, non_page_aligned_frags=%lu\n",
- page_aligned_frags, non_page_aligned_frags);
-
- fprintf(stdout, "page_aligned_frags=%lu, non_page_aligned_frags=%lu\n",
- page_aligned_frags, non_page_aligned_frags);
-
-cleanup:
-
- munmap(buf_mem, dmabuf_size);
- close(client_fd);
- close(socket_fd);
- close(buf);
- close(memfd);
- close(devfd);
- ynl_sock_destroy(ys);
-
- return 0;
-}
-
-void run_devmem_tests(void)
-{
- struct netdev_queue_id *queues;
- int devfd, memfd, buf;
- struct ynl_sock *ys;
- size_t dmabuf_size;
- size_t i = 0;
-
- dmabuf_size = getpagesize() * NUM_PAGES;
-
- create_udmabuf(&devfd, &memfd, &buf, dmabuf_size);
-
- /* Configure RSS to divert all traffic from our devmem queues */
- if (configure_rss())
- error(1, 0, "rss error\n");
-
- queues = calloc(num_queues, sizeof(*queues));
-
- if (configure_headersplit(1))
- error(1, 0, "Failed to configure header split\n");
-
- if (!bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
- error(1, 0, "Binding empty queues array should have failed\n");
-
- for (i = 0; i < num_queues; i++) {
- queues[i]._present.type = 1;
- queues[i]._present.id = 1;
- queues[i].type = NETDEV_QUEUE_TYPE_RX;
- queues[i].id = start_queue + i;
- }
-
- if (configure_headersplit(0))
- error(1, 0, "Failed to configure header split\n");
-
- if (!bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
- error(1, 0, "Configure dmabuf with header split off should have failed\n");
-
- if (configure_headersplit(1))
- error(1, 0, "Failed to configure header split\n");
-
- for (i = 0; i < num_queues; i++) {
- queues[i]._present.type = 1;
- queues[i]._present.id = 1;
- queues[i].type = NETDEV_QUEUE_TYPE_RX;
- queues[i].id = start_queue + i;
- }
-
- if (bind_rx_queue(ifindex, buf, queues, num_queues, &ys))
- error(1, 0, "Failed to bind\n");
-
- /* Deactivating a bound queue should not be legal */
- if (!configure_channels(num_queues, num_queues - 1))
- error(1, 0, "Deactivating a bound queue should be illegal.\n");
-
- /* Closing the netlink socket does an implicit unbind */
- ynl_sock_destroy(ys);
-}
-
-int main(int argc, char *argv[])
-{
- int is_server = 0, opt;
-
- while ((opt = getopt(argc, argv, "ls:c:p:v:q:t:f:")) != -1) {
- switch (opt) {
- case 'l':
- is_server = 1;
- break;
- case 's':
- server_ip = optarg;
- break;
- case 'c':
- client_ip = optarg;
- break;
- case 'p':
- port = optarg;
- break;
- case 'v':
- do_validation = atoll(optarg);
- break;
- case 'q':
- num_queues = atoi(optarg);
- break;
- case 't':
- start_queue = atoi(optarg);
- break;
- case 'f':
- ifname = optarg;
- break;
- case '?':
- printf("unknown option: %c\n", optopt);
- break;
- }
- }
-
- ifindex = if_nametoindex(ifname);
-
- for (; optind < argc; optind++)
- printf("extra arguments: %s\n", argv[optind]);
-
- run_devmem_tests();
-
- if (is_server)
- return do_server();
-
- return 0;
-}
diff --git a/tools/testing/selftests/net/netfilter/Makefile b/tools/testing/selftests/net/netfilter/Makefile
index 542f7886a0bc..ffe161fac8b5 100644
--- a/tools/testing/selftests/net/netfilter/Makefile
+++ b/tools/testing/selftests/net/netfilter/Makefile
@@ -8,6 +8,7 @@ MNL_LDLIBS := $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)
TEST_PROGS := br_netfilter.sh bridge_brouter.sh
TEST_PROGS += br_netfilter_queue.sh
+TEST_PROGS += conntrack_dump_flush.sh
TEST_PROGS += conntrack_icmp_related.sh
TEST_PROGS += conntrack_ipip_mtu.sh
TEST_PROGS += conntrack_tcp_unreplied.sh
@@ -36,10 +37,9 @@ TEST_PROGS += xt_string.sh
TEST_PROGS_EXTENDED = nft_concat_range_perf.sh
-TEST_GEN_PROGS = conntrack_dump_flush
-
TEST_GEN_FILES = audit_logread
TEST_GEN_FILES += connect_close nf_queue
+TEST_GEN_FILES += conntrack_dump_flush
TEST_GEN_FILES += conntrack_reverse_clash
TEST_GEN_FILES += sctp_collision
@@ -55,4 +55,5 @@ TEST_FILES := lib.sh
TEST_FILES += packetdrill
TEST_INCLUDES := \
- ../lib.sh
+ ../lib.sh \
+ $(wildcard ../lib/sh/*.sh)
diff --git a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
index dc056fec993b..254ff03297f0 100644
--- a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
+++ b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c
@@ -98,7 +98,7 @@ static int conntrack_data_insert(struct mnl_socket *sock, struct nlmsghdr *nlh,
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *rplnlh;
unsigned int portid;
- int err, ret;
+ int ret;
portid = mnl_socket_get_portid(sock);
@@ -217,7 +217,7 @@ static int conntracK_count_zone(struct mnl_socket *sock, uint16_t zone)
struct nfgenmsg *nfh;
struct nlattr *nest;
unsigned int portid;
- int err, ret;
+ int ret;
portid = mnl_socket_get_portid(sock);
@@ -264,7 +264,7 @@ static int conntrack_flush_zone(struct mnl_socket *sock, uint16_t zone)
struct nfgenmsg *nfh;
struct nlattr *nest;
unsigned int portid;
- int err, ret;
+ int ret;
portid = mnl_socket_get_portid(sock);
diff --git a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.sh b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.sh
new file mode 100755
index 000000000000..8b0935385849
--- /dev/null
+++ b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec unshare -n ./conntrack_dump_flush
diff --git a/tools/testing/selftests/net/netfilter/nft_flowtable.sh b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
index b3995550856a..a4ee5496f2a1 100755
--- a/tools/testing/selftests/net/netfilter/nft_flowtable.sh
+++ b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
@@ -71,6 +71,8 @@ omtu=9000
lmtu=1500
rmtu=2000
+filesize=$((2 * 1024 * 1024))
+
usage(){
echo "nft_flowtable.sh [OPTIONS]"
echo
@@ -81,12 +83,13 @@ usage(){
exit 1
}
-while getopts "o:l:r:" o
+while getopts "o:l:r:s:" o
do
case $o in
o) omtu=$OPTARG;;
l) lmtu=$OPTARG;;
r) rmtu=$OPTARG;;
+ s) filesize=$OPTARG;;
*) usage;;
esac
done
@@ -217,18 +220,10 @@ ns2out=$(mktemp)
make_file()
{
- name=$1
-
- SIZE=$((RANDOM % (1024 * 128)))
- SIZE=$((SIZE + (1024 * 8)))
- TSIZE=$((SIZE * 1024))
-
- dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
+ name="$1"
+ sz="$2"
- SIZE=$((RANDOM % 1024))
- SIZE=$((SIZE + 128))
- TSIZE=$((TSIZE + SIZE))
- dd if=/dev/urandom conf=notrunc of="$name" bs=1 count=$SIZE 2> /dev/null
+ head -c "$sz" < /dev/urandom > "$name"
}
check_counters()
@@ -246,18 +241,18 @@ check_counters()
local fs
fs=$(du -sb "$nsin")
local max_orig=${fs%%/*}
- local max_repl=$((max_orig/4))
+ local max_repl=$((max_orig))
# flowtable fastpath should bypass normal routing one, i.e. the counters in forward hook
# should always be lower than the size of the transmitted file (max_orig).
if [ "$orig_cnt" -gt "$max_orig" ];then
- echo "FAIL: $what: original counter $orig_cnt exceeds expected value $max_orig" 1>&2
+ echo "FAIL: $what: original counter $orig_cnt exceeds expected value $max_orig, reply counter $repl_cnt" 1>&2
ret=1
ok=0
fi
if [ "$repl_cnt" -gt $max_repl ];then
- echo "FAIL: $what: reply counter $repl_cnt exceeds expected value $max_repl" 1>&2
+ echo "FAIL: $what: reply counter $repl_cnt exceeds expected value $max_repl, original counter $orig_cnt" 1>&2
ret=1
ok=0
fi
@@ -455,7 +450,7 @@ test_tcp_forwarding_nat()
return $lret
}
-make_file "$nsin"
+make_file "$nsin" "$filesize"
# First test:
# No PMTU discovery, nsr1 is expected to fragment packets from ns1 to ns2 as needed.
@@ -664,8 +659,16 @@ if [ "$1" = "" ]; then
l=$(((RANDOM%mtu) + low))
r=$(((RANDOM%mtu) + low))
- echo "re-run with random mtus: -o $o -l $l -r $r"
- $0 -o "$o" -l "$l" -r "$r"
+ MINSIZE=$((2 * 1000 * 1000))
+ MAXSIZE=$((64 * 1000 * 1000))
+
+ filesize=$(((RANDOM * RANDOM) % MAXSIZE))
+ if [ "$filesize" -lt "$MINSIZE" ]; then
+ filesize=$((filesize+MINSIZE))
+ fi
+
+ echo "re-run with random mtus and file size: -o $o -l $l -r $r -s $filesize"
+ $0 -o "$o" -l "$l" -r "$r" -s "$filesize"
fi
exit $ret
diff --git a/tools/testing/selftests/net/netfilter/nft_queue.sh b/tools/testing/selftests/net/netfilter/nft_queue.sh
index a9d109fcc15c..785e3875a6da 100755
--- a/tools/testing/selftests/net/netfilter/nft_queue.sh
+++ b/tools/testing/selftests/net/netfilter/nft_queue.sh
@@ -512,10 +512,10 @@ EOF
:> "$TMPFILE1"
:> "$TMPFILE2"
- timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12345,fork OPEN:"$TMPFILE1",trunc &
+ timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12345,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc &
local rpid1=$!
- timeout 10 ip netns exec "$ns3" socat UDP-LISTEN:12345,fork OPEN:"$TMPFILE2",trunc &
+ timeout 10 ip netns exec "$ns3" socat UDP-LISTEN:12345,fork,pf=ipv4 OPEN:"$TMPFILE2",trunc &
local rpid2=$!
ip netns exec "$nsrouter" ./nf_queue -q 12 -d 1000 &
@@ -528,8 +528,8 @@ EOF
# Send two packets, one should end up in ns1, other in ns2.
# This is because nfqueue will delay packet for long enough so that
# second packet will not find existing conntrack entry.
- echo "Packet 1" | ip netns exec "$ns1" socat STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
- echo "Packet 2" | ip netns exec "$ns1" socat STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
+ echo "Packet 1" | ip netns exec "$ns1" socat -u STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
+ echo "Packet 2" | ip netns exec "$ns1" socat -u STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221
busywait 10000 output_files_written "$TMPFILE1" "$TMPFILE2"
diff --git a/tools/testing/selftests/net/netlink-dumps.c b/tools/testing/selftests/net/netlink-dumps.c
new file mode 100644
index 000000000000..7ee6dcd334df
--- /dev/null
+++ b/tools/testing/selftests/net/netlink-dumps.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/genetlink.h>
+#include <linux/netlink.h>
+#include <linux/mqueue.h>
+
+#include "../kselftest_harness.h"
+
+static const struct {
+ struct nlmsghdr nlhdr;
+ struct genlmsghdr genlhdr;
+ struct nlattr ahdr;
+ __u16 val;
+ __u16 pad;
+} dump_policies = {
+ .nlhdr = {
+ .nlmsg_len = sizeof(dump_policies),
+ .nlmsg_type = GENL_ID_CTRL,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
+ .nlmsg_seq = 1,
+ },
+ .genlhdr = {
+ .cmd = CTRL_CMD_GETPOLICY,
+ .version = 2,
+ },
+ .ahdr = {
+ .nla_len = 6,
+ .nla_type = CTRL_ATTR_FAMILY_ID,
+ },
+ .val = GENL_ID_CTRL,
+ .pad = 0,
+};
+
+// Sanity check for the test itself, make sure the dump doesn't fit in one msg
+TEST(test_sanity)
+{
+ int netlink_sock;
+ char buf[8192];
+ ssize_t n;
+
+ netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ ASSERT_GE(netlink_sock, 0);
+
+ n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
+ ASSERT_EQ(n, sizeof(dump_policies));
+
+ n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
+ ASSERT_GE(n, sizeof(struct nlmsghdr));
+
+ n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
+ ASSERT_GE(n, sizeof(struct nlmsghdr));
+
+ close(netlink_sock);
+}
+
+TEST(close_in_progress)
+{
+ int netlink_sock;
+ ssize_t n;
+
+ netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ ASSERT_GE(netlink_sock, 0);
+
+ n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
+ ASSERT_EQ(n, sizeof(dump_policies));
+
+ close(netlink_sock);
+}
+
+TEST(close_with_ref)
+{
+ char cookie[NOTIFY_COOKIE_LEN] = {};
+ int netlink_sock, mq_fd;
+ struct sigevent sigev;
+ ssize_t n;
+
+ netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ ASSERT_GE(netlink_sock, 0);
+
+ n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
+ ASSERT_EQ(n, sizeof(dump_policies));
+
+ mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
+ ASSERT_GE(mq_fd, 0);
+
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.sigev_notify = SIGEV_THREAD;
+ sigev.sigev_value.sival_ptr = cookie;
+ sigev.sigev_signo = netlink_sock;
+
+ syscall(__NR_mq_notify, mq_fd, &sigev);
+
+ close(netlink_sock);
+
+ // give mqueue time to fire
+ usleep(100 * 1000);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh
index 569bce8b6383..66be7699c72c 100755
--- a/tools/testing/selftests/net/pmtu.sh
+++ b/tools/testing/selftests/net/pmtu.sh
@@ -197,6 +197,12 @@
#
# - pmtu_ipv6_route_change
# Same as above but with IPv6
+#
+# - pmtu_ipv4_mp_exceptions
+# Use the same topology as in pmtu_ipv4, but add routeable addresses
+# on host A and B on lo reachable via both routers. Host A and B
+# addresses have multipath routes to each other, b_r1 mtu = 1500.
+# Check that PMTU exceptions are created for both paths.
source lib.sh
source net_helper.sh
@@ -266,7 +272,8 @@ tests="
list_flush_ipv4_exception ipv4: list and flush cached exceptions 1
list_flush_ipv6_exception ipv6: list and flush cached exceptions 1
pmtu_ipv4_route_change ipv4: PMTU exception w/route replace 1
- pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1"
+ pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1
+ pmtu_ipv4_mp_exceptions ipv4: PMTU multipath nh exceptions 1"
# Addressing and routing for tests with routers: four network segments, with
# index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an
@@ -343,6 +350,9 @@ tunnel6_a_addr="fd00:2::a"
tunnel6_b_addr="fd00:2::b"
tunnel6_mask="64"
+host4_a_addr="192.168.99.99"
+host4_b_addr="192.168.88.88"
+
dummy6_0_prefix="fc00:1000::"
dummy6_1_prefix="fc00:1001::"
dummy6_mask="64"
@@ -984,6 +994,52 @@ setup_ovs_bridge() {
run_cmd ip route add ${prefix6}:${b_r1}::1 via ${prefix6}:${a_r1}::2
}
+setup_multipath_new() {
+ # Set up host A with multipath routes to host B host4_b_addr
+ run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo
+ run_cmd ${ns_a} ip nexthop add id 401 via ${prefix4}.${a_r1}.2 dev veth_A-R1
+ run_cmd ${ns_a} ip nexthop add id 402 via ${prefix4}.${a_r2}.2 dev veth_A-R2
+ run_cmd ${ns_a} ip nexthop add id 403 group 401/402
+ run_cmd ${ns_a} ip route add ${host4_b_addr} src ${host4_a_addr} nhid 403
+
+ # Set up host B with multipath routes to host A host4_a_addr
+ run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo
+ run_cmd ${ns_b} ip nexthop add id 401 via ${prefix4}.${b_r1}.2 dev veth_B-R1
+ run_cmd ${ns_b} ip nexthop add id 402 via ${prefix4}.${b_r2}.2 dev veth_B-R2
+ run_cmd ${ns_b} ip nexthop add id 403 group 401/402
+ run_cmd ${ns_b} ip route add ${host4_a_addr} src ${host4_b_addr} nhid 403
+}
+
+setup_multipath_old() {
+ # Set up host A with multipath routes to host B host4_b_addr
+ run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo
+ run_cmd ${ns_a} ip route add ${host4_b_addr} \
+ src ${host4_a_addr} \
+ nexthop via ${prefix4}.${a_r1}.2 weight 1 \
+ nexthop via ${prefix4}.${a_r2}.2 weight 1
+
+ # Set up host B with multipath routes to host A host4_a_addr
+ run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo
+ run_cmd ${ns_b} ip route add ${host4_a_addr} \
+ src ${host4_b_addr} \
+ nexthop via ${prefix4}.${b_r1}.2 weight 1 \
+ nexthop via ${prefix4}.${b_r2}.2 weight 1
+}
+
+setup_multipath() {
+ if [ "$USE_NH" = "yes" ]; then
+ setup_multipath_new
+ else
+ setup_multipath_old
+ fi
+
+ # Set up routers with routes to dummies
+ run_cmd ${ns_r1} ip route add ${host4_a_addr} via ${prefix4}.${a_r1}.1
+ run_cmd ${ns_r2} ip route add ${host4_a_addr} via ${prefix4}.${a_r2}.1
+ run_cmd ${ns_r1} ip route add ${host4_b_addr} via ${prefix4}.${b_r1}.1
+ run_cmd ${ns_r2} ip route add ${host4_b_addr} via ${prefix4}.${b_r2}.1
+}
+
setup() {
[ "$(id -u)" -ne 0 ] && echo " need to run as root" && return $ksft_skip
@@ -1076,23 +1132,15 @@ link_get_mtu() {
}
route_get_dst_exception() {
- ns_cmd="${1}"
- dst="${2}"
- dsfield="${3}"
+ ns_cmd="${1}"; shift
- if [ -z "${dsfield}" ]; then
- dsfield=0
- fi
-
- ${ns_cmd} ip route get "${dst}" dsfield "${dsfield}"
+ ${ns_cmd} ip route get "$@"
}
route_get_dst_pmtu_from_exception() {
- ns_cmd="${1}"
- dst="${2}"
- dsfield="${3}"
+ ns_cmd="${1}"; shift
- mtu_parse "$(route_get_dst_exception "${ns_cmd}" "${dst}" "${dsfield}")"
+ mtu_parse "$(route_get_dst_exception "${ns_cmd}" "$@")"
}
check_pmtu_value() {
@@ -1235,10 +1283,10 @@ test_pmtu_ipv4_dscp_icmp_exception() {
run_cmd "${ns_a}" ping -q -M want -Q "${dsfield}" -c 1 -w 1 -s "${len}" "${dst2}"
# Check that exceptions have been created with the correct PMTU
- pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" "${policy_mark}")"
+ pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" dsfield "${policy_mark}")"
check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1
- pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" "${policy_mark}")"
+ pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" dsfield "${policy_mark}")"
check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1
}
@@ -1285,9 +1333,9 @@ test_pmtu_ipv4_dscp_udp_exception() {
UDP:"${dst2}":50000,tos="${dsfield}"
# Check that exceptions have been created with the correct PMTU
- pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" "${policy_mark}")"
+ pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" dsfield "${policy_mark}")"
check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1
- pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" "${policy_mark}")"
+ pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" dsfield "${policy_mark}")"
check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1
}
@@ -2056,7 +2104,7 @@ check_running() {
pid=${1}
cmd=${2}
- [ "$(cat /proc/${pid}/cmdline 2>/dev/null | tr -d '\0')" = "{cmd}" ]
+ [ "$(cat /proc/${pid}/cmdline 2>/dev/null | tr -d '\0')" = "${cmd}" ]
}
test_cleanup_vxlanX_exception() {
@@ -2329,6 +2377,36 @@ test_pmtu_ipv6_route_change() {
test_pmtu_ipvX_route_change 6
}
+test_pmtu_ipv4_mp_exceptions() {
+ setup namespaces routing multipath || return $ksft_skip
+
+ trace "${ns_a}" veth_A-R1 "${ns_r1}" veth_R1-A \
+ "${ns_r1}" veth_R1-B "${ns_b}" veth_B-R1 \
+ "${ns_a}" veth_A-R2 "${ns_r2}" veth_R2-A \
+ "${ns_r2}" veth_R2-B "${ns_b}" veth_B-R2
+
+ # Set up initial MTU values
+ mtu "${ns_a}" veth_A-R1 2000
+ mtu "${ns_r1}" veth_R1-A 2000
+ mtu "${ns_r1}" veth_R1-B 1500
+ mtu "${ns_b}" veth_B-R1 1500
+
+ mtu "${ns_a}" veth_A-R2 2000
+ mtu "${ns_r2}" veth_R2-A 2000
+ mtu "${ns_r2}" veth_R2-B 1500
+ mtu "${ns_b}" veth_B-R2 1500
+
+ # Ping and expect two nexthop exceptions for two routes
+ run_cmd ${ns_a} ping -q -M want -i 0.1 -c 1 -s 1800 "${host4_b_addr}"
+
+ # Check that exceptions have been created with the correct PMTU
+ pmtu_a_R1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R1)"
+ pmtu_a_R2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R2)"
+
+ check_pmtu_value "1500" "${pmtu_a_R1}" "exceeding MTU (veth_A-R1)" || return 1
+ check_pmtu_value "1500" "${pmtu_a_R2}" "exceeding MTU (veth_A-R2)" || return 1
+}
+
usage() {
echo
echo "$0 [OPTIONS] [TEST]..."
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index 87dce3efe31e..7f05b5f9b76f 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -21,10 +21,10 @@ ALL_TESTS="
kci_test_vrf
kci_test_encap
kci_test_macsec
- kci_test_macsec_offload
kci_test_ipsec
kci_test_ipsec_offload
kci_test_fdb_get
+ kci_test_fdb_del
kci_test_neigh_get
kci_test_bridge_parent_id
kci_test_address_proto
@@ -559,73 +559,6 @@ kci_test_macsec()
end_test "PASS: macsec"
}
-kci_test_macsec_offload()
-{
- sysfsd=/sys/kernel/debug/netdevsim/netdevsim0/ports/0/
- sysfsnet=/sys/bus/netdevsim/devices/netdevsim0/net/
- probed=false
- local ret=0
- run_cmd_grep "^Usage: ip macsec" ip macsec help
- if [ $? -ne 0 ]; then
- end_test "SKIP: macsec: iproute2 too old"
- return $ksft_skip
- fi
-
- if ! mount | grep -q debugfs; then
- mount -t debugfs none /sys/kernel/debug/ &> /dev/null
- fi
-
- # setup netdevsim since dummydev doesn't have offload support
- if [ ! -w /sys/bus/netdevsim/new_device ] ; then
- run_cmd modprobe -q netdevsim
-
- if [ $ret -ne 0 ]; then
- end_test "SKIP: macsec_offload can't load netdevsim"
- return $ksft_skip
- fi
- probed=true
- fi
-
- echo "0" > /sys/bus/netdevsim/new_device
- while [ ! -d $sysfsnet ] ; do :; done
- udevadm settle
- dev=`ls $sysfsnet`
-
- ip link set $dev up
- if [ ! -d $sysfsd ] ; then
- end_test "FAIL: macsec_offload can't create device $dev"
- return 1
- fi
- run_cmd_grep 'macsec-hw-offload: on' ethtool -k $dev
- if [ $? -eq 1 ] ; then
- end_test "FAIL: macsec_offload netdevsim doesn't support MACsec offload"
- return 1
- fi
- run_cmd ip link add link $dev kci_macsec1 type macsec port 4 offload mac
- run_cmd ip link add link $dev kci_macsec2 type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
- run_cmd ip link add link $dev kci_macsec3 type macsec sci abbacdde01020304 offload mac
- run_cmd_fail ip link add link $dev kci_macsec4 type macsec port 8 offload mac
-
- msname=kci_macsec1
- run_cmd ip macsec add "$msname" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
- run_cmd ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef"
- run_cmd ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
- key 00 0123456789abcdef0123456789abcdef
- run_cmd_fail ip macsec add "$msname" rx port 1235 address "1c:ed:de:ad:be:ef"
- # clean up any leftovers
- for msdev in kci_macsec{1,2,3,4} ; do
- ip link del $msdev 2> /dev/null
- done
- echo 0 > /sys/bus/netdevsim/del_device
- $probed && rmmod netdevsim
-
- if [ $ret -ne 0 ]; then
- end_test "FAIL: macsec_offload"
- return 1
- fi
- end_test "PASS: macsec_offload"
-}
-
#-------------------------------------------------------------------
# Example commands
# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \
@@ -1065,6 +998,45 @@ kci_test_fdb_get()
end_test "PASS: bridge fdb get"
}
+kci_test_fdb_del()
+{
+ local test_mac=de:ad:be:ef:13:37
+ local dummydev="dummy1"
+ local brdev="test-br0"
+ local ret=0
+
+ run_cmd_grep 'bridge fdb get' bridge fdb help
+ if [ $? -ne 0 ]; then
+ end_test "SKIP: fdb del tests: iproute2 too old"
+ return $ksft_skip
+ fi
+
+ setup_ns testns
+ if [ $? -ne 0 ]; then
+ end_test "SKIP fdb del tests: cannot add net namespace $testns"
+ return $ksft_skip
+ fi
+ IP="ip -netns $testns"
+ BRIDGE="bridge -netns $testns"
+ run_cmd $IP link add $dummydev type dummy
+ run_cmd $IP link add name $brdev type bridge vlan_filtering 1
+ run_cmd $IP link set dev $dummydev master $brdev
+ run_cmd $BRIDGE fdb add $test_mac dev $dummydev master static vlan 1
+ run_cmd $BRIDGE vlan del vid 1 dev $dummydev
+ run_cmd $BRIDGE fdb get $test_mac br $brdev vlan 1
+ run_cmd $BRIDGE fdb del $test_mac dev $dummydev master vlan 1
+ run_cmd_fail $BRIDGE fdb get $test_mac br $brdev vlan 1
+
+ ip netns del $testns &>/dev/null
+
+ if [ $ret -ne 0 ]; then
+ end_test "FAIL: bridge fdb del"
+ return 1
+ fi
+
+ end_test "PASS: bridge fdb del"
+}
+
kci_test_neigh_get()
{
dstmac=de:ad:be:ef:13:37
diff --git a/tools/testing/selftests/net/veth.sh b/tools/testing/selftests/net/veth.sh
index 4f1edbafb946..6bb7dfaa30b6 100755
--- a/tools/testing/selftests/net/veth.sh
+++ b/tools/testing/selftests/net/veth.sh
@@ -46,8 +46,6 @@ create_ns() {
ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
done
- echo "#kernel" > $BASE
- chmod go-rw $BASE
}
__chk_flag() {
diff --git a/tools/testing/selftests/sched_ext/Makefile b/tools/testing/selftests/sched_ext/Makefile
index 06ae9c107049..011762224600 100644
--- a/tools/testing/selftests/sched_ext/Makefile
+++ b/tools/testing/selftests/sched_ext/Makefile
@@ -184,7 +184,7 @@ auto-test-targets := \
testcase-targets := $(addsuffix .o,$(addprefix $(SCXOBJ_DIR)/,$(auto-test-targets)))
-$(SCXOBJ_DIR)/runner.o: runner.c | $(SCXOBJ_DIR)
+$(SCXOBJ_DIR)/runner.o: runner.c | $(SCXOBJ_DIR) $(BPFOBJ)
$(CC) $(CFLAGS) -c $< -o $@
# Create all of the test targets object files, whose testcase objects will be
diff --git a/tools/testing/selftests/sched_ext/create_dsq.bpf.c b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
index 23f79ed343f0..2cfc4ffd60e2 100644
--- a/tools/testing/selftests/sched_ext/create_dsq.bpf.c
+++ b/tools/testing/selftests/sched_ext/create_dsq.bpf.c
@@ -51,8 +51,8 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(create_dsq_init)
SEC(".struct_ops.link")
struct sched_ext_ops create_dsq_ops = {
- .init_task = create_dsq_init_task,
- .exit_task = create_dsq_exit_task,
- .init = create_dsq_init,
+ .init_task = (void *) create_dsq_init_task,
+ .exit_task = (void *) create_dsq_exit_task,
+ .init = (void *) create_dsq_init,
.name = "create_dsq",
};
diff --git a/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c b/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c
index e97ad41d354a..37d9bf6fb745 100644
--- a/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c
+++ b/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c
@@ -35,8 +35,8 @@ void BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops ddsp_bogus_dsq_fail_ops = {
- .select_cpu = ddsp_bogus_dsq_fail_select_cpu,
- .exit = ddsp_bogus_dsq_fail_exit,
+ .select_cpu = (void *) ddsp_bogus_dsq_fail_select_cpu,
+ .exit = (void *) ddsp_bogus_dsq_fail_exit,
.name = "ddsp_bogus_dsq_fail",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c b/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c
index dde7e7dafbfb..dffc97d9cdf1 100644
--- a/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c
+++ b/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c
@@ -32,8 +32,8 @@ void BPF_STRUCT_OPS(ddsp_vtimelocal_fail_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops ddsp_vtimelocal_fail_ops = {
- .select_cpu = ddsp_vtimelocal_fail_select_cpu,
- .exit = ddsp_vtimelocal_fail_exit,
+ .select_cpu = (void *) ddsp_vtimelocal_fail_select_cpu,
+ .exit = (void *) ddsp_vtimelocal_fail_exit,
.name = "ddsp_vtimelocal_fail",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c b/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c
index efb4672decb4..6a7db1502c29 100644
--- a/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c
+++ b/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c
@@ -56,10 +56,10 @@ void BPF_STRUCT_OPS(dsp_local_on_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops dsp_local_on_ops = {
- .select_cpu = dsp_local_on_select_cpu,
- .enqueue = dsp_local_on_enqueue,
- .dispatch = dsp_local_on_dispatch,
- .exit = dsp_local_on_exit,
+ .select_cpu = (void *) dsp_local_on_select_cpu,
+ .enqueue = (void *) dsp_local_on_enqueue,
+ .dispatch = (void *) dsp_local_on_dispatch,
+ .exit = (void *) dsp_local_on_exit,
.name = "dsp_local_on",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.bpf.c b/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.bpf.c
index b0b99531d5d5..e1bd13e48889 100644
--- a/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.bpf.c
+++ b/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.bpf.c
@@ -12,10 +12,18 @@
char _license[] SEC("license") = "GPL";
+u32 exit_kind;
+
+void BPF_STRUCT_OPS_SLEEPABLE(enq_last_no_enq_fails_exit, struct scx_exit_info *info)
+{
+ exit_kind = info->kind;
+}
+
SEC(".struct_ops.link")
struct sched_ext_ops enq_last_no_enq_fails_ops = {
.name = "enq_last_no_enq_fails",
/* Need to define ops.enqueue() with SCX_OPS_ENQ_LAST */
.flags = SCX_OPS_ENQ_LAST,
+ .exit = (void *) enq_last_no_enq_fails_exit,
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.c b/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.c
index 2a3eda5e2c0b..73e679953e27 100644
--- a/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.c
+++ b/tools/testing/selftests/sched_ext/enq_last_no_enq_fails.c
@@ -31,8 +31,12 @@ static enum scx_test_status run(void *ctx)
struct bpf_link *link;
link = bpf_map__attach_struct_ops(skel->maps.enq_last_no_enq_fails_ops);
- if (link) {
- SCX_ERR("Incorrectly succeeded in to attaching scheduler");
+ if (!link) {
+ SCX_ERR("Incorrectly failed at attaching scheduler");
+ return SCX_TEST_FAIL;
+ }
+ if (!skel->bss->exit_kind) {
+ SCX_ERR("Incorrectly stayed loaded");
return SCX_TEST_FAIL;
}
@@ -50,7 +54,7 @@ static void cleanup(void *ctx)
struct scx_test enq_last_no_enq_fails = {
.name = "enq_last_no_enq_fails",
- .description = "Verify we fail to load a scheduler if we specify "
+ .description = "Verify we eject a scheduler if we specify "
"the SCX_OPS_ENQ_LAST flag without defining "
"ops.enqueue()",
.setup = setup,
diff --git a/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c b/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c
index b3dfc1033cd6..1efb50d61040 100644
--- a/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c
+++ b/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c
@@ -36,8 +36,8 @@ void BPF_STRUCT_OPS(enq_select_cpu_fails_enqueue, struct task_struct *p,
SEC(".struct_ops.link")
struct sched_ext_ops enq_select_cpu_fails_ops = {
- .select_cpu = enq_select_cpu_fails_select_cpu,
- .enqueue = enq_select_cpu_fails_enqueue,
+ .select_cpu = (void *) enq_select_cpu_fails_select_cpu,
+ .enqueue = (void *) enq_select_cpu_fails_enqueue,
.name = "enq_select_cpu_fails",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/exit.bpf.c b/tools/testing/selftests/sched_ext/exit.bpf.c
index ae12ddaac921..d75d4faf07f6 100644
--- a/tools/testing/selftests/sched_ext/exit.bpf.c
+++ b/tools/testing/selftests/sched_ext/exit.bpf.c
@@ -15,6 +15,8 @@ UEI_DEFINE(uei);
#define EXIT_CLEANLY() scx_bpf_exit(exit_point, "%d", exit_point)
+#define DSQ_ID 0
+
s32 BPF_STRUCT_OPS(exit_select_cpu, struct task_struct *p,
s32 prev_cpu, u64 wake_flags)
{
@@ -31,7 +33,7 @@ void BPF_STRUCT_OPS(exit_enqueue, struct task_struct *p, u64 enq_flags)
if (exit_point == EXIT_ENQUEUE)
EXIT_CLEANLY();
- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags);
+ scx_bpf_dispatch(p, DSQ_ID, SCX_SLICE_DFL, enq_flags);
}
void BPF_STRUCT_OPS(exit_dispatch, s32 cpu, struct task_struct *p)
@@ -39,7 +41,7 @@ void BPF_STRUCT_OPS(exit_dispatch, s32 cpu, struct task_struct *p)
if (exit_point == EXIT_DISPATCH)
EXIT_CLEANLY();
- scx_bpf_consume(SCX_DSQ_GLOBAL);
+ scx_bpf_consume(DSQ_ID);
}
void BPF_STRUCT_OPS(exit_enable, struct task_struct *p)
@@ -67,18 +69,18 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(exit_init)
if (exit_point == EXIT_INIT)
EXIT_CLEANLY();
- return 0;
+ return scx_bpf_create_dsq(DSQ_ID, -1);
}
SEC(".struct_ops.link")
struct sched_ext_ops exit_ops = {
- .select_cpu = exit_select_cpu,
- .enqueue = exit_enqueue,
- .dispatch = exit_dispatch,
- .init_task = exit_init_task,
- .enable = exit_enable,
- .exit = exit_exit,
- .init = exit_init,
+ .select_cpu = (void *) exit_select_cpu,
+ .enqueue = (void *) exit_enqueue,
+ .dispatch = (void *) exit_dispatch,
+ .init_task = (void *) exit_init_task,
+ .enable = (void *) exit_enable,
+ .exit = (void *) exit_exit,
+ .init = (void *) exit_init,
.name = "exit",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/hotplug.bpf.c b/tools/testing/selftests/sched_ext/hotplug.bpf.c
index 8f2601db39f3..6c9f25c9bf53 100644
--- a/tools/testing/selftests/sched_ext/hotplug.bpf.c
+++ b/tools/testing/selftests/sched_ext/hotplug.bpf.c
@@ -46,16 +46,16 @@ void BPF_STRUCT_OPS_SLEEPABLE(hotplug_cpu_offline, s32 cpu)
SEC(".struct_ops.link")
struct sched_ext_ops hotplug_cb_ops = {
- .cpu_online = hotplug_cpu_online,
- .cpu_offline = hotplug_cpu_offline,
- .exit = hotplug_exit,
+ .cpu_online = (void *) hotplug_cpu_online,
+ .cpu_offline = (void *) hotplug_cpu_offline,
+ .exit = (void *) hotplug_exit,
.name = "hotplug_cbs",
.timeout_ms = 1000U,
};
SEC(".struct_ops.link")
struct sched_ext_ops hotplug_nocb_ops = {
- .exit = hotplug_exit,
+ .exit = (void *) hotplug_exit,
.name = "hotplug_nocbs",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/init_enable_count.bpf.c b/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
index 47ea89a626c3..5eb9edb1837d 100644
--- a/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
+++ b/tools/testing/selftests/sched_ext/init_enable_count.bpf.c
@@ -45,9 +45,9 @@ void BPF_STRUCT_OPS(cnt_disable, struct task_struct *p)
SEC(".struct_ops.link")
struct sched_ext_ops init_enable_count_ops = {
- .init_task = cnt_init_task,
- .exit_task = cnt_exit_task,
- .enable = cnt_enable,
- .disable = cnt_disable,
+ .init_task = (void *) cnt_init_task,
+ .exit_task = (void *) cnt_exit_task,
+ .enable = (void *) cnt_enable,
+ .disable = (void *) cnt_disable,
.name = "init_enable_count",
};
diff --git a/tools/testing/selftests/sched_ext/maximal.bpf.c b/tools/testing/selftests/sched_ext/maximal.bpf.c
index 00bfa9cb95d3..4d4cd8d966db 100644
--- a/tools/testing/selftests/sched_ext/maximal.bpf.c
+++ b/tools/testing/selftests/sched_ext/maximal.bpf.c
@@ -131,34 +131,34 @@ void BPF_STRUCT_OPS(maximal_exit, struct scx_exit_info *info)
SEC(".struct_ops.link")
struct sched_ext_ops maximal_ops = {
- .select_cpu = maximal_select_cpu,
- .enqueue = maximal_enqueue,
- .dequeue = maximal_dequeue,
- .dispatch = maximal_dispatch,
- .runnable = maximal_runnable,
- .running = maximal_running,
- .stopping = maximal_stopping,
- .quiescent = maximal_quiescent,
- .yield = maximal_yield,
- .core_sched_before = maximal_core_sched_before,
- .set_weight = maximal_set_weight,
- .set_cpumask = maximal_set_cpumask,
- .update_idle = maximal_update_idle,
- .cpu_acquire = maximal_cpu_acquire,
- .cpu_release = maximal_cpu_release,
- .cpu_online = maximal_cpu_online,
- .cpu_offline = maximal_cpu_offline,
- .init_task = maximal_init_task,
- .enable = maximal_enable,
- .exit_task = maximal_exit_task,
- .disable = maximal_disable,
- .cgroup_init = maximal_cgroup_init,
- .cgroup_exit = maximal_cgroup_exit,
- .cgroup_prep_move = maximal_cgroup_prep_move,
- .cgroup_move = maximal_cgroup_move,
- .cgroup_cancel_move = maximal_cgroup_cancel_move,
- .cgroup_set_weight = maximal_cgroup_set_weight,
- .init = maximal_init,
- .exit = maximal_exit,
+ .select_cpu = (void *) maximal_select_cpu,
+ .enqueue = (void *) maximal_enqueue,
+ .dequeue = (void *) maximal_dequeue,
+ .dispatch = (void *) maximal_dispatch,
+ .runnable = (void *) maximal_runnable,
+ .running = (void *) maximal_running,
+ .stopping = (void *) maximal_stopping,
+ .quiescent = (void *) maximal_quiescent,
+ .yield = (void *) maximal_yield,
+ .core_sched_before = (void *) maximal_core_sched_before,
+ .set_weight = (void *) maximal_set_weight,
+ .set_cpumask = (void *) maximal_set_cpumask,
+ .update_idle = (void *) maximal_update_idle,
+ .cpu_acquire = (void *) maximal_cpu_acquire,
+ .cpu_release = (void *) maximal_cpu_release,
+ .cpu_online = (void *) maximal_cpu_online,
+ .cpu_offline = (void *) maximal_cpu_offline,
+ .init_task = (void *) maximal_init_task,
+ .enable = (void *) maximal_enable,
+ .exit_task = (void *) maximal_exit_task,
+ .disable = (void *) maximal_disable,
+ .cgroup_init = (void *) maximal_cgroup_init,
+ .cgroup_exit = (void *) maximal_cgroup_exit,
+ .cgroup_prep_move = (void *) maximal_cgroup_prep_move,
+ .cgroup_move = (void *) maximal_cgroup_move,
+ .cgroup_cancel_move = (void *) maximal_cgroup_cancel_move,
+ .cgroup_set_weight = (void *) maximal_cgroup_set_weight,
+ .init = (void *) maximal_init,
+ .exit = (void *) maximal_exit,
.name = "maximal",
};
diff --git a/tools/testing/selftests/sched_ext/maybe_null.bpf.c b/tools/testing/selftests/sched_ext/maybe_null.bpf.c
index 27d0f386acfb..cf4ae870cd4e 100644
--- a/tools/testing/selftests/sched_ext/maybe_null.bpf.c
+++ b/tools/testing/selftests/sched_ext/maybe_null.bpf.c
@@ -29,8 +29,8 @@ bool BPF_STRUCT_OPS(maybe_null_success_yield, struct task_struct *from,
SEC(".struct_ops.link")
struct sched_ext_ops maybe_null_success = {
- .dispatch = maybe_null_success_dispatch,
- .yield = maybe_null_success_yield,
- .enable = maybe_null_running,
+ .dispatch = (void *) maybe_null_success_dispatch,
+ .yield = (void *) maybe_null_success_yield,
+ .enable = (void *) maybe_null_running,
.name = "minimal",
};
diff --git a/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c b/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c
index c0641050271d..ec724d7b33d1 100644
--- a/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c
+++ b/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c
@@ -19,7 +19,7 @@ void BPF_STRUCT_OPS(maybe_null_fail_dispatch, s32 cpu, struct task_struct *p)
SEC(".struct_ops.link")
struct sched_ext_ops maybe_null_fail = {
- .dispatch = maybe_null_fail_dispatch,
- .enable = maybe_null_running,
+ .dispatch = (void *) maybe_null_fail_dispatch,
+ .enable = (void *) maybe_null_running,
.name = "maybe_null_fail_dispatch",
};
diff --git a/tools/testing/selftests/sched_ext/maybe_null_fail_yld.bpf.c b/tools/testing/selftests/sched_ext/maybe_null_fail_yld.bpf.c
index 3c1740028e3b..e6552cace020 100644
--- a/tools/testing/selftests/sched_ext/maybe_null_fail_yld.bpf.c
+++ b/tools/testing/selftests/sched_ext/maybe_null_fail_yld.bpf.c
@@ -22,7 +22,7 @@ bool BPF_STRUCT_OPS(maybe_null_fail_yield, struct task_struct *from,
SEC(".struct_ops.link")
struct sched_ext_ops maybe_null_fail = {
- .yield = maybe_null_fail_yield,
- .enable = maybe_null_running,
+ .yield = (void *) maybe_null_fail_yield,
+ .enable = (void *) maybe_null_running,
.name = "maybe_null_fail_yield",
};
diff --git a/tools/testing/selftests/sched_ext/prog_run.bpf.c b/tools/testing/selftests/sched_ext/prog_run.bpf.c
index 6a4d7c48e3f2..00c267626a68 100644
--- a/tools/testing/selftests/sched_ext/prog_run.bpf.c
+++ b/tools/testing/selftests/sched_ext/prog_run.bpf.c
@@ -28,6 +28,6 @@ void BPF_STRUCT_OPS(prog_run_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops prog_run_ops = {
- .exit = prog_run_exit,
+ .exit = (void *) prog_run_exit,
.name = "prog_run",
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c
index 2ed2991afafe..f171ac470970 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c
@@ -35,6 +35,6 @@ void BPF_STRUCT_OPS(select_cpu_dfl_enqueue, struct task_struct *p,
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_dfl_ops = {
- .enqueue = select_cpu_dfl_enqueue,
+ .enqueue = (void *) select_cpu_dfl_enqueue,
.name = "select_cpu_dfl",
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c
index 4bb5abb2d369..9efdbb7da928 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c
@@ -82,8 +82,8 @@ s32 BPF_STRUCT_OPS(select_cpu_dfl_nodispatch_init_task,
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_dfl_nodispatch_ops = {
- .select_cpu = select_cpu_dfl_nodispatch_select_cpu,
- .enqueue = select_cpu_dfl_nodispatch_enqueue,
- .init_task = select_cpu_dfl_nodispatch_init_task,
+ .select_cpu = (void *) select_cpu_dfl_nodispatch_select_cpu,
+ .enqueue = (void *) select_cpu_dfl_nodispatch_enqueue,
+ .init_task = (void *) select_cpu_dfl_nodispatch_init_task,
.name = "select_cpu_dfl_nodispatch",
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c
index f0b96a4a04b2..59bfc4f36167 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c
@@ -35,7 +35,7 @@ dispatch:
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_dispatch_ops = {
- .select_cpu = select_cpu_dispatch_select_cpu,
+ .select_cpu = (void *) select_cpu_dispatch_select_cpu,
.name = "select_cpu_dispatch",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c
index 7b42ddce0f56..3bbd5fcdfb18 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c
@@ -30,8 +30,8 @@ void BPF_STRUCT_OPS(select_cpu_dispatch_bad_dsq_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_dispatch_bad_dsq_ops = {
- .select_cpu = select_cpu_dispatch_bad_dsq_select_cpu,
- .exit = select_cpu_dispatch_bad_dsq_exit,
+ .select_cpu = (void *) select_cpu_dispatch_bad_dsq_select_cpu,
+ .exit = (void *) select_cpu_dispatch_bad_dsq_exit,
.name = "select_cpu_dispatch_bad_dsq",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c
index 653e3dc0b4dc..0fda57fe0ecf 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c
@@ -31,8 +31,8 @@ void BPF_STRUCT_OPS(select_cpu_dispatch_dbl_dsp_exit, struct scx_exit_info *ei)
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_dispatch_dbl_dsp_ops = {
- .select_cpu = select_cpu_dispatch_dbl_dsp_select_cpu,
- .exit = select_cpu_dispatch_dbl_dsp_exit,
+ .select_cpu = (void *) select_cpu_dispatch_dbl_dsp_select_cpu,
+ .exit = (void *) select_cpu_dispatch_dbl_dsp_exit,
.name = "select_cpu_dispatch_dbl_dsp",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c
index 7f3ebf4fc2ea..e6c67bcf5e6e 100644
--- a/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c
+++ b/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c
@@ -81,12 +81,12 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(select_cpu_vtime_init)
SEC(".struct_ops.link")
struct sched_ext_ops select_cpu_vtime_ops = {
- .select_cpu = select_cpu_vtime_select_cpu,
- .dispatch = select_cpu_vtime_dispatch,
- .running = select_cpu_vtime_running,
- .stopping = select_cpu_vtime_stopping,
- .enable = select_cpu_vtime_enable,
- .init = select_cpu_vtime_init,
+ .select_cpu = (void *) select_cpu_vtime_select_cpu,
+ .dispatch = (void *) select_cpu_vtime_dispatch,
+ .running = (void *) select_cpu_vtime_running,
+ .stopping = (void *) select_cpu_vtime_stopping,
+ .enable = (void *) select_cpu_vtime_enable,
+ .init = (void *) select_cpu_vtime_init,
.name = "select_cpu_vtime",
.timeout_ms = 1000U,
};
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/basic.json b/tools/testing/selftests/tc-testing/tc-tests/filters/basic.json
index d1278de8ebc3..c9309a44a87e 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/basic.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/basic.json
@@ -67,7 +67,7 @@
},
{
"id": "4943",
- "name": "Add basic filter with cmp ematch u32/link layer and miltiple actions",
+ "name": "Add basic filter with cmp ematch u32/link layer and multiple actions",
"category": [
"filter",
"basic"
@@ -155,7 +155,7 @@
},
{
"id": "32d8",
- "name": "Add basic filter with cmp ematch u32/network layer and miltiple actions",
+ "name": "Add basic filter with cmp ematch u32/network layer and multiple actions",
"category": [
"filter",
"basic"
@@ -243,7 +243,7 @@
},
{
"id": "62d7",
- "name": "Add basic filter with cmp ematch u32/transport layer and miltiple actions",
+ "name": "Add basic filter with cmp ematch u32/transport layer and multiple actions",
"category": [
"filter",
"basic"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/cgroup.json b/tools/testing/selftests/tc-testing/tc-tests/filters/cgroup.json
index 03723cf84379..35c9a7dbe1c4 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/cgroup.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/cgroup.json
@@ -67,7 +67,7 @@
},
{
"id": "0234",
- "name": "Add cgroup filter with cmp ematch u32/link layer and miltiple actions",
+ "name": "Add cgroup filter with cmp ematch u32/link layer and multiple actions",
"category": [
"filter",
"cgroup"
@@ -155,7 +155,7 @@
},
{
"id": "2733",
- "name": "Add cgroup filter with cmp ematch u32/network layer and miltiple actions",
+ "name": "Add cgroup filter with cmp ematch u32/network layer and multiple actions",
"category": [
"filter",
"cgroup"
@@ -1189,7 +1189,7 @@
},
{
"id": "4319",
- "name": "Replace cgroup filter with diffferent match",
+ "name": "Replace cgroup filter with different match",
"category": [
"filter",
"cgroup"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/flow.json b/tools/testing/selftests/tc-testing/tc-tests/filters/flow.json
index 58189327f644..996448afe31b 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/flow.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/flow.json
@@ -507,7 +507,7 @@
},
{
"id": "4341",
- "name": "Add flow filter with muliple ops",
+ "name": "Add flow filter with multiple ops",
"category": [
"filter",
"flow"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/route.json b/tools/testing/selftests/tc-testing/tc-tests/filters/route.json
index 8d8de8f65aef..05cedca67cca 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/route.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/route.json
@@ -111,7 +111,7 @@
},
{
"id": "7994",
- "name": "Add route filter with miltiple actions",
+ "name": "Add route filter with multiple actions",
"category": [
"filter",
"route"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json b/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json
index 24bd0c2a3014..b2ca9d4e991b 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/u32.json
@@ -329,5 +329,29 @@
"teardown": [
"$TC qdisc del dev $DEV1 parent root drr"
]
+ },
+ {
+ "id": "1234",
+ "name": "Exercise IDR leaks by creating/deleting a filter many (2048) times",
+ "category": [
+ "filter",
+ "u32"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$TC qdisc add dev $DEV1 parent root handle 10: drr",
+ "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 2 u32 match ip src 0.0.0.2/32 action drop",
+ "$TC filter add dev $DEV1 parent 10:0 protocol ip prio 3 u32 match ip src 0.0.0.3/32 action drop"
+ ],
+ "cmdUnderTest": "bash -c 'for i in {1..2048} ;do echo filter delete dev $DEV1 pref 3;echo filter add dev $DEV1 parent 10:0 protocol ip prio 3 u32 match ip src 0.0.0.3/32 action drop;done | $TC -b -'",
+ "expExitCode": "0",
+ "verifyCmd": "$TC filter show dev $DEV1",
+ "matchPattern": "protocol ip pref 3 u32",
+ "matchCount": "3",
+ "teardown": [
+ "$TC qdisc del dev $DEV1 parent root drr"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json
new file mode 100644
index 000000000000..d3dd65b05b5f
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json
@@ -0,0 +1,98 @@
+[
+ {
+ "id": "ca5e",
+ "name": "Check class delete notification for ffff:",
+ "category": [
+ "qdisc"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+ "$TC qdisc add dev $DUMMY root handle 1: drr",
+ "$TC filter add dev $DUMMY parent 1: basic classid 1:1",
+ "$TC class add dev $DUMMY parent 1: classid 1:1 drr",
+ "$TC qdisc add dev $DUMMY parent 1:1 handle ffff: drr",
+ "$TC filter add dev $DUMMY parent ffff: basic classid ffff:1",
+ "$TC class add dev $DUMMY parent ffff: classid ffff:1 drr",
+ "$TC qdisc add dev $DUMMY parent ffff:1 netem delay 1s",
+ "ping -c1 -W0.01 -I $DUMMY 10.10.10.1 || true",
+ "$TC class del dev $DUMMY classid ffff:1",
+ "$TC class add dev $DUMMY parent ffff: classid ffff:1 drr"
+ ],
+ "cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.10.1",
+ "expExitCode": "1",
+ "verifyCmd": "$TC -s qdisc ls dev $DUMMY",
+ "matchPattern": "drr 1: root",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root handle 1: drr",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY"
+ ]
+ },
+ {
+ "id": "e4b7",
+ "name": "Check class delete notification for root ffff:",
+ "category": [
+ "qdisc"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+ "$TC qdisc add dev $DUMMY root handle ffff: drr",
+ "$TC filter add dev $DUMMY parent ffff: basic classid ffff:1",
+ "$TC class add dev $DUMMY parent ffff: classid ffff:1 drr",
+ "$TC qdisc add dev $DUMMY parent ffff:1 netem delay 1s",
+ "ping -c1 -W0.01 -I $DUMMY 10.10.10.1 || true",
+ "$TC class del dev $DUMMY classid ffff:1",
+ "$TC class add dev $DUMMY parent ffff: classid ffff:1 drr"
+ ],
+ "cmdUnderTest": "ping -c1 -W0.01 -I $DUMMY 10.10.10.1",
+ "expExitCode": "1",
+ "verifyCmd": "$TC qdisc ls dev $DUMMY",
+ "matchPattern": "drr ffff: root",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root handle ffff: drr",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY"
+ ]
+ },
+ {
+ "id": "33a9",
+ "name": "Check ingress is not searchable on backlog update",
+ "category": [
+ "qdisc"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ "$IP link set dev $DUMMY up || true",
+ "$IP addr add 10.10.10.10/24 dev $DUMMY || true",
+ "$TC qdisc add dev $DUMMY ingress",
+ "$TC qdisc add dev $DUMMY root handle 1: drr",
+ "$TC filter add dev $DUMMY parent 1: basic classid 1:1",
+ "$TC class add dev $DUMMY parent 1: classid 1:1 drr",
+ "$TC qdisc add dev $DUMMY parent 1:1 handle 2: drr",
+ "$TC filter add dev $DUMMY parent 2: basic classid 2:1",
+ "$TC class add dev $DUMMY parent 2: classid 2:1 drr",
+ "$TC qdisc add dev $DUMMY parent 2:1 netem delay 1s",
+ "ping -c1 -W0.01 -I $DUMMY 10.10.10.1 || true"
+ ],
+ "cmdUnderTest": "$TC class del dev $DUMMY classid 2:1",
+ "expExitCode": "0",
+ "verifyCmd": "$TC qdisc ls dev $DUMMY",
+ "matchPattern": "drr 1: root",
+ "matchCount": "1",
+ "teardown": [
+ "$TC qdisc del dev $DUMMY root handle 1: drr",
+ "$TC qdisc del dev $DUMMY ingress",
+ "$IP addr del 10.10.10.10/24 dev $DUMMY"
+ ]
+ }
+]
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c
index bc71cbca0dde..a1f506ba5578 100644
--- a/tools/testing/selftests/watchdog/watchdog-test.c
+++ b/tools/testing/selftests/watchdog/watchdog-test.c
@@ -334,7 +334,13 @@ int main(int argc, char *argv[])
printf("Watchdog Ticking Away!\n");
+ /*
+ * Register the signals
+ */
signal(SIGINT, term);
+ signal(SIGTERM, term);
+ signal(SIGKILL, term);
+ signal(SIGQUIT, term);
while (1) {
keep_alive();
diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/vma.c
index c53f220eb6cc..b33b47342d41 100644
--- a/tools/testing/vma/vma.c
+++ b/tools/testing/vma/vma.c
@@ -1522,6 +1522,45 @@ static bool test_copy_vma(void)
return true;
}
+static bool test_expand_only_mode(void)
+{
+ unsigned long flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
+ struct mm_struct mm = {};
+ VMA_ITERATOR(vmi, &mm, 0);
+ struct vm_area_struct *vma_prev, *vma;
+ VMG_STATE(vmg, &mm, &vmi, 0x5000, 0x9000, flags, 5);
+
+ /*
+ * Place a VMA prior to the one we're expanding so we assert that we do
+ * not erroneously try to traverse to the previous VMA even though we
+ * have, through the use of VMG_FLAG_JUST_EXPAND, indicated we do not
+ * need to do so.
+ */
+ alloc_and_link_vma(&mm, 0, 0x2000, 0, flags);
+
+ /*
+ * We will be positioned at the prev VMA, but looking to expand to
+ * 0x9000.
+ */
+ vma_iter_set(&vmi, 0x3000);
+ vma_prev = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, flags);
+ vmg.prev = vma_prev;
+ vmg.merge_flags = VMG_FLAG_JUST_EXPAND;
+
+ vma = vma_merge_new_range(&vmg);
+ ASSERT_NE(vma, NULL);
+ ASSERT_EQ(vma, vma_prev);
+ ASSERT_EQ(vmg.state, VMA_MERGE_SUCCESS);
+ ASSERT_EQ(vma->vm_start, 0x3000);
+ ASSERT_EQ(vma->vm_end, 0x9000);
+ ASSERT_EQ(vma->vm_pgoff, 3);
+ ASSERT_TRUE(vma_write_started(vma));
+ ASSERT_EQ(vma_iter_addr(&vmi), 0x3000);
+
+ cleanup_mm(&mm, &vmi);
+ return true;
+}
+
int main(void)
{
int num_tests = 0, num_fail = 0;
@@ -1553,6 +1592,7 @@ int main(void)
TEST(vmi_prealloc_fail);
TEST(merge_extend);
TEST(copy_vma);
+ TEST(expand_only_mode);
#undef TEST
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c
index b29101986b5a..6b78d4a81e95 100644
--- a/tools/usb/usbip/src/usbip_detach.c
+++ b/tools/usb/usbip/src/usbip_detach.c
@@ -68,6 +68,7 @@ static int detach_port(char *port)
}
if (!found) {
+ ret = -1;
err("Invalid port %s > maxports %d",
port, vhci_driver->nports);
goto call_driver_close;
diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c
index 43d3a6aa1dcf..b9591223437a 100644
--- a/tools/virtio/vringh_test.c
+++ b/tools/virtio/vringh_test.c
@@ -519,7 +519,7 @@ int main(int argc, char *argv[])
errx(1, "virtqueue_add_sgs: %i", err);
__kmalloc_fake = NULL;
- /* Host retreives it. */
+ /* Host retrieves it. */
vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));